diff options
author | Nicola Tuveri <nic.tuv@gmail.com> | 2020-07-21 17:04:38 +0200 |
---|---|---|
committer | Nicola Tuveri <nic.tuv@gmail.com> | 2020-07-29 22:45:57 +0200 |
commit | f5384f064ec2ef9f1975877da46e6f64c776427c (patch) | |
tree | 9f1b777a3ec849a43bb86d68fe8343631e0347fa | |
parent | namemap: fix threading issue (diff) | |
download | openssl-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.c | 281 |
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; } |