From f0591559f6f4697768f516da11ba5557842191b0 Mon Sep 17 00:00:00 2001 From: Shane Lontis Date: Fri, 20 Nov 2020 19:14:14 +1000 Subject: Add validate method to ECX keymanager Fixes #11619 Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/13459) --- providers/implementations/keymgmt/ecx_kmgmt.c | 77 ++++++++++++++++++++++ test/evp_pkey_provided_test.c | 95 +++++++++++++++++++++------ 2 files changed, 152 insertions(+), 20 deletions(-) diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c index 3dccbaf880..076e59eafe 100644 --- a/providers/implementations/keymgmt/ecx_kmgmt.c +++ b/providers/implementations/keymgmt/ecx_kmgmt.c @@ -60,6 +60,10 @@ static OSSL_FUNC_keymgmt_settable_params_fn ed25519_settable_params; static OSSL_FUNC_keymgmt_settable_params_fn ed448_settable_params; static OSSL_FUNC_keymgmt_has_fn ecx_has; static OSSL_FUNC_keymgmt_match_fn ecx_match; +static OSSL_FUNC_keymgmt_validate_fn x25519_validate; +static OSSL_FUNC_keymgmt_validate_fn x448_validate; +static OSSL_FUNC_keymgmt_validate_fn ed25519_validate; +static OSSL_FUNC_keymgmt_validate_fn ed448_validate; static OSSL_FUNC_keymgmt_import_fn ecx_import; static OSSL_FUNC_keymgmt_import_types_fn ecx_imexport_types; static OSSL_FUNC_keymgmt_export_fn ecx_export; @@ -670,6 +674,78 @@ void *ecx_load(const void *reference, size_t reference_sz) return NULL; } +static int ecx_key_pairwise_check(const ECX_KEY *ecx, int type) +{ + uint8_t pub[64]; + + switch (type) { + case ECX_KEY_TYPE_X25519: + X25519_public_from_private(pub, ecx->privkey); + break; + case ECX_KEY_TYPE_X448: + X448_public_from_private(pub, ecx->privkey); + break; + case ECX_KEY_TYPE_ED25519: + if (!ED25519_public_from_private(ecx->libctx, pub, ecx->privkey, + ecx->propq)) + return 0; + break; + case ECX_KEY_TYPE_ED448: + if (!ED448_public_from_private(ecx->libctx, pub, ecx->privkey, + ecx->propq)) + return 0; + break; + default: + return 0; + } + return CRYPTO_memcmp(ecx->pubkey, pub, ecx->keylen) == 0; +} + +static int ecx_validate(const void *keydata, int selection, int type, size_t keylen) +{ + const ECX_KEY *ecx = keydata; + int ok = 0; + + if (!ossl_prov_is_running()) + return 0; + + assert(keylen == ecx->keylen); + + if ((selection & ECX_POSSIBLE_SELECTIONS) != 0) + ok = 1; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && ecx->haspubkey; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && ecx->privkey != NULL; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR) + ok = ok && ecx_key_pairwise_check(ecx, type); + + return ok; +} + +static int x25519_validate(const void *keydata, int selection) +{ + return ecx_validate(keydata, selection, ECX_KEY_TYPE_X25519, X25519_KEYLEN); +} + +static int x448_validate(const void *keydata, int selection) +{ + return ecx_validate(keydata, selection, ECX_KEY_TYPE_X448, X448_KEYLEN); +} + +static int ed25519_validate(const void *keydata, int selection) +{ + return ecx_validate(keydata, selection, ECX_KEY_TYPE_ED25519, ED25519_KEYLEN); +} + +static int ed448_validate(const void *keydata, int selection) +{ + return ecx_validate(keydata, selection, ECX_KEY_TYPE_ED448, ED448_KEYLEN); +} + #define MAKE_KEYMGMT_FUNCTIONS(alg) \ const OSSL_DISPATCH ossl_##alg##_keymgmt_functions[] = { \ { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))alg##_new_key }, \ @@ -680,6 +756,7 @@ void *ecx_load(const void *reference, size_t reference_sz) { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))alg##_settable_params }, \ { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ecx_has }, \ { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ecx_match }, \ + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))alg##_validate }, \ { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ecx_import }, \ { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ecx_imexport_types }, \ { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ecx_export }, \ diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c index a5604b4fdf..a983d3b533 100644 --- a/test/evp_pkey_provided_test.c +++ b/test/evp_pkey_provided_test.c @@ -22,6 +22,11 @@ static char *datadir = NULL; +/* + * Do not change the order of the following defines unless you also + * update the for loop bounds used inside test_print_key_using_encoder() and + * test_print_key_using_encoder_public(). + */ #define PRIV_TEXT 0 #define PRIV_PEM 1 #define PRIV_DER 2 @@ -266,11 +271,25 @@ static int test_print_key_using_encoder(const char *alg, const EVP_PKEY *pk) int i; int ret = 1; - for (i = 0; i < 6; i++) + for (i = PRIV_TEXT; i <= PUB_DER; i++) + ret = ret && test_print_key_type_using_encoder(alg, i, pk); + + return ret; +} + +#ifndef OPENSSL_NO_EC +static int test_print_key_using_encoder_public(const char *alg, + const EVP_PKEY *pk) +{ + int i; + int ret = 1; + + for (i = PUB_TEXT; i <= PUB_DER; i++) ret = ret && test_print_key_type_using_encoder(alg, i, pk); return ret; } +#endif /* Array indexes used in test_fromdata_rsa */ #define N 0 @@ -709,15 +728,23 @@ err: # define ED25519_IDX 2 # define ED448_IDX 3 +/* + * tst uses indexes 0 ... (3 * 4 - 1) + * For the 4 ECX key types (X25519_IDX..ED448_IDX) + * 0..3 = public + private key. + * 4..7 = private key (This will generate the public key from the private key) + * 8..11 = public key + */ static int test_fromdata_ecx(int tst) { int ret = 0; - EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY_CTX *ctx = NULL, *ctx2 = NULL; EVP_PKEY *pk = NULL, *copy_pk = NULL; const char *alg = NULL; size_t len; unsigned char out_pub[ED448_KEYLEN]; unsigned char out_priv[ED448_KEYLEN]; + OSSL_PARAM params[3] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; /* ED448_KEYLEN > X448_KEYLEN > X25519_KEYLEN == ED25519_KEYLEN */ static unsigned char key_numbers[4][2][ED448_KEYLEN] = { @@ -836,8 +863,9 @@ static int test_fromdata_ecx(int tst) }; OSSL_PARAM *fromdata_params = NULL; int bits = 0, security_bits = 0, size = 0; + OSSL_PARAM *orig_fromdata_params = NULL; - switch (tst) { + switch (tst & 3) { case X25519_IDX: fromdata_params = x25519_fromdata_params; bits = X25519_BITS; @@ -877,6 +905,17 @@ static int test_fromdata_ecx(int tst) if (!TEST_ptr(ctx)) goto err; + orig_fromdata_params = fromdata_params; + if (tst > 7) { + /* public key only */ + fromdata_params++; + } else if (tst > 3) { + /* private key only */ + params[0] = fromdata_params[0]; + params[1] = fromdata_params[2]; + fromdata_params = params; + } + if (!TEST_true(EVP_PKEY_key_fromdata_init(ctx)) || !TEST_true(EVP_PKEY_fromdata(ctx, &pk, fromdata_params)) || !TEST_int_eq(EVP_PKEY_bits(pk), bits) @@ -884,32 +923,48 @@ static int test_fromdata_ecx(int tst) || !TEST_int_eq(EVP_PKEY_size(pk), size)) goto err; + if (!TEST_ptr(ctx2 = EVP_PKEY_CTX_new_from_pkey(NULL, pk, NULL))) + goto err; + if (tst <= 7) { + if (!TEST_true(EVP_PKEY_check(ctx2))) + goto err; + if (!TEST_true(EVP_PKEY_get_octet_string_param( + pk, orig_fromdata_params[PRIV_KEY].key, + out_priv, sizeof(out_priv), &len)) + || !TEST_mem_eq(out_priv, len, + orig_fromdata_params[PRIV_KEY].data, + orig_fromdata_params[PRIV_KEY].data_size) + || !TEST_true(EVP_PKEY_get_octet_string_param( + pk, orig_fromdata_params[PUB_KEY].key, + out_pub, sizeof(out_pub), &len)) + || !TEST_mem_eq(out_pub, len, + orig_fromdata_params[PUB_KEY].data, + orig_fromdata_params[PUB_KEY].data_size)) + goto err; + } else { + /* The private key check should fail if there is only a public key */ + if (!TEST_true(EVP_PKEY_public_check(ctx2)) + || !TEST_false(EVP_PKEY_private_check(ctx2)) + || !TEST_false(EVP_PKEY_check(ctx2))) + goto err; + } + if (!TEST_ptr(copy_pk = EVP_PKEY_new()) /* This should succeed because there are no parameters to copy */ || !TEST_true(EVP_PKEY_copy_parameters(copy_pk, pk))) goto err; - if (!TEST_true(EVP_PKEY_get_octet_string_param( - pk, fromdata_params[PRIV_KEY].key, - out_priv, sizeof(out_priv), &len)) - || !TEST_mem_eq(out_priv, len, - fromdata_params[PRIV_KEY].data, - fromdata_params[PRIV_KEY].data_size) - || !TEST_true(EVP_PKEY_get_octet_string_param( - pk, fromdata_params[PUB_KEY].key, - out_pub, sizeof(out_pub), &len)) - || !TEST_mem_eq(out_pub, len, - fromdata_params[PUB_KEY].data, - fromdata_params[PUB_KEY].data_size)) - goto err; - - ret = test_print_key_using_pem(alg, pk) - && test_print_key_using_encoder(alg, pk); + if (tst > 7) + ret = test_print_key_using_encoder_public(alg, pk); + else + ret = test_print_key_using_pem(alg, pk) + && test_print_key_using_encoder(alg, pk); err: EVP_PKEY_free(pk); EVP_PKEY_free(copy_pk); EVP_PKEY_CTX_free(ctx); + EVP_PKEY_CTX_free(ctx2); return ret; } @@ -1286,7 +1341,7 @@ int setup_tests(void) ADD_TEST(test_fromdata_dsa_fips186_4); #endif #ifndef OPENSSL_NO_EC - ADD_ALL_TESTS(test_fromdata_ecx, 4); + ADD_ALL_TESTS(test_fromdata_ecx, 4 * 3); ADD_TEST(test_fromdata_ec); #endif return 1; -- cgit v1.2.3