HPKE base mode with single-shot API

Add support for HPKE base mode with single-shot API (see RFC 9180) using
OpenSSL. This is needed for DPP private introduction protocol.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2022-07-17 23:33:11 +03:00 committed by Jouni Malinen
parent f0273bc814
commit 786ea402bc
3 changed files with 1240 additions and 0 deletions

View file

@ -1010,6 +1010,16 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
*/ */
struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len); struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len);
/**
* crypto_ec_key_set_priv - Initialize EC key pair from raw key data
* @group: Identifying number for the ECC group
* @raw: Raw key data
* @raw_len: Length of @raw buffer
* Returns: EC key or %NULL on failure
*/
struct crypto_ec_key * crypto_ec_key_set_priv(int group,
const u8 *raw, size_t raw_len);
/** /**
* crypto_ec_key_parse_pub - Initialize EC key pair from SubjectPublicKeyInfo ASN.1 * crypto_ec_key_parse_pub - Initialize EC key pair from SubjectPublicKeyInfo ASN.1
* @der: DER encoding of ASN.1 SubjectPublicKeyInfo * @der: DER encoding of ASN.1 SubjectPublicKeyInfo
@ -1313,6 +1323,58 @@ struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
*/ */
void crypto_rsa_key_free(struct crypto_rsa_key *key); void crypto_rsa_key_free(struct crypto_rsa_key *key);
enum hpke_mode {
HPKE_MODE_BASE = 0x00,
HPKE_MODE_PSK = 0x01,
HPKE_MODE_AUTH = 0x02,
HPKE_MODE_AUTH_PSK = 0x03,
};
enum hpke_kem_id {
HPKE_DHKEM_P256_HKDF_SHA256 = 0x0010,
HPKE_DHKEM_P384_HKDF_SHA384 = 0x0011,
HPKE_DHKEM_P521_HKDF_SHA512 = 0x0012,
HPKE_DHKEM_X5519_HKDF_SHA256 = 0x0020,
HPKE_DHKEM_X448_HKDF_SHA512 = 0x0021,
};
enum hpke_kdf_id {
HPKE_KDF_HKDF_SHA256 = 0x0001,
HPKE_KDF_HKDF_SHA384 = 0x0002,
HPKE_KDF_HKDF_SHA512 = 0x0003,
};
enum hpke_aead_id {
HPKE_AEAD_AES_128_GCM = 0x0001,
HPKE_AEAD_AES_256_GCM = 0x0002,
HPKE_AEAD_CHACHA20POLY1305 = 0x0003,
};
/**
* hpke_base_seal - HPKE base mode single-shot encrypt
* Returns: enc | ct; or %NULL on failure
*/
struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id,
enum hpke_kdf_id kdf_id,
enum hpke_aead_id aead_id,
struct crypto_ec_key *peer_pub,
const u8 *info, size_t info_len,
const u8 *aad, size_t aad_len,
const u8 *pt, size_t pt_len);
/**
* hpke_base_open - HPKE base mode single-shot decrypt
* @enc_ct: enc | ct
* Returns: pt; or %NULL on failure
*/
struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id,
enum hpke_kdf_id kdf_id,
enum hpke_aead_id aead_id,
struct crypto_ec_key *own_priv,
const u8 *info, size_t info_len,
const u8 *aad, size_t aad_len,
const u8 *enc_ct, size_t enc_ct_len);
/** /**
* crypto_unload - Unload crypto resources * crypto_unload - Unload crypto resources
* *

View file

@ -2190,6 +2190,285 @@ static int test_extract_expand_hkdf(void)
} }
#ifdef CONFIG_DPP3
static const struct hpke_test {
const char *name;
enum hpke_mode mode;
enum hpke_kem_id kem_id;
enum hpke_kdf_id kdf_id;
enum hpke_aead_id aead_id;
const char *info;
int sk_r_group;
const char *pk_r;
const char *sk_r;
const char *enc;
const char *pt;
const char *aad;
const char *ct;
} hpke_tests[] = {
{
.name = "A.3. DHKEM(P-256, HKDF-SHA256), HKDF-SHA256, AES-128-GCM",
.mode = HPKE_MODE_BASE,
.kem_id = HPKE_DHKEM_P256_HKDF_SHA256,
.kdf_id = HPKE_KDF_HKDF_SHA256,
.aead_id = HPKE_AEAD_AES_128_GCM,
.info = "4f6465206f6e2061204772656369616e2055726e",
.sk_r_group = 19,
.pk_r = "04fe8c19ce0905191ebc298a9245792531f26f0cece2460639e8bc39cb7f706a826a779b4cf969b8a0e539c7f62fb3d30ad6aa8f80e30f1d128aafd68a2ce72ea0",
.sk_r = "f3ce7fdae57e1a310d87f1ebbde6f328be0a99cdbcadf4d6589cf29de4b8ffd2",
.enc = "04a92719c6195d5085104f469a8b9814d5838ff72b60501e2c4466e5e67b325ac98536d7b61a1af4b78e5b7f951c0900be863c403ce65c9bfcb9382657222d18c4",
.pt = "4265617574792069732074727574682c20747275746820626561757479",
.aad = "436f756e742d30",
.ct = "5ad590bb8baa577f8619db35a36311226a896e7342a6d836d8b7bcd2f20b6c7f9076ac232e3ab2523f39513434",
},
{
.name = "A.4. DHKEM(P-256, HKDF-SHA256), HKDF-SHA512, AES-128-GCM",
.mode = HPKE_MODE_BASE,
.kem_id = HPKE_DHKEM_P256_HKDF_SHA256,
.kdf_id = HPKE_KDF_HKDF_SHA512,
.aead_id = HPKE_AEAD_AES_128_GCM,
.info = "4f6465206f6e2061204772656369616e2055726e",
.sk_r_group = 19,
.pk_r = "04085aa5b665dc3826f9650ccbcc471be268c8ada866422f739e2d531d4a8818a9466bc6b449357096232919ec4fe9070ccbac4aac30f4a1a53efcf7af90610edd",
.sk_r = "3ac8530ad1b01885960fab38cf3cdc4f7aef121eaa239f222623614b4079fb38",
.enc = "0493ed86735bdfb978cc055c98b45695ad7ce61ce748f4dd63c525a3b8d53a15565c6897888070070c1579db1f86aaa56deb8297e64db7e8924e72866f9a472580",
.pt = "4265617574792069732074727574682c20747275746820626561757479",
.aad = "436f756e742d30",
.ct = "d3cf4984931484a080f74c1bb2a6782700dc1fef9abe8442e44a6f09044c88907200b332003543754eb51917ba",
},
{
.name = "A.6. DHKEM(P-521, HKDF-SHA512), HKDF-SHA512, AES-256-GCM",
.mode = HPKE_MODE_BASE,
.kem_id = HPKE_DHKEM_P521_HKDF_SHA512,
.kdf_id = HPKE_KDF_HKDF_SHA512,
.aead_id = HPKE_AEAD_AES_256_GCM,
.info = "4f6465206f6e2061204772656369616e2055726e",
.sk_r_group = 21,
.pk_r = "0401b45498c1714e2dce167d3caf162e45e0642afc7ed435df7902ccae0e84ba0f7d373f646b7738bbbdca11ed91bdeae3cdcba3301f2457be452f271fa6837580e661012af49583a62e48d44bed350c7118c0d8dc861c238c72a2bda17f64704f464b57338e7f40b60959480c0e58e6559b190d81663ed816e523b6b6a418f66d2451ec64",
.sk_r = "01462680369ae375e4b3791070a7458ed527842f6a98a79ff5e0d4cbde83c27196a3916956655523a6a2556a7af62c5cadabe2ef9da3760bb21e005202f7b2462847",
.enc = "040138b385ca16bb0d5fa0c0665fbbd7e69e3ee29f63991d3e9b5fa740aab8900aaeed46ed73a49055758425a0ce36507c54b29cc5b85a5cee6bae0cf1c21f2731ece2013dc3fb7c8d21654bb161b463962ca19e8c654ff24c94dd2898de12051f1ed0692237fb02b2f8d1dc1c73e9b366b529eb436e98a996ee522aef863dd5739d2f29b0",
.pt = "4265617574792069732074727574682c20747275746820626561757479",
.aad = "436f756e742d30",
.ct = "170f8beddfe949b75ef9c387e201baf4132fa7374593dfafa90768788b7b2b200aafcc6d80ea4c795a7c5b841a",
},
{ /* self-generated test vector for P-384 */
.name = "custom DHKEM(P-384, HKDF-SHA384), HKDF-SHA384, AES-256-GCM",
.mode = HPKE_MODE_BASE,
.kem_id = HPKE_DHKEM_P384_HKDF_SHA384,
.kdf_id = HPKE_KDF_HKDF_SHA384,
.aead_id = HPKE_AEAD_AES_256_GCM,
.info = "4f6465206f6e2061204772656369616e2055726e",
.sk_r_group = 20,
.pk_r = "049c0e4dcbbb3c80715cafaa1839d0bc3c3adcc95eb8062f84175f9c3cec115e6b799061c65a0605907785c25b3571564706a8ba6a204452b38c7c205db17d328f2353df05d5f1c568e7503331178c36c2d37bbed48401295407face3f8dae5ed8",
.sk_r = "cabffb07d20ffcfdaa043e1de49e1654659e0f0aba5de56523e8b73dc80c579a9e5c89ed3810ec21c4bafcf74ad2a245",
.enc = "04b30bea96d0e51582033b02a4d676d0464a5eb2d858be86cda1c4e6f8b2aa9fb80f5365483f781b1b3a8b3b8efd50b0f7bca16f06d0435fa3da1d671ea0a318b40fe170a074923c651e5dc824966b7b98d0e36bdf932875dae7130369a793cecc",
.pt = "4265617574792069732074727574682c20747275746820626561757479",
.aad = "436f756e742d30",
.ct = "ae7feccfea0f8fcd620d15369a28db8701cdc90d55c20efff6296bd441697b0da34671d1f3c4864183e86d27fc",
},
{ /* self-generated test vector for BP-256 */
.name = "custom PB-256 using DHKEM(P-256, HKDF-SHA256), HKDF-SHA256, AES-128-GCM",
.mode = HPKE_MODE_BASE,
.kem_id = HPKE_DHKEM_P256_HKDF_SHA256,
.kdf_id = HPKE_KDF_HKDF_SHA256,
.aead_id = HPKE_AEAD_AES_128_GCM,
.info = "4f6465206f6e2061204772656369616e2055726e",
.sk_r_group = 28,
.pk_r = "04a2cb9c4cae90cdc1c27516e9f84b6b166e4b1dcc517286268239ddb0bf74cca6390fed092ac4423ab2192b8bb41a4824d908d2053b93fc813830bebac5ce19b9",
.sk_r = "11d9db41c4341166ca52f5a1775595c0bdb4934350daeb7bce659c4b7a40e314",
.enc = "047a25e309c7ee50ec27f13d44734a3ccd8c703e3affcc728513df416511ef9bf02f5e7750e7415de8b5f306ebd3fc88ea9b9368523eb1733a8d82c1a877e5a0f4",
.pt = "4265617574792069732074727574682c20747275746820626561757479",
.aad = "436f756e742d30",
.ct = "17c84b3f07f6ffe08ff2be45c709ea782229504aa5b2253876725c6c39f8d8c992304fc5877994f79d6c10d462",
},
{ /* self-generated test vector for BP-384 */
.name = "custom PB-384 using DHKEM(P-384, HKDF-SHA384), HKDF-SHA384, AES-256-GCM",
.mode = HPKE_MODE_BASE,
.kem_id = HPKE_DHKEM_P384_HKDF_SHA384,
.kdf_id = HPKE_KDF_HKDF_SHA384,
.aead_id = HPKE_AEAD_AES_256_GCM,
.info = "4f6465206f6e2061204772656369616e2055726e",
.sk_r_group = 29,
.pk_r = "041f4199ad28835908079c45d165d55630098be53eb4beede9921f5b2204fa396111f99ac54c56411f7cb2c43ec18d8e604d895027228cf975f5a4b598f189d8fb03e3fefe020258c40d4d1b15fd7587d209925d67a41f9659a8ed6f662fb441e4",
.sk_r = "7017cf8a5a9a81ad4e0d755ccbea27a378b787561f8d5662639850805fefcbaab6b9a15729872abb7dc53d19a6cf77e4",
.enc = "0415d49dedc5bc1ffe9f8de9022c266bb605ec6cd7b77b6ce68974095398856f8aefa4b7abbfbd496b99a2dda3a9c65f1a71b9d40255aa1c7c4205a8b4ef611b96ed29fd2d7b0cde4c0e82058805e6276025cc4fc606f6e5771c31bd9704e9ba0b",
.pt = "4265617574792069732074727574682c20747275746820626561757479",
.aad = "436f756e742d30",
.ct = "5f5e9f82bedadec0e9b01a1b304cb48b05c0d6d397b1c8a95ed541218ec54f634a41cbc4066910a409e47b254e",
},
{ /* self-generated test vector for BP-512 */
.name = "custom PB-512 using DHKEM(P-521, HKDF-SHA512), HKDF-SHA512, AES-256-GCM",
.mode = HPKE_MODE_BASE,
.kem_id = HPKE_DHKEM_P521_HKDF_SHA512,
.kdf_id = HPKE_KDF_HKDF_SHA512,
.aead_id = HPKE_AEAD_AES_256_GCM,
.info = "4f6465206f6e2061204772656369616e2055726e",
.sk_r_group = 30,
.pk_r = "049e81046a531365a3b5215ac37e7b38f5fa34f86c4eb2e03113b197390a26c555bb007596e131c2541f336eb24a45f44283b5b53fedddfa5642675602fdec17d34120a35efffb44952e32dee7732f2f3245c3314269996b610703a63fb8555a75ca5092690a1125ae8712c1e31fd77aee42bd052e71f9f9459814d6f4065bcea0",
.sk_r = "483b6882608182b296843fa7dfffbdd61ed0372574d4aa32a035c8e33a493927aaf00d42bd9124ebe4df26010b38124668c02b35a749e74845d565734310cfe9",
.enc = "04158d18473aeb3b283d3345b1a87d3de2b192ff9e41b5a98f91daacfb24be72e698cbc04c33078681e507bf346c0ea70c927083a22ca9ea027f420067ee42285b798d95fea51002d097ce28371883202bfd300fb64943669e32c6f1a348087368bb480b757892ebd199a9389978c92cbc44076626d705a771fbbd90c030a6767e",
.pt = "4265617574792069732074727574682c20747275746820626561757479",
.aad = "436f756e742d30",
.ct = "033d91c4514857da5b833635180c1acc09f175cbf44777a7b71e177705cfd17437b1c85d671dd767bb4fe20e2e",
},
};
static int run_hpke_test(const struct hpke_test *test)
{
struct wpabuf *info, *pk_r, *sk_r, *enc, *pt, *aad, *ct;
struct wpabuf *res_pt = NULL, *enc_ct = NULL, *res_ct = NULL;
struct crypto_ec_key *own_priv = NULL, *peer_pub = NULL;
int res = -1;
size_t coord_len;
wpa_printf(MSG_INFO, "- %s", test->name);
info = wpabuf_parse_bin(test->info);
pk_r = wpabuf_parse_bin(test->pk_r);
sk_r = wpabuf_parse_bin(test->sk_r);
enc = wpabuf_parse_bin(test->enc);
pt = wpabuf_parse_bin(test->pt);
aad = wpabuf_parse_bin(test->aad);
ct = wpabuf_parse_bin(test->ct);
if (!info || !pk_r || !sk_r || !enc || !pt || !aad || !ct) {
wpa_printf(MSG_ERROR, "Could not parse test data");
goto fail;
}
/* Receiver - decryption against the test vector */
enc_ct = wpabuf_concat(enc, ct);
enc = NULL;
ct = NULL;
if (!enc_ct)
goto fail;
own_priv = crypto_ec_key_set_priv(test->sk_r_group, wpabuf_head(sk_r),
wpabuf_len(sk_r));
if (!own_priv) {
wpa_printf(MSG_ERROR,
"HPKE base open - failed to set private key");
goto fail;
}
res_pt = hpke_base_open(test->kem_id, test->kdf_id, test->aead_id,
own_priv,
wpabuf_head(info), wpabuf_len(info),
wpabuf_head(aad), wpabuf_len(aad),
wpabuf_head(enc_ct), wpabuf_len(enc_ct));
if (!res_pt) {
wpa_printf(MSG_ERROR, "HPKE base open - failed to decrypt");
wpa_hexdump_buf(MSG_INFO, "pt", res_pt);
goto fail;
}
if (wpabuf_len(res_pt) != wpabuf_len(pt) ||
os_memcmp(wpabuf_head(res_pt), wpabuf_head(pt),
wpabuf_len(pt)) != 0) {
wpa_printf(MSG_ERROR,
"HPKE base open - failed - decryption mismatch");
goto fail;
}
/* Sender - encryption (randomized algorithm) */
if (test->sk_r_group == 19)
coord_len = 32;
else if (test->sk_r_group == 20)
coord_len = 48;
else if (test->sk_r_group == 21)
coord_len = 66;
else if (test->sk_r_group == 28)
coord_len = 32;
else if (test->sk_r_group == 29)
coord_len = 48;
else if (test->sk_r_group == 30)
coord_len = 64;
else
goto fail;
if (wpabuf_len(pk_r) != 1 + 2 * coord_len) {
wpa_printf(MSG_ERROR, "Unexpected pkR length (%zu != %zu)",
wpabuf_len(pk_r), 1 + 2 * coord_len);
goto fail;
}
peer_pub = crypto_ec_key_set_pub(test->sk_r_group,
wpabuf_head_u8(pk_r) + 1,
wpabuf_head_u8(pk_r) + 1 + coord_len,
coord_len);
if (!peer_pub) {
wpa_printf(MSG_ERROR,
"HPKE base open - failed to set public key");
goto fail;
}
res_ct = hpke_base_seal(test->kem_id, test->kdf_id, test->aead_id,
peer_pub,
wpabuf_head(info), wpabuf_len(info),
wpabuf_head(aad), wpabuf_len(aad),
wpabuf_head(pt), wpabuf_len(pt));
if (!res_ct) {
wpa_printf(MSG_ERROR, "HPKE base open - failed to encrypt");
goto fail;
}
/* Receiver - decryption (to verify own encryption) */
wpabuf_free(res_pt);
res_pt = hpke_base_open(test->kem_id, test->kdf_id, test->aead_id,
own_priv,
wpabuf_head(info), wpabuf_len(info),
wpabuf_head(aad), wpabuf_len(aad),
wpabuf_head(res_ct), wpabuf_len(res_ct));
if (!res_pt) {
wpa_printf(MSG_ERROR, "HPKE base open - failed to decrypt own encrypted version");
goto fail;
}
if (wpabuf_len(res_pt) != wpabuf_len(pt) ||
os_memcmp(wpabuf_head(res_pt), wpabuf_head(pt),
wpabuf_len(pt)) != 0) {
wpa_printf(MSG_ERROR,
"HPKE base open - failed - decryption mismatch for own encrypted version");
wpa_hexdump_buf(MSG_INFO, "pt", res_pt);
goto fail;
}
res = 0;
fail:
wpabuf_free(info);
wpabuf_free(pk_r);
wpabuf_free(sk_r);
wpabuf_free(enc);
wpabuf_free(pt);
wpabuf_free(aad);
wpabuf_free(ct);
wpabuf_free(enc_ct);
wpabuf_free(res_pt);
wpabuf_free(res_ct);
crypto_ec_key_deinit(own_priv);
return res;
}
#endif /* CONFIG_DPP3 */
static int test_hpke(void)
{
#ifdef CONFIG_DPP3
unsigned int i;
wpa_printf(MSG_INFO, "RFC 9180 - HPKE");
for (i = 0; i < ARRAY_SIZE(hpke_tests); i++) {
if (run_hpke_test(&hpke_tests[i]) < 0)
return -1;
}
wpa_printf(MSG_INFO, "HPKE base open test cases passed");
#endif /* CONFIG_DPP3 */
return 0;
}
static int test_ms_funcs(void) static int test_ms_funcs(void)
{ {
#ifndef CONFIG_FIPS #ifndef CONFIG_FIPS
@ -2310,6 +2589,7 @@ int crypto_module_tests(void)
test_sha384() || test_sha384() ||
test_fips186_2_prf() || test_fips186_2_prf() ||
test_extract_expand_hkdf() || test_extract_expand_hkdf() ||
test_hpke() ||
test_ms_funcs()) test_ms_funcs())
ret = -1; ret = -1;

