summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicola Tuveri <nic.tuv@gmail.com>2020-07-21 17:04:38 +0200
committerNicola Tuveri <nic.tuv@gmail.com>2020-07-29 22:45:57 +0200
commitf5384f064ec2ef9f1975877da46e6f64c776427c (patch)
tree9f1b777a3ec849a43bb86d68fe8343631e0347fa
parentnamemap: fix threading issue (diff)
downloadopenssl-f5384f064ec2ef9f1975877da46e6f64c776427c.tar.xz
openssl-f5384f064ec2ef9f1975877da46e6f64c776427c.zip
[test] Vertically test explicit EC params API patterns
This commit adds a new test (run on all the built-in curves) to create `EC_GROUP` with **unknown** *explicit parameters*: from a built-in group we create an alternative group from scratch that differs in the generator used. At the `EC_GROUP` layer we perform a basic math check to ensure that the math on the alternative group still makes sense, using comparable results from the origin group. We then create two `EC_KEY` objects on top of this alternative group and run key generation from the `EC_KEY` layer. Then we promote these two `EC_KEY`s to `EVP_PKEY` objects and try to run the derive operation at the highest abstraction layer, comparing results in both directions. Finally, we create provider-native keys using `EVP_PKEY_fromdata` and data derived from the previous objects, we compute an equivalent shared secret from these provider keys, and compare it to the result obtained from the previous steps. Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12507)
-rw-r--r--test/ectest.c281
1 files changed, 280 insertions, 1 deletions
diff --git a/test/ectest.c b/test/ectest.c
index 8cceaa67e7..66da1b9e05 100644
--- a/test/ectest.c
+++ b/test/ectest.c
@@ -32,6 +32,9 @@
# include <openssl/rand.h>
# include <openssl/bn.h>
# include <openssl/opensslconf.h>
+# include "openssl/core_names.h"
+# include "openssl/param_build.h"
+# include "openssl/evp.h"
static size_t crv_len = 0;
static EC_builtin_curve *curves = NULL;
@@ -2402,7 +2405,7 @@ static int custom_generator_test(int id)
POINT_CONVERSION_UNCOMPRESSED, b2,
bsize, ctx), bsize)
/* Q1 = kG = k/2 G2 = Q2 should hold */
- || !TEST_int_eq(CRYPTO_memcmp(b1, b2, bsize), 0))
+ || !TEST_mem_eq(b1, bsize, b2, bsize))
goto err;
ret = 1;
@@ -2420,6 +2423,281 @@ static int custom_generator_test(int id)
return ret;
}
+/*
+ * check creation of curves from explicit params through the public API
+ */
+static int custom_params_test(int id)
+{
+ int ret = 0, nid, bsize;
+ const char *curve_name = NULL;
+ EC_GROUP *group = NULL, *altgroup = NULL;
+ EC_POINT *G2 = NULL, *Q1 = NULL, *Q2 = NULL;
+ const EC_POINT *Q = NULL;
+ BN_CTX *ctx = NULL;
+ BIGNUM *k = NULL;
+ unsigned char *buf1 = NULL, *buf2 = NULL;
+ const BIGNUM *z = NULL, *cof = NULL, *priv1 = NULL;
+ BIGNUM *p = NULL, *a = NULL, *b = NULL;
+ int is_prime = 0;
+ EC_KEY *eckey1 = NULL, *eckey2 = NULL;
+ EVP_PKEY *pkey1 = NULL, *pkey2 = NULL;
+ EVP_PKEY_CTX *pctx1 = NULL, *pctx2 = NULL;
+ size_t sslen, t;
+ unsigned char *pub1 = NULL , *pub2 = NULL;
+ OSSL_PARAM_BLD *param_bld = NULL;
+ OSSL_PARAM *params1 = NULL, *params2 = NULL;
+
+ /* Do some setup */
+ nid = curves[id].nid;
+ curve_name = OBJ_nid2sn(nid);
+ TEST_note("Curve %s", curve_name);
+
+ if (nid == NID_sm2)
+ return TEST_skip("custom params not supported with SM2");
+
+ if (!TEST_ptr(ctx = BN_CTX_new()))
+ return 0;
+
+ if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(nid)))
+ goto err;
+
+ is_prime = EC_GROUP_get_field_type(group) == NID_X9_62_prime_field;
+# ifdef OPENSSL_NO_EC2M
+ if (!is_prime) {
+ ret = TEST_skip("binary curves not supported in this build");
+ goto err;
+ }
+# endif
+
+ BN_CTX_start(ctx);
+ if (!TEST_ptr(p = BN_CTX_get(ctx))
+ || !TEST_ptr(a = BN_CTX_get(ctx))
+ || !TEST_ptr(b = BN_CTX_get(ctx))
+ || !TEST_ptr(k = BN_CTX_get(ctx)))
+ goto err;
+
+ /* expected byte length of encoded points */
+ bsize = (EC_GROUP_get_degree(group) + 7) / 8;
+ bsize = 1 + 2 * bsize; /* UNCOMPRESSED_POINT format */
+
+ /* extract parameters from built-in curve */
+ if (!TEST_true(EC_GROUP_get_curve(group, p, a, b, ctx))
+ || !TEST_ptr(G2 = EC_POINT_new(group))
+ /* new generator is G2 := 2G */
+ || !TEST_true(EC_POINT_dbl(group, G2,
+ EC_GROUP_get0_generator(group), ctx))
+ /* pull out the bytes of that */
+ || !TEST_int_eq(EC_POINT_point2oct(group, G2,
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, ctx), bsize)
+ || !TEST_ptr(buf1 = OPENSSL_malloc(bsize))
+ || !TEST_int_eq(EC_POINT_point2oct(group, G2,
+ POINT_CONVERSION_UNCOMPRESSED,
+ buf1, bsize, ctx), bsize)
+ || !TEST_ptr(z = EC_GROUP_get0_order(group))
+ || !TEST_ptr(cof = EC_GROUP_get0_cofactor(group))
+ )
+ goto err;
+
+ /* create a new group using same params (but different generator) */
+ if (is_prime) {
+ if (!TEST_ptr(altgroup = EC_GROUP_new_curve_GFp(p, a, b, ctx)))
+ goto err;
+ }
+# ifndef OPENSSL_NO_EC2M
+ else {
+ if (!TEST_ptr(altgroup = EC_GROUP_new_curve_GF2m(p, a, b, ctx)))
+ goto err;
+ }
+# endif
+
+ /* set 2*G as the generator of altgroup */
+ EC_POINT_free(G2); /* discard G2 as it refers to the original group */
+ if (!TEST_ptr(G2 = EC_POINT_new(altgroup))
+ || !TEST_true(EC_POINT_oct2point(altgroup, G2, buf1, bsize, ctx))
+ || !TEST_int_eq(EC_POINT_is_on_curve(altgroup, G2, ctx), 1)
+ || !TEST_true(EC_GROUP_set_generator(altgroup, G2, z, cof))
+ )
+ goto err;
+
+ /* verify math checks out */
+ if (/* allocate temporary points on group and altgroup */
+ !TEST_ptr(Q1 = EC_POINT_new(group))
+ || !TEST_ptr(Q2 = EC_POINT_new(altgroup))
+ /* fetch a testing scalar k != 0,1 */
+ || !TEST_true(BN_rand(k, EC_GROUP_order_bits(group) - 1,
+ BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
+ /* make k even */
+ || !TEST_true(BN_clear_bit(k, 0))
+ /* Q1 := kG on group */
+ || !TEST_true(EC_POINT_mul(group, Q1, k, NULL, NULL, ctx))
+ /* pull out the bytes of that */
+ || !TEST_int_eq(EC_POINT_point2oct(group, Q1,
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, ctx), bsize)
+ || !TEST_int_eq(EC_POINT_point2oct(group, Q1,
+ POINT_CONVERSION_UNCOMPRESSED,
+ buf1, bsize, ctx), bsize)
+ /* k := k/2 */
+ || !TEST_true(BN_rshift1(k, k))
+ /* Q2 := k/2 G2 on altgroup */
+ || !TEST_true(EC_POINT_mul(altgroup, Q2, k, NULL, NULL, ctx))
+ /* pull out the bytes of that */
+ || !TEST_int_eq(EC_POINT_point2oct(altgroup, Q2,
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, ctx), bsize)
+ || !TEST_ptr(buf2 = OPENSSL_malloc(bsize))
+ || !TEST_int_eq(EC_POINT_point2oct(altgroup, Q2,
+ POINT_CONVERSION_UNCOMPRESSED,
+ buf2, bsize, ctx), bsize)
+ /* Q1 = kG = k/2 G2 = Q2 should hold */
+ || !TEST_mem_eq(buf1, bsize, buf2, bsize))
+ goto err;
+
+ /* create two `EC_KEY`s on altgroup */
+ if (!TEST_ptr(eckey1 = EC_KEY_new())
+ || !TEST_true(EC_KEY_set_group(eckey1, altgroup))
+ || !TEST_true(EC_KEY_generate_key(eckey1))
+ || !TEST_ptr(eckey2 = EC_KEY_new())
+ || !TEST_true(EC_KEY_set_group(eckey2, altgroup))
+ || !TEST_true(EC_KEY_generate_key(eckey2)))
+ goto err;
+
+ /* retrieve priv1 for later */
+ if (!TEST_ptr(priv1 = EC_KEY_get0_private_key(eckey1)))
+ goto err;
+
+ /*
+ * retrieve bytes for pub1 for later
+ *
+ * We compute the pub key in the original group as we will later use it to
+ * define a provider key in the built-in group.
+ */
+ if (!TEST_true(EC_POINT_mul(group, Q1, priv1, NULL, NULL, ctx))
+ || !TEST_int_eq(EC_POINT_point2oct(group, Q1,
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, ctx), bsize)
+ || !TEST_ptr(pub1 = OPENSSL_malloc(bsize))
+ || !TEST_int_eq(EC_POINT_point2oct(group, Q1,
+ POINT_CONVERSION_UNCOMPRESSED,
+ pub1, bsize, ctx), bsize))
+ goto err;
+
+ /* retrieve bytes for pub2 for later */
+ if (!TEST_ptr(Q = EC_KEY_get0_public_key(eckey2))
+ || !TEST_int_eq(EC_POINT_point2oct(altgroup, Q,
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, ctx), bsize)
+ || !TEST_ptr(pub2 = OPENSSL_malloc(bsize))
+ || !TEST_int_eq(EC_POINT_point2oct(altgroup, Q,
+ POINT_CONVERSION_UNCOMPRESSED,
+ pub2, bsize, ctx), bsize))
+ goto err;
+
+ /* create two `EVP_PKEY`s from the `EC_KEY`s */
+ if(!TEST_ptr(pkey1 = EVP_PKEY_new())
+ || !TEST_int_eq(EVP_PKEY_assign_EC_KEY(pkey1, eckey1), 1))
+ goto err;
+ eckey1 = NULL; /* ownership passed to pkey1 */
+ if(!TEST_ptr(pkey2 = EVP_PKEY_new())
+ || !TEST_int_eq(EVP_PKEY_assign_EC_KEY(pkey2, eckey2), 1))
+ goto err;
+ eckey2 = NULL; /* ownership passed to pkey2 */
+
+ /* Compute keyexchange in both directions */
+ if (!TEST_ptr(pctx1 = EVP_PKEY_CTX_new(pkey1, NULL))
+ || !TEST_int_eq(EVP_PKEY_derive_init(pctx1), 1)
+ || !TEST_int_eq(EVP_PKEY_derive_set_peer(pctx1, pkey2), 1)
+ || !TEST_int_eq(EVP_PKEY_derive(pctx1, NULL, &sslen), 1)
+ || !TEST_int_gt(bsize, sslen)
+ || !TEST_int_eq(EVP_PKEY_derive(pctx1, buf1, &sslen), 1))
+ goto err;
+ if (!TEST_ptr(pctx2 = EVP_PKEY_CTX_new(pkey2, NULL))
+ || !TEST_int_eq(EVP_PKEY_derive_init(pctx2), 1)
+ || !TEST_int_eq(EVP_PKEY_derive_set_peer(pctx2, pkey1), 1)
+ || !TEST_int_eq(EVP_PKEY_derive(pctx2, NULL, &t), 1)
+ || !TEST_int_gt(bsize, t)
+ || !TEST_int_le(sslen, t)
+ || !TEST_int_eq(EVP_PKEY_derive(pctx2, buf2, &t), 1))
+ goto err;
+
+ /* Both sides should expect the same shared secret */
+ if (!TEST_mem_eq(buf1, sslen, buf2, t))
+ goto err;
+
+ /* Build parameters for provider-native keys */
+ if (!TEST_ptr(param_bld = OSSL_PARAM_BLD_new())
+ || !TEST_true(OSSL_PARAM_BLD_push_utf8_string(param_bld,
+ OSSL_PKEY_PARAM_GROUP_NAME,
+ curve_name, 0))
+ || !TEST_true(OSSL_PARAM_BLD_push_octet_string(param_bld,
+ OSSL_PKEY_PARAM_PUB_KEY,
+ pub1, bsize))
+ || !TEST_true(OSSL_PARAM_BLD_push_BN(param_bld,
+ OSSL_PKEY_PARAM_PRIV_KEY,
+ priv1))
+ || !TEST_ptr(params1 = OSSL_PARAM_BLD_to_param(param_bld)))
+ goto err;
+
+ OSSL_PARAM_BLD_free(param_bld);
+ if (!TEST_ptr(param_bld = OSSL_PARAM_BLD_new())
+ || !TEST_true(OSSL_PARAM_BLD_push_utf8_string(param_bld,
+ OSSL_PKEY_PARAM_GROUP_NAME,
+ curve_name, 0))
+ || !TEST_true(OSSL_PARAM_BLD_push_octet_string(param_bld,
+ OSSL_PKEY_PARAM_PUB_KEY,
+ pub2, bsize))
+ || !TEST_ptr(params2 = OSSL_PARAM_BLD_to_param(param_bld)))
+ goto err;
+
+ /* create two new provider-native `EVP_PKEY`s */
+ EVP_PKEY_CTX_free(pctx2);
+ if (!TEST_ptr(pctx2 = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL))
+ || !TEST_true(EVP_PKEY_key_fromdata_init(pctx2))
+ || !TEST_true(EVP_PKEY_fromdata(pctx2, &pkey1, params1))
+ || !TEST_true(EVP_PKEY_fromdata(pctx2, &pkey2, params2)))
+ goto err;
+
+ /* compute keyexchange once more using the provider keys */
+ EVP_PKEY_CTX_free(pctx1);
+ if (!TEST_ptr(pctx1 = EVP_PKEY_CTX_new(pkey1, NULL))
+ || !TEST_int_eq(EVP_PKEY_derive_init(pctx1), 1)
+ || !TEST_int_eq(EVP_PKEY_derive_set_peer(pctx1, pkey2), 1)
+ || !TEST_int_eq(EVP_PKEY_derive(pctx1, NULL, &t), 1)
+ || !TEST_int_gt(bsize, t)
+ || !TEST_int_le(sslen, t)
+ || !TEST_int_eq(EVP_PKEY_derive(pctx1, buf1, &t), 1)
+ /* compare with previous result */
+ || !TEST_mem_eq(buf1, t, buf2, sslen))
+ goto err;
+
+ ret = 1;
+
+ err:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ OSSL_PARAM_BLD_free(param_bld);
+ OSSL_PARAM_BLD_free_params(params1);
+ OSSL_PARAM_BLD_free_params(params2);
+ EC_POINT_free(Q1);
+ EC_POINT_free(Q2);
+ EC_POINT_free(G2);
+ EC_GROUP_free(group);
+ EC_GROUP_free(altgroup);
+ OPENSSL_free(buf1);
+ OPENSSL_free(buf2);
+ OPENSSL_free(pub1);
+ OPENSSL_free(pub2);
+ EC_KEY_free(eckey1);
+ EC_KEY_free(eckey2);
+ EVP_PKEY_free(pkey1);
+ EVP_PKEY_free(pkey2);
+ EVP_PKEY_CTX_free(pctx1);
+ EVP_PKEY_CTX_free(pctx2);
+
+ return ret;
+}
+
#endif /* OPENSSL_NO_EC */
int setup_tests(void)
@@ -2448,6 +2726,7 @@ int setup_tests(void)
ADD_ALL_TESTS(check_named_curve_from_ecparameters, crv_len);
ADD_ALL_TESTS(ec_point_hex2point_test, crv_len);
ADD_ALL_TESTS(custom_generator_test, crv_len);
+ ADD_ALL_TESTS(custom_params_test, crv_len);
#endif /* OPENSSL_NO_EC */
return 1;
}