/* * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include #include #include #include "internal/nelem.h" #include "testutil.h" #define TEST_KEM_ENCAP 0 #define TEST_KEM_DECAP 1 #define TEST_KEM_ENCAP_DECAP 2 #define TEST_TYPE_AUTH 0 #define TEST_TYPE_NOAUTH 1 #define TEST_TYPE_AUTH_NOAUTH 2 #define TEST_KEYTYPE_P256 0 #define TEST_KEYTYPE_X25519 1 #define TEST_KEYTYPES_P256_X25519 2 static OSSL_LIB_CTX *libctx = NULL; static OSSL_PROVIDER *nullprov = NULL; static OSSL_PROVIDER *libprov = NULL; static OSSL_PARAM opparam[2]; static EVP_PKEY *rkey[TEST_KEYTYPES_P256_X25519] = { NULL, NULL }; static EVP_PKEY_CTX *rctx[TEST_KEYTYPES_P256_X25519] = { NULL, NULL }; #include "dhkem_test.inc" /* Perform encapsulate KAT's */ static int test_dhkem_encapsulate(int tstid) { int ret = 0; EVP_PKEY *rpub = NULL, *spriv = NULL; const TEST_ENCAPDATA *t = &ec_encapdata[tstid]; TEST_note("Test %s %s Decapsulate", t->curve, t->spriv != NULL ? "Auth" : ""); if (!TEST_ptr(rpub = new_raw_public_key(t->curve, t->rpub, t->rpublen))) goto err; if (t->spriv != NULL) { if (!TEST_ptr(spriv = new_raw_private_key(t->curve, t->spriv, t->sprivlen, t->spub, t->spublen))) goto err; } ret = do_encap(t, rpub, spriv); err: EVP_PKEY_free(spriv); EVP_PKEY_free(rpub); return ret; } /* Perform decapsulate KAT's */ static int test_dhkem_decapsulate(int tstid) { int ret = 0; EVP_PKEY *rpriv = NULL, *spub = NULL; const TEST_ENCAPDATA *t = &ec_encapdata[tstid]; TEST_note("Test %s %s Decapsulate", t->curve, t->spub != NULL ? "Auth" : ""); if (!TEST_ptr(rpriv = new_raw_private_key(t->curve, t->rpriv, t->rprivlen, t->rpub, t->rpublen))) goto err; if (t->spub != NULL) { if (!TEST_ptr(spub = new_raw_public_key(t->curve, t->spub, t->spublen))) goto err; } ret = do_decap(t, rpriv, spub); err: EVP_PKEY_free(spub); EVP_PKEY_free(rpriv); return ret; } /* Test that there are settables and they have correct data types */ static int test_settables(int tstid) { EVP_PKEY_CTX *ctx = rctx[tstid]; const OSSL_PARAM *settableparams; const OSSL_PARAM *p; return TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1) && TEST_ptr(settableparams = EVP_PKEY_CTX_settable_params(ctx)) && TEST_ptr(p = OSSL_PARAM_locate_const(settableparams, OSSL_KEM_PARAM_OPERATION)) && TEST_uint_eq(p->data_type, OSSL_PARAM_UTF8_STRING) && TEST_ptr(p = OSSL_PARAM_locate_const(settableparams, OSSL_KEM_PARAM_IKME)) && TEST_uint_eq(p->data_type, OSSL_PARAM_OCTET_STRING); } /* Test initing multiple times passes */ static int test_init_multiple(int tstid) { EVP_PKEY_CTX *ctx = rctx[tstid]; return TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1) && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1) && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1) && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1); } /* Fail is various bad inputs are passed to the derivekey (keygen) operation */ static int test_ec_dhkem_derivekey_fail(void) { int ret = 0; EVP_PKEY *pkey = NULL; OSSL_PARAM params[3]; EVP_PKEY_CTX *genctx = NULL; const TEST_DERIVEKEY_DATA *t = &ec_derivekey_data[0]; BIGNUM *priv = NULL; /* Check non nist curve fails */ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, "secp256k1", 0); params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM, (char *)t->ikm, t->ikmlen); params[2] = OSSL_PARAM_construct_end(); if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL)) || !TEST_int_eq(EVP_PKEY_keygen_init(genctx), 1) || !TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1) || !TEST_int_eq(EVP_PKEY_generate(genctx, &pkey),0)) goto err; /* Fail if curve is not one of P-256, P-384 or P-521 */ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, "P-224", 0); params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM, (char *)t->ikm, t->ikmlen); params[2] = OSSL_PARAM_construct_end(); if (!TEST_int_eq(EVP_PKEY_keygen_init(genctx), 1) || !TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1) || !TEST_int_eq(EVP_PKEY_generate(genctx, &pkey), 0)) goto err; /* Fail if ikm len is too small*/ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, "P-256", 0); params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM, (char *)t->ikm, t->ikmlen - 1); params[2] = OSSL_PARAM_construct_end(); if (!TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1) || !TEST_int_eq(EVP_PKEY_generate(genctx, &pkey), 0)) goto err; ret = 1; err: BN_free(priv); EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(genctx); return ret; } /* Fail if the operation parameter is not set */ static int test_no_operation_set(int tstid) { EVP_PKEY_CTX *ctx = rctx[tstid]; const TEST_ENCAPDATA *t = &ec_encapdata[tstid]; size_t len = 0; return TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1) && TEST_int_eq(EVP_PKEY_encapsulate(ctx, NULL, &len, NULL, NULL), -2) && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1) && TEST_int_eq(EVP_PKEY_decapsulate(ctx, NULL, &len, t->expected_enc, t->expected_enclen), -2); } /* Fail if the ikm is too small */ static int test_ikm_small(int tstid) { unsigned char tmp[16] = { 0 }; unsigned char secret[256]; unsigned char enc[256]; size_t secretlen = sizeof(secret); size_t enclen = sizeof(enc); OSSL_PARAM params[3]; EVP_PKEY_CTX *ctx = rctx[tstid]; params[0] = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION, OSSL_KEM_PARAM_OPERATION_DHKEM, 0); params[1] = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME, tmp, sizeof(tmp)); params[2] = OSSL_PARAM_construct_end(); return TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, params), 1) && TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc, &enclen, secret, &secretlen), 0); } /* Fail if buffers lengths are too small to hold returned data */ static int test_input_size_small(int tstid) { int ret = 0; unsigned char sec[256]; unsigned char enc[256]; size_t seclen = sizeof(sec); size_t enclen = sizeof(enc); EVP_PKEY_CTX *ctx = rctx[tstid]; if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), 1) || !TEST_int_eq(EVP_PKEY_encapsulate(ctx, NULL, &enclen, NULL, &seclen), 1)) goto err; /* buffer too small for enc */ enclen--; if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc, &enclen, sec, &seclen), 0)) goto err; enclen++; /* buffer too small for secret */ seclen--; if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc, &enclen, sec, &seclen), 0)) goto err; seclen++; if (!TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1)) goto err; /* buffer too small for decapsulate secret */ seclen--; if (!TEST_int_eq(EVP_PKEY_decapsulate(ctx, sec, &seclen, enc, enclen), 0)) goto err; seclen++; /* incorrect enclen passed to decap */ enclen--; ret = TEST_int_eq(EVP_PKEY_decapsulate(ctx, sec, &seclen, enc, enclen), 0); err: return ret; } /* Fail if the auth key has a different curve */ static int test_ec_auth_key_curve_mismatch(void) { int ret = 0; EVP_PKEY *auth = NULL; if (!TEST_ptr(auth = EVP_PKEY_Q_keygen(libctx, NULL, "EC", "P-521"))) return 0; ret = TEST_int_eq(EVP_PKEY_auth_encapsulate_init(rctx[0], auth, opparam), 0); EVP_PKEY_free(auth); return ret; } /* Fail if the auth key has a different key type to the recipient */ static int test_auth_key_type_mismatch(int tstid) { int id1 = tstid; int id2 = !tstid; return TEST_int_eq(EVP_PKEY_auth_encapsulate_init(rctx[id1], rkey[id2], opparam), 0); } static int test_ec_invalid_private_key(void) { int ret = 0; EVP_PKEY *priv = NULL; EVP_PKEY_CTX *ctx = NULL; const TEST_ENCAPDATA *t = &ec_encapdata[0]; static const unsigned char order[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51 }; ret = TEST_ptr(priv = new_raw_private_key("P-256", order, sizeof(order), t->rpub, t->rpublen)) && TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, priv, NULL)) && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 0); EVP_PKEY_free(priv); EVP_PKEY_CTX_free(ctx); return ret; } static int test_ec_public_key_infinity(void) { int ret = 0; EVP_PKEY *key = NULL; EVP_PKEY_CTX *keyctx = NULL; unsigned char s[256]; unsigned char e[256]; size_t slen = sizeof(s); size_t elen = sizeof(e); unsigned char tmp[1] = { 0 }; /* The encoding for an EC point at infinity */ EVP_PKEY_CTX *ctx = rctx[0]; const TEST_ENCAPDATA *t = &ec_encapdata[0]; ret = TEST_ptr(key = new_raw_private_key(t->curve, t->rpriv, t->rprivlen, tmp, sizeof(tmp))) && TEST_ptr(keyctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL)) /* Fail if the recipient public key is invalid */ && TEST_int_eq(EVP_PKEY_encapsulate_init(keyctx, opparam), 1) && TEST_int_eq(EVP_PKEY_encapsulate(keyctx, e, &elen, s, &slen), 0) /* Fail the decap if the recipient public key is invalid */ && TEST_int_eq(EVP_PKEY_decapsulate_init(keyctx, opparam), 1) && TEST_int_eq(EVP_PKEY_decapsulate(keyctx, s, &slen, t->expected_enc, t->expected_enclen), 0) /* Fail if the auth key has a bad public key */ && TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, key, opparam), 1) && TEST_int_eq(EVP_PKEY_encapsulate(ctx, e, &elen, s, &slen), 0); EVP_PKEY_free(key); EVP_PKEY_CTX_free(keyctx); return ret; } /* Test incorrectly passing NULL values fail */ static int test_null_params(int tstid) { EVP_PKEY_CTX *ctx = rctx[tstid]; const TEST_ENCAPDATA *t = &ec_encapdata[tstid]; /* auth_encap/decap init must be passed a non NULL value */ return TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, NULL, opparam), 0) && TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, NULL, opparam), 0) /* Check decap fails if NULL params are passed */ && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1) && TEST_int_eq(EVP_PKEY_decapsulate(ctx, NULL, NULL, t->expected_enc, t->expected_enclen), 0) /* Check encap fails if NULL params are passed */ && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), 1) && TEST_int_eq(EVP_PKEY_encapsulate(ctx, NULL, NULL, NULL, NULL), 0); } static int test_set_params(int tstid) { int ret = 0; EVP_PKEY_CTX *ctx = rctx[tstid]; OSSL_PARAM badparams[4]; int val = 1; /* wrong data type for operation param */ badparams[0] = OSSL_PARAM_construct_int(OSSL_KEM_PARAM_OPERATION, &val); badparams[1] = OSSL_PARAM_construct_end(); if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 0)) goto err; /* unknown string used for the operation param */ badparams[0] = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION, "unknown_op", 0); badparams[1] = OSSL_PARAM_construct_end(); if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 0)) goto err; /* NULL string set for the operation param */ badparams[0] = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0); badparams[1] = OSSL_PARAM_construct_end(); if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 0)) goto err; /* wrong data type for ikme param */ badparams[0] = OSSL_PARAM_construct_int(OSSL_KEM_PARAM_IKME, &val); badparams[1] = OSSL_PARAM_construct_end(); if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 0)) goto err; /* Setting the ikme to NULL is allowed */ badparams[0] = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0); badparams[1] = OSSL_PARAM_construct_end(); if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 1)) goto err; /* Test that unknown params are ignored */ badparams[0] = OSSL_PARAM_construct_int("unknownparam", &val); badparams[1] = OSSL_PARAM_construct_end(); ret = TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, badparams), 1); err: return ret; } /* * ECX keys autogen the public key if a private key is loaded, * So this test passes for ECX, but fails for EC */ static int test_nopublic(int tstid) { int ret = 0; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *priv = NULL; int encap = ((tstid & 1) == 0); int keytype = tstid >= TEST_KEM_ENCAP_DECAP; const TEST_ENCAPDATA *t = &ec_encapdata[keytype]; int expected = (keytype == TEST_KEYTYPE_X25519); TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap"); if (!TEST_ptr(priv = new_raw_private_key(t->curve, t->rpriv, t->rprivlen, NULL, 0))) goto err; if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, priv, NULL))) goto err; if (encap) { if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), expected)) goto err; } else { if (!TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), expected)) goto err; } if (expected == 0 && !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_NOT_A_PUBLIC_KEY)) goto err; ret = 1; err: EVP_PKEY_free(priv); EVP_PKEY_CTX_free(ctx); return ret; } /* Test that not setting the auth public key fails the auth encap/decap init */ static int test_noauthpublic(int tstid) { int ret = 0; EVP_PKEY *auth = NULL; int encap = ((tstid & 1) == 0); int keytype = tstid >= TEST_KEM_ENCAP_DECAP; const TEST_ENCAPDATA *t = &ec_encapdata[keytype]; EVP_PKEY_CTX *ctx = rctx[keytype]; int expected = (keytype == TEST_KEYTYPE_X25519); TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap"); if (!TEST_ptr(auth = new_raw_private_key(t->curve, t->rpriv, t->rprivlen, NULL, expected))) goto err; if (encap) { if (!TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, auth, opparam), expected)) goto err; } else { if (!TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, auth, opparam), expected)) goto err; } if (expected == 0 && !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_NOT_A_PUBLIC_KEY)) goto err; ret = 1; err: EVP_PKEY_free(auth); return ret; } /* EC specific tests */ /* Perform EC DHKEM KATs */ static int test_ec_dhkem_derivekey(int tstid) { int ret = 0; EVP_PKEY *pkey = NULL; OSSL_PARAM params[3]; EVP_PKEY_CTX *genctx = NULL; const TEST_DERIVEKEY_DATA *t = &ec_derivekey_data[tstid]; unsigned char pubkey[133]; unsigned char privkey[66]; size_t pubkeylen = 0, privkeylen = 0; BIGNUM *priv = NULL; params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, (char *)t->curvename, 0); params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM, (char *)t->ikm, t->ikmlen); params[2] = OSSL_PARAM_construct_end(); ret = TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL)) && TEST_int_eq(EVP_PKEY_keygen_init(genctx), 1) && TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1) && TEST_int_eq(EVP_PKEY_generate(genctx, &pkey), 1) && TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, pubkey, sizeof(pubkey), &pubkeylen)) && TEST_true(EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv)) && TEST_int_gt(privkeylen = BN_bn2bin(priv, privkey), 0) && TEST_int_le(privkeylen, sizeof(privkey)) && TEST_mem_eq(privkey, privkeylen, t->priv, t->privlen) && TEST_mem_eq(pubkey, pubkeylen, t->pub, t->publen); BN_free(priv); EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(genctx); return ret; } /* * Test that encapsulation uses a random seed if the ikm is not specified, * and verify that the shared secret matches the decapsulate result. */ static int test_ec_noikme(int tstid) { int ret = 0, auth = 0; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *recip = NULL; EVP_PKEY *sender_auth = NULL; unsigned char sender_secret[256]; unsigned char recip_secret[256]; unsigned char sender_pub[256]; size_t sender_secretlen = sizeof(sender_secret); size_t recip_secretlen = sizeof(recip_secret); size_t sender_publen = sizeof(sender_pub); const char *curve; int sz = OSSL_NELEM(dhkem_supported_curves); const char *op = OSSL_KEM_PARAM_OPERATION_DHKEM; if (tstid >= sz) { auth = 1; tstid -= sz; } curve = dhkem_supported_curves[tstid]; TEST_note("testing encap/decap of curve %s%s\n", curve, auth ? " with auth" : ""); if (curve[0] == 'X') { if (!TEST_ptr(recip = EVP_PKEY_Q_keygen(libctx, NULL, curve)) || (auth && !TEST_ptr(sender_auth = EVP_PKEY_Q_keygen(libctx, NULL, curve)))) goto err; } else { if (!TEST_ptr(recip = EVP_PKEY_Q_keygen(libctx, NULL, "EC", curve)) || (auth && !TEST_ptr(sender_auth = EVP_PKEY_Q_keygen(libctx, NULL, "EC", curve)))) goto err; } ret = TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, recip, NULL)) && (sender_auth == NULL || TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, sender_auth, NULL), 1)) && (sender_auth != NULL || TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1)) && TEST_int_eq(EVP_PKEY_CTX_set_kem_op(ctx, op), 1) && TEST_int_eq(EVP_PKEY_encapsulate(ctx, sender_pub, &sender_publen, sender_secret, &sender_secretlen), 1) && (sender_auth == NULL || TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, sender_auth, NULL), 1)) && (sender_auth != NULL || TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), 1)) && TEST_int_eq(EVP_PKEY_CTX_set_kem_op(ctx, op), 1) && TEST_int_eq(EVP_PKEY_decapsulate(ctx, recip_secret, &recip_secretlen, sender_pub, sender_publen), 1) && TEST_mem_eq(recip_secret, recip_secretlen, sender_secret, sender_secretlen); err: EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(sender_auth); EVP_PKEY_free(recip); return ret; } /* Test encap/decap init fail if the curve is invalid */ static int do_ec_curve_failtest(const char *curve) { int ret; EVP_PKEY *key = NULL; EVP_PKEY_CTX *ctx = NULL; ret = TEST_ptr(key = EVP_PKEY_Q_keygen(libctx, NULL, "EC", curve)) && TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL)) && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), -2) && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), -2); EVP_PKEY_free(key); EVP_PKEY_CTX_free(ctx); return ret; } static int test_ec_curve_nonnist(void) { return do_ec_curve_failtest("secp256k1"); } static int test_ec_curve_unsupported(void) { return do_ec_curve_failtest("P-224"); } /* Test that passing a bad recipient public EC key fails during encap/decap */ static int test_ec_badpublic(int tstid) { int ret = 0; EVP_PKEY *recippriv = NULL; EVP_PKEY_CTX *ctx = NULL; unsigned char secret[256]; unsigned char pub[256]; size_t secretlen = sizeof(secret); int encap = ((tstid & 1) == 0); const TEST_ENCAPDATA *t = &ec_encapdata[0]; TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap"); /* Set the recipient public key to the point at infinity */ pub[0] = 0; if (!TEST_ptr(recippriv = new_raw_private_key(t->curve, t->rpriv, t->rprivlen, pub, 1))) goto err; if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, recippriv, NULL))) goto err; if (encap) { unsigned char enc[256]; size_t enclen = sizeof(enc); if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), 1)) goto err; if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc , &enclen, secret, &secretlen), 0 )) goto err; } else { if (!TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1)) goto err; if (!TEST_int_eq(EVP_PKEY_decapsulate(ctx, secret, &secretlen, t->expected_enc, t->expected_enclen), 0)) goto err; } if (!TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_INVALID_KEY)) goto err; ret = 1; err: EVP_PKEY_free(recippriv); EVP_PKEY_CTX_free(ctx); return ret; } static int test_ec_badauth(int tstid) { int ret = 0; EVP_PKEY *auth = NULL; unsigned char enc[256]; unsigned char secret[256]; unsigned char pub[256]; size_t enclen = sizeof(enc); size_t secretlen = sizeof(secret); int encap = ((tstid & 1) == 0); const TEST_ENCAPDATA *t = &ec_encapdata[TEST_KEYTYPE_P256]; EVP_PKEY_CTX *ctx = rctx[TEST_KEYTYPE_P256]; TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap"); /* Set the auth public key to the point at infinity */ pub[0] = 0; if (!TEST_ptr(auth = new_raw_private_key(t->curve, t->rpriv, t->rprivlen, pub, 1))) goto err; if (encap) { if (!TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, auth, opparam), 1) || !TEST_int_eq(EVP_PKEY_encapsulate(ctx, enc, &enclen, secret, &secretlen), 0)) goto err; } else { if (!TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, auth, opparam), 1) || !TEST_int_eq(EVP_PKEY_decapsulate(ctx, secret, &secretlen, t->expected_enc, t->expected_enclen), 0)) goto err; } if (!TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_INVALID_KEY)) goto err; ret = 1; err: EVP_PKEY_free(auth); return ret; } static int test_ec_invalid_decap_enc_buffer(void) { const TEST_ENCAPDATA *t = &ec_encapdata[TEST_KEYTYPE_P256]; unsigned char enc[256]; unsigned char secret[256]; size_t secretlen = sizeof(secret); EVP_PKEY_CTX *ctx = rctx[0]; memcpy(enc, t->expected_enc, t->expected_enclen); enc[0] = 0xFF; return TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1) && TEST_int_eq(EVP_PKEY_decapsulate(ctx, secret, &secretlen, enc, t->expected_enclen), 0); } /* ECX specific tests */ /* Perform ECX DHKEM KATs */ static int test_ecx_dhkem_derivekey(int tstid) { int ret; OSSL_PARAM params[2]; EVP_PKEY_CTX *genctx; EVP_PKEY *pkey = NULL; unsigned char pubkey[64]; unsigned char privkey[64]; unsigned char masked_priv[64]; size_t pubkeylen = 0, privkeylen = 0; const TEST_DERIVEKEY_DATA *t = &ecx_derivekey_data[tstid]; memcpy(masked_priv, t->priv, t->privlen); if (OPENSSL_strcasecmp(t->curvename, "X25519") == 0) { /* * The RFC test vector seems incorrect since it is not in serialized form, * So manually do the conversion here for now. */ masked_priv[0] &= 248; masked_priv[t->privlen - 1] &= 127; masked_priv[t->privlen - 1] |= 64; } else { masked_priv[0] &= 252; masked_priv[t->privlen - 1] |= 128; } params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM, (char *)t->ikm, t->ikmlen); params[1] = OSSL_PARAM_construct_end(); ret = TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, t->curvename, NULL)) && TEST_int_eq(EVP_PKEY_keygen_init(genctx), 1) && TEST_int_eq(EVP_PKEY_CTX_set_params(genctx, params), 1) && TEST_int_eq(EVP_PKEY_keygen(genctx, &pkey), 1) && TEST_int_eq(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, pubkey, sizeof(pubkey), &pubkeylen), 1) && TEST_int_eq(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, privkey, sizeof(privkey), &privkeylen), 1) && TEST_mem_eq(t->pub, t->publen, pubkey, pubkeylen) && TEST_mem_eq(masked_priv, t->privlen, privkey, privkeylen); EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(genctx); return ret; } /* Fail if the auth key has a different curve */ static int test_ecx_auth_key_curve_mismatch(void) { int ret = 0; EVP_PKEY *auth = NULL; if (!TEST_ptr(auth = EVP_PKEY_Q_keygen(libctx, NULL, "X448"))) return 0; ret = TEST_int_eq(EVP_PKEY_auth_encapsulate_init(rctx[TEST_KEYTYPE_X25519], auth, opparam), 0); EVP_PKEY_free(auth); return ret; } /* Fail if ED448 is used for DHKEM */ static int test_ed_curve_unsupported(void) { int ret; EVP_PKEY *key = NULL; EVP_PKEY_CTX *ctx = NULL; ret = TEST_ptr(key = EVP_PKEY_Q_keygen(libctx, NULL, "ED448")) && TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL)) && TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), -2) && TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, NULL), -2); EVP_PKEY_free(key); EVP_PKEY_CTX_free(ctx); return ret; } int setup_tests(void) { const char *prov_name = "default"; char *config_file = NULL; char *op = OSSL_KEM_PARAM_OPERATION_DHKEM; if (!test_get_libctx(&libctx, &nullprov, config_file, &libprov, prov_name)) return 0; opparam[0] = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION, op, 0); opparam[1] = OSSL_PARAM_construct_end(); /* Create P256 and X25519 keys and ctxs */ if (!TEST_ptr(rkey[TEST_KEYTYPE_P256] = EVP_PKEY_Q_keygen(libctx, NULL, "EC", "P-256"))) goto err; if (!TEST_ptr(rkey[TEST_KEYTYPE_X25519] = EVP_PKEY_Q_keygen(libctx, NULL, "X25519"))) goto err; if (!TEST_ptr(rctx[TEST_KEYTYPE_P256] = EVP_PKEY_CTX_new_from_pkey(libctx, rkey[TEST_KEYTYPE_P256], NULL))) goto err; if (!TEST_ptr(rctx[TEST_KEYTYPE_X25519] = EVP_PKEY_CTX_new_from_pkey(libctx, rkey[TEST_KEYTYPE_X25519], NULL))) goto err; ADD_ALL_TESTS(test_dhkem_encapsulate, OSSL_NELEM(ec_encapdata)); ADD_ALL_TESTS(test_dhkem_decapsulate, OSSL_NELEM(ec_encapdata)); ADD_ALL_TESTS(test_settables, TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_init_multiple, TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_auth_key_type_mismatch, TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_no_operation_set, TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_ikm_small, TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_input_size_small, TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_null_params, TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_set_params, TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_nopublic, TEST_KEM_ENCAP_DECAP * TEST_KEYTYPES_P256_X25519); ADD_ALL_TESTS(test_noauthpublic, TEST_KEM_ENCAP_DECAP * TEST_KEYTYPES_P256_X25519); /* EC Specific tests */ ADD_ALL_TESTS(test_ec_dhkem_derivekey, OSSL_NELEM(ec_derivekey_data)); ADD_ALL_TESTS(test_ec_noikme, TEST_TYPE_AUTH_NOAUTH * OSSL_NELEM(dhkem_supported_curves)); ADD_TEST(test_ec_auth_key_curve_mismatch); ADD_TEST(test_ec_invalid_private_key); ADD_TEST(test_ec_dhkem_derivekey_fail); ADD_TEST(test_ec_curve_nonnist); ADD_TEST(test_ec_curve_unsupported); ADD_TEST(test_ec_invalid_decap_enc_buffer); ADD_TEST(test_ec_public_key_infinity); ADD_ALL_TESTS(test_ec_badpublic, TEST_KEM_ENCAP_DECAP); ADD_ALL_TESTS(test_ec_badauth, TEST_KEM_ENCAP_DECAP); /* ECX specific tests */ ADD_ALL_TESTS(test_ecx_dhkem_derivekey, OSSL_NELEM(ecx_derivekey_data)); ADD_TEST(test_ecx_auth_key_curve_mismatch); ADD_TEST(test_ed_curve_unsupported); return 1; err: return 0; } void cleanup_tests(void) { EVP_PKEY_free(rkey[1]); EVP_PKEY_free(rkey[0]); EVP_PKEY_CTX_free(rctx[1]); EVP_PKEY_CTX_free(rctx[0]); OSSL_PROVIDER_unload(libprov); OSSL_LIB_CTX_free(libctx); OSSL_PROVIDER_unload(nullprov); }