View file

@ -3039,6 +3039,141 @@ fail:
} }
struct crypto_ec_key * crypto_ec_key_set_priv(int group,
const u8 *raw, size_t raw_len)
{
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
const char *group_name;
OSSL_PARAM params[4];
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
BIGNUM *priv;
EC_POINT *pub = NULL;
EC_GROUP *ec_group = NULL;
size_t len;
u8 *pub_bin = NULL;
u8 *priv_bin = NULL;
int priv_bin_len;
group_name = crypto_ec_group_2_name(group);
if (!group_name)
return NULL;
priv = BN_bin2bn(raw, raw_len, NULL);
if (!priv)
return NULL;
priv_bin = os_malloc(raw_len);
if (!priv_bin)
goto fail;
priv_bin_len = BN_bn2lebinpad(priv, priv_bin, raw_len);
if (priv_bin_len < 0)
goto fail;
ec_group = EC_GROUP_new_by_curve_name(crypto_ec_group_2_nid(group));
if (!ec_group)
goto fail;
pub = EC_POINT_new(ec_group);
if (!pub ||
EC_POINT_mul(ec_group, pub, priv, NULL, NULL, NULL) != 1)
goto fail;
len = EC_POINT_point2oct(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED,
NULL, 0, NULL);
if (len == 0)
goto fail;
pub_bin = os_malloc(len);
if (!pub_bin)
goto fail;
len = EC_POINT_point2oct(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED,
pub_bin, len, NULL);
if (len == 0)
goto fail;
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
(char *) group_name, 0);
params[1] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PRIV_KEY,
priv_bin, priv_bin_len);
params[2] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
pub_bin, len);
params[3] = OSSL_PARAM_construct_end();
ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
if (!ctx ||
EVP_PKEY_fromdata_init(ctx) <= 0 ||
EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0)
goto fail;
out:
bin_clear_free(priv_bin, raw_len);
os_free(pub_bin);
BN_clear_free(priv);
EVP_PKEY_CTX_free(ctx);
EC_POINT_free(pub);
EC_GROUP_free(ec_group);
return (struct crypto_ec_key *) pkey;
fail:
EVP_PKEY_free(pkey);
pkey = NULL;
goto out;
#else /* OpenSSL version >= 3.0 */
EC_KEY *eckey = NULL;
EVP_PKEY *pkey = NULL;
BIGNUM *priv = NULL;
int nid;
const EC_GROUP *ec_group;
EC_POINT *pub = NULL;
nid = crypto_ec_group_2_nid(group);
if (nid < 0) {
wpa_printf(MSG_ERROR, "OpenSSL: Unsupported group %d", group);
return NULL;
}
eckey = EC_KEY_new_by_curve_name(nid);
priv = BN_bin2bn(raw, raw_len, NULL);
if (!eckey || !priv ||
EC_KEY_set_private_key(eckey, priv) != 1) {
wpa_printf(MSG_ERROR,
"OpenSSL: Failed to set EC_KEY: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
ec_group = EC_KEY_get0_group(eckey);
if (!ec_group)
goto fail;
pub = EC_POINT_new(ec_group);
if (!pub ||
EC_POINT_mul(ec_group, pub, priv, NULL, NULL, NULL) != 1 ||
EC_KEY_set_public_key(eckey, pub) != 1) {
wpa_printf(MSG_ERROR,
"OpenSSL: Failed to set EC_KEY(pub): %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
wpa_printf(MSG_ERROR, "OpenSSL: Could not create EVP_PKEY");
goto fail;
}
out:
BN_clear_free(priv);
EC_POINT_free(pub);
return (struct crypto_ec_key *) pkey;
fail:
EC_KEY_free(eckey);
EVP_PKEY_free(pkey);
pkey = NULL;
goto out;
#endif /* OpenSSL version >= 3.0 */
}
struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len) struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
{ {
EVP_PKEY *pkey; EVP_PKEY *pkey;
@ -4431,6 +4566,769 @@ void crypto_rsa_key_free(struct crypto_rsa_key *key)
} }
#ifdef CONFIG_DPP3
#define HPKE_MAX_SHARED_SECRET_LEN 66
#define HPKE_MAX_HASH_LEN 64
#define HPKE_MAX_KEY_LEN 32
#define HPKE_MAX_NONCE_LEN 12
#define HPKE_MAX_PUB_LEN (1 + 2 * 66)
struct hpke_context {
/* KEM */
enum hpke_kem_id kem_id;
int kem_nid;
int iana_group;
size_t n_pk;
size_t n_secret;
const EVP_MD *kem_h;
size_t kem_n_h;
/* KDF */
enum hpke_kdf_id kdf_id;
const EVP_MD *kdf_h;
size_t n_h;
/* AEAD */
enum hpke_aead_id aead_id;
const EVP_CIPHER *cipher;
size_t n_k;
size_t n_n;
size_t n_t;
u8 key[HPKE_MAX_KEY_LEN];
u8 base_nonce[HPKE_MAX_NONCE_LEN];
};
static void hpke_free_context(struct hpke_context *ctx)
{
bin_clear_free(ctx, sizeof(*ctx));
}
static struct hpke_context * hpke_get_context(enum hpke_kem_id kem_id,
enum hpke_kdf_id kdf_id,
enum hpke_aead_id aead_id,
struct crypto_ec_key *key)
{
struct hpke_context *ctx;
int group;
ctx = os_zalloc(sizeof(*ctx));
if (!ctx)
return NULL;
ctx->kem_id = kem_id;
switch (kem_id) {
case HPKE_DHKEM_P256_HKDF_SHA256:
ctx->kem_nid = NID_X9_62_prime256v1;
ctx->iana_group = 19;
ctx->n_pk = 65;
ctx->n_secret = 32;
ctx->kem_h = EVP_sha256();
ctx->kem_n_h = 32;
break;
case HPKE_DHKEM_P384_HKDF_SHA384:
ctx->kem_nid = NID_secp384r1;
ctx->iana_group = 20;
ctx->n_pk = 97;
ctx->n_secret = 48;
ctx->kem_h = EVP_sha384();
ctx->kem_n_h = 48;
break;
case HPKE_DHKEM_P521_HKDF_SHA512:
ctx->kem_nid = NID_secp521r1;
ctx->iana_group = 21;
ctx->n_pk = 133;
ctx->n_secret = 64;
ctx->kem_h = EVP_sha512();
ctx->kem_n_h = 64;
break;
default:
goto fail;
}
ctx->kdf_id = kdf_id;
switch (kdf_id) {
case HPKE_KDF_HKDF_SHA256:
ctx->kdf_h = EVP_sha256();
ctx->n_h = 32;
break;
case HPKE_KDF_HKDF_SHA384:
ctx->kdf_h = EVP_sha384();
ctx->n_h = 48;
break;
case HPKE_KDF_HKDF_SHA512:
ctx->kdf_h = EVP_sha512();
ctx->n_h = 64;
break;
default:
goto fail;
}
ctx->aead_id = aead_id;
switch (aead_id) {
case HPKE_AEAD_AES_128_GCM:
ctx->cipher = EVP_aes_128_gcm();
ctx->n_k = 16;
ctx->n_n = 12;
ctx->n_t = 16;
break;
case HPKE_AEAD_AES_256_GCM:
ctx->cipher = EVP_aes_256_gcm();
ctx->n_k = 32;
ctx->n_n = 12;
ctx->n_t = 16;
break;
default:
goto fail;
}
/* Convert BP-256/384/512 to P-256/384/521 for DPP */
group = crypto_ec_key_group(key);
if (group == 28 && ctx->iana_group == 19) {
ctx->iana_group = 28;
} else if (group == 29 && ctx->iana_group == 20) {
ctx->iana_group = 29;
} else if (group == 30 && ctx->iana_group == 21) {
ctx->iana_group = 30;
ctx->n_pk = 129;
}
if (group != ctx->iana_group) {
wpa_printf(MSG_INFO, "OpenSSL:%s:group mismatch (%d != %d)",
__func__, group, ctx->iana_group);
goto fail;
}
return ctx;
fail:
hpke_free_context(ctx);
return NULL;
}
static size_t hpke_suite_id(struct hpke_context *ctx, bool kem, u8 *suite_id)
{
size_t suite_id_len;
if (kem) {
os_memcpy(suite_id, "KEM", 3);
WPA_PUT_BE16(&suite_id[3], ctx->kem_id);
suite_id_len = 5;
} else {
os_memcpy(suite_id, "HPKE", 4);
WPA_PUT_BE16(&suite_id[4], ctx->kem_id);
WPA_PUT_BE16(&suite_id[6], ctx->kdf_id);
WPA_PUT_BE16(&suite_id[8], ctx->aead_id);
suite_id_len = 10;
}
return suite_id_len;
}
static int hpke_labeled_extract(struct hpke_context *ctx, bool kem,
const u8 *salt, size_t salt_len,
const char *label,
const u8 *ikm, size_t ikm_len, u8 *prk)
{
u8 zero[HPKE_MAX_HASH_LEN];
u8 suite_id[10];
size_t suite_id_len;
unsigned int mdlen = kem ? ctx->kem_n_h : ctx->n_h;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
EVP_MAC *hmac;
OSSL_PARAM params[2];
EVP_MAC_CTX *hctx;
size_t mlen;
int res;
#else /* OpenSSL version >= 3.0 */
HMAC_CTX *hctx;
int res;
#endif /* OpenSSL version >= 3.0 */
if (!salt || !salt_len) {
salt_len = mdlen;
os_memset(zero, 0, salt_len);
salt = zero;
}
suite_id_len = hpke_suite_id(ctx, kem, suite_id);
/* labeled_ikm = concat("HPKE-v1", suite_id, label, ikm)
* return Extract(salt, labeled_ikm) */
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
if (!hmac)
return -1;
params[0] = OSSL_PARAM_construct_utf8_string(
"digest",
(char *) EVP_MD_get0_name(kem ? ctx->kem_h : ctx->kdf_h), 0);
params[1] = OSSL_PARAM_construct_end();
hctx = EVP_MAC_CTX_new(hmac);
EVP_MAC_free(hmac);
if (!hctx)
return -1;
if (EVP_MAC_init(hctx, salt, salt_len, params) != 1)
goto fail;
if (EVP_MAC_update(hctx, (const unsigned char *) "HPKE-v1", 7) != 1 ||
EVP_MAC_update(hctx, suite_id, suite_id_len) != 1 ||
EVP_MAC_update(hctx, (const unsigned char *) label,
os_strlen(label)) != 1 ||
EVP_MAC_update(hctx, ikm, ikm_len) != 1)
goto fail;
res = EVP_MAC_final(hctx, prk, &mlen, mdlen);
EVP_MAC_CTX_free(hctx);
return res == 1 ? 0 : -1;
fail:
EVP_MAC_CTX_free(hctx);
return -1;
#else /* OpenSSL version >= 3.0 */
hctx = HMAC_CTX_new();
if (!hctx)
return -1;
res = HMAC_Init_ex(hctx, salt, salt_len, kem ? ctx->kem_h : ctx->kdf_h,
NULL);
if (res != 1)
goto done;
HMAC_Update(hctx, (const unsigned char *) "HPKE-v1", 7);
HMAC_Update(hctx, suite_id, suite_id_len);
HMAC_Update(hctx, (const unsigned char *) label, os_strlen(label));
HMAC_Update(hctx, ikm, ikm_len);
res = HMAC_Final(hctx, prk, &mdlen);
done:
HMAC_CTX_free(hctx);
return res == 1 ? 0 : -1;
#endif /* OpenSSL version >= 3.0 */
}
static int
hpke_labeled_expand(struct hpke_context *ctx, bool kem, const u8 *prk,
const char *label, const u8 *info, size_t info_len,
u8 *out, size_t out_len)
{
u8 suite_id[10];
size_t suite_id_len;
u8 hash[HPKE_MAX_HASH_LEN];
u8 iter = 0;
size_t label_len = os_strlen(label);
u8 *pos;
size_t left = out_len, clen;
int res = -1;
u8 *labeled_info;
size_t labeled_info_len;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
EVP_MAC *hmac;
OSSL_PARAM params[2];
EVP_MAC_CTX *hctx = NULL;
size_t mdlen;
#else /* OpenSSL version >= 3.0 */
HMAC_CTX *hctx;
unsigned int mdlen;
#endif /* OpenSSL version >= 3.0 */
/* labeled_info = concat(I2OSP(L, 2), "HPKE-v1", suite_id,
* label, info)
* return Expand(prk, labeled_info, L) */
suite_id_len = hpke_suite_id(ctx, kem, suite_id);
labeled_info_len = 2 + 7 + suite_id_len + label_len + info_len;
labeled_info = os_malloc(labeled_info_len);
if (!labeled_info)
return -1;
pos = labeled_info;
WPA_PUT_BE16(pos, out_len);
pos += 2;
os_memcpy(pos, "HPKE-v1", 7);
pos += 7;
os_memcpy(pos, suite_id, suite_id_len);
pos += suite_id_len;
os_memcpy(pos, label, label_len);
pos += label_len;
if (info && info_len) {
os_memcpy(pos, info, info_len);
pos += info_len;
}
pos = out;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
if (!hmac)
return -1;
params[0] = OSSL_PARAM_construct_utf8_string(
"digest",
(char *) EVP_MD_get0_name(kem ? ctx->kem_h : ctx->kdf_h), 0);
params[1] = OSSL_PARAM_construct_end();
#else /* OpenSSL version >= 3.0 */
hctx = HMAC_CTX_new();
if (!hctx)
return -1;
#endif /* OpenSSL version >= 3.0 */
while (left > 0) {
mdlen = kem ? ctx->kem_n_h : ctx->n_h;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
EVP_MAC_CTX_free(hctx);
hctx = EVP_MAC_CTX_new(hmac);
if (!hctx)
return -1;
if (EVP_MAC_init(hctx, prk, mdlen, params) != 1)
goto fail;
if (iter > 0 && EVP_MAC_update(hctx, hash, mdlen) != 1)
goto fail;
if (iter == 255)
goto fail;
iter++;
if (EVP_MAC_update(hctx, labeled_info, labeled_info_len) != 1 ||
EVP_MAC_update(hctx, &iter, sizeof(iter)) != 1)
goto fail;
if (EVP_MAC_final(hctx, hash, &mdlen, mdlen) != 1)
goto fail;
#else /* OpenSSL version >= 3.0 */
if (HMAC_Init_ex(hctx, prk, mdlen,
kem ? ctx->kem_h : ctx->kdf_h,
NULL) != 1)
goto fail;
if (iter > 0)
HMAC_Update(hctx, hash, mdlen);
if (iter == 255)
goto fail;
iter++;
HMAC_Update(hctx, labeled_info, labeled_info_len);
HMAC_Update(hctx, &iter, sizeof(iter));
if (HMAC_Final(hctx, hash, &mdlen) != 1)
goto fail;
HMAC_CTX_reset(hctx);
#endif /* OpenSSL version >= 3.0 */
clen = left > mdlen ? mdlen : left;
os_memcpy(pos, hash, clen);
pos += clen;
left -= clen;
}
res = 0;
fail:
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
EVP_MAC_free(hmac);
EVP_MAC_CTX_free(hctx);
#else /* OpenSSL version >= 3.0 */
HMAC_CTX_free(hctx);
#endif /* OpenSSL version >= 3.0 */
os_free(labeled_info);
return res;
}
static int hpke_extract_and_expand(struct hpke_context *ctx,
const u8 *dhss, size_t dhss_len,
const u8 *enc, size_t enc_len,
const u8 *pk_rm, size_t pk_rm_len,
u8 *shared_secret)
{
u8 kem_context[2 * HPKE_MAX_PUB_LEN];
u8 eae_prk[HPKE_MAX_HASH_LEN];
/* eae_prk = LabeledExtract("", "eae_prk", dh) */
if (hpke_labeled_extract(ctx, true, NULL, 0, "eae_prk", dhss, dhss_len,
eae_prk) < 0)
return -1;
if (enc_len > HPKE_MAX_PUB_LEN || pk_rm_len > HPKE_MAX_PUB_LEN)
return -1;
/* kem_context = concat(enc, pkRm) */
os_memcpy(kem_context, enc, enc_len);
os_memcpy(&kem_context[enc_len], pk_rm, pk_rm_len);
/* shared_secret = LabeledExpand(eae_prk, "shared_secret",
* kem_context, Nsecret) */
if (hpke_labeled_expand(ctx, true, eae_prk, "shared_secret",
kem_context, enc_len + pk_rm_len,
shared_secret, ctx->n_secret) < 0)
return -1;
forced_memzero(eae_prk, sizeof(eae_prk));
return 0;
}
static int hpke_key_schedule(struct hpke_context *ctx, const u8 *shared_secret,
const u8 *info, size_t info_len)
{
u8 key_schedule_context[1 + 2 * HPKE_MAX_HASH_LEN];
u8 secret[HPKE_MAX_HASH_LEN];
int res = -1;
/* key_schedule_context = concat(mode, psk_id_hash, info_hash) */
key_schedule_context[0] = HPKE_MODE_BASE;
/* psk_id_hash = LabeledExtract("", "psk_id_hash", psk_id) */
if (hpke_labeled_extract(ctx, false, NULL, 0, "psk_id_hash",
NULL, 0, &key_schedule_context[1]) < 0)
goto fail;
/* info_hash = LabeledExtract("", "info_hash", info) */
if (hpke_labeled_extract(ctx, false, NULL, 0, "info_hash",
info, info_len,
&key_schedule_context[1 + ctx->n_h]) < 0)
goto fail;
/* secret = LabeledExtract(shared_secret, "secret", psk) */
if (hpke_labeled_extract(ctx, false, shared_secret, ctx->n_secret,
"secret", NULL, 0, secret) < 0)
goto fail;
/* key = LabeledExpand(secret, "key", key_schedule_context, Nk) */
if (hpke_labeled_expand(ctx, false, secret, "key",
key_schedule_context, 1 + 2 * ctx->n_h,
ctx->key, ctx->n_k) < 0)
goto fail;
/* base_nonce = LabeledExpand(secret, "base_nonce",
* key_schedule_context, Nn) */
if (hpke_labeled_expand(ctx, false, secret, "base_nonce",
key_schedule_context, 1 + 2 * ctx->n_h,
ctx->base_nonce, ctx->n_n) < 0)
goto fail;
res = 0;
fail:
forced_memzero(key_schedule_context, sizeof(key_schedule_context));
forced_memzero(secret, sizeof(secret));
return res;
}
static int hpke_encap(struct hpke_context *ctx, struct crypto_ec_key *pk_r,
u8 *shared_secret, u8 *enc)
{
EVP_PKEY_CTX *pctx = NULL;
struct crypto_ec_key *sk_e;
int res = -1;
u8 dhss[HPKE_MAX_SHARED_SECRET_LEN];
size_t dhss_len;
struct wpabuf *enc_buf = NULL, *pk_rm = NULL;
/* skE, pkE = GenerateKeyPair() */
sk_e = crypto_ec_key_gen(ctx->iana_group);
if (!sk_e) {
wpa_printf(MSG_INFO, "OpenSSL:%s:Could not generate key pair",
__func__);
goto fail;
}
/* dh = DH(skE, pkR) */
pctx = EVP_PKEY_CTX_new((EVP_PKEY *) sk_e, NULL);
if (!pctx ||
EVP_PKEY_derive_init(pctx) != 1 ||
EVP_PKEY_derive_set_peer(pctx, (EVP_PKEY *) pk_r) != 1 ||
EVP_PKEY_derive(pctx, NULL, &dhss_len) != 1 ||
dhss_len > HPKE_MAX_SHARED_SECRET_LEN ||
EVP_PKEY_derive(pctx, dhss, &dhss_len) != 1) {
wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
/* enc = SerializePublicKey(pkE) */
enc_buf = crypto_ec_key_get_pubkey_point(sk_e, 1);
if (!enc_buf)
goto fail;
os_memcpy(enc, wpabuf_head(enc_buf), wpabuf_len(enc_buf));
/* pkRm = SerializePublicKey(pkR) */
pk_rm = crypto_ec_key_get_pubkey_point(pk_r, 1);
if (!pk_rm)
goto fail;
/* kem_context = concat(enc, pkRm) */
/* shared_secret = ExtractAndExpand(dh, kem_context) */
/* return shared_secret, enc */
res = hpke_extract_and_expand(ctx, dhss, dhss_len, enc, ctx->n_pk,
wpabuf_head(pk_rm),
wpabuf_len(pk_rm), shared_secret);
fail:
forced_memzero(dhss, sizeof(dhss));
crypto_ec_key_deinit(sk_e);
EVP_PKEY_CTX_free(pctx);
wpabuf_free(enc_buf);
wpabuf_free(pk_rm);
return res;
}
static struct wpabuf *
hpke_aead_seal(struct hpke_context *ctx, const u8 *aad, size_t aad_len,
const u8 *pt, size_t pt_len)
{
EVP_CIPHER_CTX *cctx;
int len = 0;
struct wpabuf *ct = NULL;
/* No need to xor in sequence number since we support only the
* single-shot API, i.e., base_nonce can be used as-is. */
cctx = EVP_CIPHER_CTX_new();
if (!cctx ||
EVP_EncryptInit_ex(cctx, ctx->cipher, NULL, ctx->key,
ctx->base_nonce) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptInit_ex failed",
__func__);
goto fail;
}
if (aad && aad_len &&
EVP_EncryptUpdate(cctx, NULL, &len, aad, aad_len) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_EncryptUpdate(AAD) failed",
__func__);
goto fail;
}
ct = wpabuf_alloc(pt_len + AES_BLOCK_SIZE + ctx->n_t);
if (!ct)
goto fail;
if (EVP_EncryptUpdate(cctx, wpabuf_put(ct, 0), &len, pt, pt_len) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_EncryptUpdate failed",
__func__);
goto fail;
}
wpabuf_put(ct, len);
if (EVP_EncryptFinal(cctx, wpabuf_put(ct, 0), &len) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptFinal failed",
__func__);
wpabuf_free(ct);
ct = NULL;
goto fail;
}
if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG, ctx->n_t,
wpabuf_put(ct, ctx->n_t)) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:Could not get tag",
__func__);
wpabuf_free(ct);
ct = NULL;
goto fail;
}
fail:
EVP_CIPHER_CTX_free(cctx);
return ct;
}
struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id,
enum hpke_kdf_id kdf_id,
enum hpke_aead_id aead_id,
struct crypto_ec_key *peer_pub,
const u8 *info, size_t info_len,
const u8 *aad, size_t aad_len,
const u8 *pt, size_t pt_len)
{
struct hpke_context *ctx;
u8 shared_secret[HPKE_MAX_SHARED_SECRET_LEN];
u8 enc[1 + 2 * HPKE_MAX_PUB_LEN];
struct wpabuf *ct = NULL, *enc_ct = NULL;
ctx = hpke_get_context(kem_id, kdf_id, aead_id, peer_pub);
if (!ctx)
return NULL;
/* shared_secret, enc = Encap(pkR) */
if (hpke_encap(ctx, peer_pub, shared_secret, enc) < 0)
goto fail;
/* KeyScheduleS(mode_base, shared_secret, info,
* default_psk, default_psk_id) */
if (hpke_key_schedule(ctx, shared_secret, info, info_len) < 0)
goto fail;
/* ct = ctx.Seal(aad, pt) */
ct = hpke_aead_seal(ctx, aad, aad_len, pt, pt_len);
if (!ct)
goto fail;
/* return enc, ct */
enc_ct = wpabuf_alloc(ctx->n_pk + wpabuf_len(ct));
if (!enc_ct)
goto fail;
wpabuf_put_data(enc_ct, enc, ctx->n_pk);
wpabuf_put_buf(enc_ct, ct);
fail:
forced_memzero(shared_secret, sizeof(shared_secret));
hpke_free_context(ctx);
wpabuf_free(ct);
return enc_ct;
}
static int hpke_decap(struct hpke_context *ctx, const u8 *enc,
size_t enc_ct_len, struct crypto_ec_key *sk_r,
u8 *shared_secret)
{
EVP_PKEY_CTX *pctx = NULL;
struct wpabuf *pk_rm = NULL;
size_t len;
int res = -1;
struct crypto_ec_key *pk_e = NULL;
u8 dhss[HPKE_MAX_SHARED_SECRET_LEN];
size_t dhss_len;
/* pkE = DeserializePublicKey(enc) */
if (enc_ct_len < ctx->n_pk)
return -1; /* not enough room for enc */
if (enc[0] != 0x04)
return -1; /* not in uncompressed form */
len = (ctx->n_pk - 1) / 2;
pk_e = crypto_ec_key_set_pub(ctx->iana_group, &enc[1],
&enc[1 + len], len);
if (!pk_e)
return -1; /* invalid public key point */
/* dh = DH(skR, pkE) */
pctx = EVP_PKEY_CTX_new((EVP_PKEY *) sk_r, NULL);
if (!pctx ||
EVP_PKEY_derive_init(pctx) != 1 ||
EVP_PKEY_derive_set_peer(pctx, (EVP_PKEY *) pk_e) != 1 ||
EVP_PKEY_derive(pctx, NULL, &dhss_len) != 1 ||
dhss_len > HPKE_MAX_SHARED_SECRET_LEN ||
EVP_PKEY_derive(pctx, dhss, &dhss_len) != 1) {
wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
/* pkRm = SerializePublicKey(pk(skR)) */
pk_rm = crypto_ec_key_get_pubkey_point(sk_r, 1);
if (!pk_rm)
goto fail;
/* kem_context = concat(enc, pkRm) */
/* shared_secret = ExtractAndExpand(dh, kem_context) */
res = hpke_extract_and_expand(ctx, dhss, dhss_len, enc, ctx->n_pk,
wpabuf_head(pk_rm),
wpabuf_len(pk_rm), shared_secret);
fail:
forced_memzero(dhss, sizeof(dhss));
crypto_ec_key_deinit(pk_e);
EVP_PKEY_CTX_free(pctx);
wpabuf_free(pk_rm);
return res;
}
static struct wpabuf *
hpke_aead_open(struct hpke_context *ctx, const u8 *aad, size_t aad_len,
const u8 *ct, size_t ct_len)
{
EVP_CIPHER_CTX *cctx;
int len = 0;
const u8 *tag;
struct wpabuf *pt = NULL;
if (ct_len < ctx->n_t)
return NULL;
tag = ct + ct_len - ctx->n_t;
ct_len -= ctx->n_t;
/* No need to xor in sequence number since we support only the
* single-shot API, i.e., base_nonce can be used as-is. */
cctx = EVP_CIPHER_CTX_new();
if (!cctx ||
EVP_DecryptInit_ex(cctx, ctx->cipher, NULL, ctx->key,
ctx->base_nonce) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptInit_ex failed",
__func__);
goto fail;
}
if (aad && aad_len &&
EVP_DecryptUpdate(cctx, NULL, &len, aad, aad_len) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptUpdate(AAD) failed",
__func__);
goto fail;
}
pt = wpabuf_alloc(ct_len + AES_BLOCK_SIZE);
if (!pt)
goto fail;
if (EVP_DecryptUpdate(cctx, wpabuf_put(pt, 0), &len, ct, ct_len) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptUpdate failed",
__func__);
goto fail;
}
wpabuf_put(pt, len);
if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_SET_TAG, ctx->n_t,
(void *) tag) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:Could not set tag",
__func__);
wpabuf_free(pt);
pt = NULL;
goto fail;
}
if (EVP_DecryptFinal(cctx, wpabuf_put(pt, 0), &len) != 1) {
wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptFinal failed",
__func__);
wpabuf_free(pt);
pt = NULL;
}
fail:
EVP_CIPHER_CTX_free(cctx);
return pt;
}
struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id,
enum hpke_kdf_id kdf_id,
enum hpke_aead_id aead_id,
struct crypto_ec_key *own_priv,
const u8 *info, size_t info_len,
const u8 *aad, size_t aad_len,
const u8 *enc_ct, size_t enc_ct_len)
{
struct hpke_context *ctx;
u8 shared_secret[HPKE_MAX_SHARED_SECRET_LEN];
struct wpabuf *pt = NULL;
ctx = hpke_get_context(kem_id, kdf_id, aead_id, own_priv);
if (!ctx)
return NULL;
/* shared_secret = Decap(enc, skR) */
if (hpke_decap(ctx, enc_ct, enc_ct_len, own_priv, shared_secret) < 0)
goto fail;
/* KeyScheduleR(mode_base, shared_secret, info,
* default_psk, default_psk_id) */
if (hpke_key_schedule(ctx, shared_secret, info, info_len) < 0)
goto fail;
/* return ctx.Open(aad, ct) */
pt = hpke_aead_open(ctx, aad, aad_len,
&enc_ct[ctx->n_pk], enc_ct_len - ctx->n_pk);
fail:
forced_memzero(shared_secret, sizeof(shared_secret));
hpke_free_context(ctx);
return pt;
}
#endif /* CONFIG_DPP3 */
void crypto_unload(void) void crypto_unload(void)
{ {
openssl_unload_legacy_provider(); openssl_unload_legacy_provider();