ecx_kem.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. /*
  2. * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. /*
  10. * The following implementation is part of RFC 9180 related to DHKEM using
  11. * ECX keys (i.e. X25519 and X448)
  12. * References to Sections in the comments below refer to RFC 9180.
  13. */
  14. #include "internal/deprecated.h"
  15. #include <string.h>
  16. #include <openssl/crypto.h>
  17. #include <openssl/evp.h>
  18. #include <openssl/core_dispatch.h>
  19. #include <openssl/core_names.h>
  20. #include <openssl/params.h>
  21. #include <openssl/kdf.h>
  22. #include <openssl/err.h>
  23. #include <openssl/sha.h>
  24. #include <openssl/rand.h>
  25. #include <openssl/proverr.h>
  26. #include "prov/provider_ctx.h"
  27. #include "prov/implementations.h"
  28. #include "prov/securitycheck.h"
  29. #include "prov/providercommon.h"
  30. #include "prov/ecx.h"
  31. #include "crypto/ecx.h"
  32. #include <openssl/hpke.h>
  33. #include "internal/hpke_util.h"
  34. #include "eckem.h"
  35. #define MAX_ECX_KEYLEN X448_KEYLEN
  36. /* KEM identifiers from Section 7.1 "Table 2 KEM IDs" */
  37. #define KEMID_X25519_HKDF_SHA256 0x20
  38. #define KEMID_X448_HKDF_SHA512 0x21
  39. /* ASCII: "KEM", in hex for EBCDIC compatibility */
  40. static const char LABEL_KEM[] = "\x4b\x45\x4d";
  41. typedef struct {
  42. ECX_KEY *recipient_key;
  43. ECX_KEY *sender_authkey;
  44. OSSL_LIB_CTX *libctx;
  45. char *propq;
  46. unsigned int mode;
  47. unsigned int op;
  48. unsigned char *ikm;
  49. size_t ikmlen;
  50. const char *kdfname;
  51. const OSSL_HPKE_KEM_INFO *info;
  52. } PROV_ECX_CTX;
  53. static OSSL_FUNC_kem_newctx_fn ecxkem_newctx;
  54. static OSSL_FUNC_kem_encapsulate_init_fn ecxkem_encapsulate_init;
  55. static OSSL_FUNC_kem_encapsulate_fn ecxkem_encapsulate;
  56. static OSSL_FUNC_kem_decapsulate_init_fn ecxkem_decapsulate_init;
  57. static OSSL_FUNC_kem_decapsulate_fn ecxkem_decapsulate;
  58. static OSSL_FUNC_kem_freectx_fn ecxkem_freectx;
  59. static OSSL_FUNC_kem_set_ctx_params_fn ecxkem_set_ctx_params;
  60. static OSSL_FUNC_kem_auth_encapsulate_init_fn ecxkem_auth_encapsulate_init;
  61. static OSSL_FUNC_kem_auth_decapsulate_init_fn ecxkem_auth_decapsulate_init;
  62. /*
  63. * Set KEM values as specified in Section 7.1 "Table 2 KEM IDs"
  64. * There is only one set of values for X25519 and X448.
  65. * Additional values could be set via set_params if required.
  66. */
  67. static const OSSL_HPKE_KEM_INFO *get_kem_info(ECX_KEY *ecx)
  68. {
  69. const char *name = NULL;
  70. if (ecx->type == ECX_KEY_TYPE_X25519)
  71. name = SN_X25519;
  72. else
  73. name = SN_X448;
  74. return ossl_HPKE_KEM_INFO_find_curve(name);
  75. }
  76. /*
  77. * Set the recipient key, and free any existing key.
  78. * ecx can be NULL. The ecx key may have only a private or public component.
  79. */
  80. static int recipient_key_set(PROV_ECX_CTX *ctx, ECX_KEY *ecx)
  81. {
  82. ossl_ecx_key_free(ctx->recipient_key);
  83. ctx->recipient_key = NULL;
  84. if (ecx != NULL) {
  85. ctx->info = get_kem_info(ecx);
  86. if (ctx->info == NULL)
  87. return -2;
  88. ctx->kdfname = "HKDF";
  89. if (!ossl_ecx_key_up_ref(ecx))
  90. return 0;
  91. ctx->recipient_key = ecx;
  92. }
  93. return 1;
  94. }
  95. /*
  96. * Set the senders auth key, and free any existing auth key.
  97. * ecx can be NULL.
  98. */
  99. static int sender_authkey_set(PROV_ECX_CTX *ctx, ECX_KEY *ecx)
  100. {
  101. ossl_ecx_key_free(ctx->sender_authkey);
  102. ctx->sender_authkey = NULL;
  103. if (ecx != NULL) {
  104. if (!ossl_ecx_key_up_ref(ecx))
  105. return 0;
  106. ctx->sender_authkey = ecx;
  107. }
  108. return 1;
  109. }
  110. /*
  111. * Serialize a public key from byte array's for the encoded public keys.
  112. * ctx is used to access the key type.
  113. * Returns: The created ECX_KEY or NULL on error.
  114. */
  115. static ECX_KEY *ecxkey_pubfromdata(PROV_ECX_CTX *ctx,
  116. const unsigned char *pubbuf, size_t pubbuflen)
  117. {
  118. ECX_KEY *ecx = NULL;
  119. OSSL_PARAM params[2], *p = params;
  120. *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
  121. (char *)pubbuf, pubbuflen);
  122. *p = OSSL_PARAM_construct_end();
  123. ecx = ossl_ecx_key_new(ctx->libctx, ctx->recipient_key->type, 1, ctx->propq);
  124. if (ecx == NULL)
  125. return NULL;
  126. if (ossl_ecx_key_fromdata(ecx, params, 0) <= 0) {
  127. ossl_ecx_key_free(ecx);
  128. ecx = NULL;
  129. }
  130. return ecx;
  131. }
  132. static unsigned char *ecx_pubkey(ECX_KEY *ecx)
  133. {
  134. if (ecx == NULL || !ecx->haspubkey) {
  135. ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY);
  136. return 0;
  137. }
  138. return ecx->pubkey;
  139. }
  140. static void *ecxkem_newctx(void *provctx)
  141. {
  142. PROV_ECX_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_ECX_CTX));
  143. if (ctx == NULL)
  144. return NULL;
  145. ctx->libctx = PROV_LIBCTX_OF(provctx);
  146. return ctx;
  147. }
  148. static void ecxkem_freectx(void *vectx)
  149. {
  150. PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vectx;
  151. OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
  152. recipient_key_set(ctx, NULL);
  153. sender_authkey_set(ctx, NULL);
  154. OPENSSL_free(ctx);
  155. }
  156. static int ecx_match_params(const ECX_KEY *key1, const ECX_KEY *key2)
  157. {
  158. return (key1->type == key2->type && key1->keylen == key2->keylen);
  159. }
  160. static int ecx_key_check(const ECX_KEY *ecx, int requires_privatekey)
  161. {
  162. if (ecx->privkey == NULL)
  163. return (requires_privatekey == 0);
  164. return 1;
  165. }
  166. static int ecxkem_init(void *vecxctx, int operation, void *vecx, void *vauth,
  167. ossl_unused const OSSL_PARAM params[])
  168. {
  169. int rv;
  170. PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vecxctx;
  171. ECX_KEY *ecx = vecx;
  172. ECX_KEY *auth = vauth;
  173. if (!ossl_prov_is_running())
  174. return 0;
  175. if (!ecx_key_check(ecx, operation == EVP_PKEY_OP_DECAPSULATE))
  176. return 0;
  177. rv = recipient_key_set(ctx, ecx);
  178. if (rv <= 0)
  179. return rv;
  180. if (auth != NULL) {
  181. if (!ecx_match_params(auth, ctx->recipient_key)
  182. || !ecx_key_check(auth, operation == EVP_PKEY_OP_ENCAPSULATE)
  183. || !sender_authkey_set(ctx, auth))
  184. return 0;
  185. }
  186. ctx->op = operation;
  187. return ecxkem_set_ctx_params(vecxctx, params);
  188. }
  189. static int ecxkem_encapsulate_init(void *vecxctx, void *vecx,
  190. const OSSL_PARAM params[])
  191. {
  192. return ecxkem_init(vecxctx, EVP_PKEY_OP_ENCAPSULATE, vecx, NULL, params);
  193. }
  194. static int ecxkem_decapsulate_init(void *vecxctx, void *vecx,
  195. const OSSL_PARAM params[])
  196. {
  197. return ecxkem_init(vecxctx, EVP_PKEY_OP_DECAPSULATE, vecx, NULL, params);
  198. }
  199. static int ecxkem_auth_encapsulate_init(void *vctx, void *vecx, void *vauthpriv,
  200. const OSSL_PARAM params[])
  201. {
  202. return ecxkem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vecx, vauthpriv, params);
  203. }
  204. static int ecxkem_auth_decapsulate_init(void *vctx, void *vecx, void *vauthpub,
  205. const OSSL_PARAM params[])
  206. {
  207. return ecxkem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vecx, vauthpub, params);
  208. }
  209. static int ecxkem_set_ctx_params(void *vctx, const OSSL_PARAM params[])
  210. {
  211. PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
  212. const OSSL_PARAM *p;
  213. int mode;
  214. if (ctx == NULL)
  215. return 0;
  216. if (params == NULL)
  217. return 1;
  218. p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_IKME);
  219. if (p != NULL) {
  220. void *tmp = NULL;
  221. size_t tmplen = 0;
  222. if (p->data != NULL && p->data_size != 0) {
  223. if (!OSSL_PARAM_get_octet_string(p, &tmp, 0, &tmplen))
  224. return 0;
  225. }
  226. OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
  227. ctx->ikm = tmp;
  228. ctx->ikmlen = tmplen;
  229. }
  230. p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION);
  231. if (p != NULL) {
  232. if (p->data_type != OSSL_PARAM_UTF8_STRING)
  233. return 0;
  234. mode = ossl_eckem_modename2id(p->data);
  235. if (mode == KEM_MODE_UNDEFINED)
  236. return 0;
  237. ctx->mode = mode;
  238. }
  239. return 1;
  240. }
  241. static const OSSL_PARAM known_settable_ecxkem_ctx_params[] = {
  242. OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0),
  243. OSSL_PARAM_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0),
  244. OSSL_PARAM_END
  245. };
  246. static const OSSL_PARAM *ecxkem_settable_ctx_params(ossl_unused void *vctx,
  247. ossl_unused void *provctx)
  248. {
  249. return known_settable_ecxkem_ctx_params;
  250. }
  251. /*
  252. * See Section 4.1 DH-Based KEM (DHKEM) ExtractAndExpand
  253. */
  254. static int dhkem_extract_and_expand(EVP_KDF_CTX *kctx,
  255. unsigned char *okm, size_t okmlen,
  256. uint16_t kemid,
  257. const unsigned char *dhkm, size_t dhkmlen,
  258. const unsigned char *kemctx,
  259. size_t kemctxlen)
  260. {
  261. uint8_t suiteid[2];
  262. uint8_t prk[EVP_MAX_MD_SIZE];
  263. size_t prklen = okmlen; /* Nh */
  264. int ret;
  265. if (prklen > sizeof(prk))
  266. return 0;
  267. suiteid[0] = (kemid >> 8) &0xff;
  268. suiteid[1] = kemid & 0xff;
  269. ret = ossl_hpke_labeled_extract(kctx, prk, prklen,
  270. NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
  271. OSSL_DHKEM_LABEL_EAE_PRK, dhkm, dhkmlen)
  272. && ossl_hpke_labeled_expand(kctx, okm, okmlen, prk, prklen,
  273. LABEL_KEM, suiteid, sizeof(suiteid),
  274. OSSL_DHKEM_LABEL_SHARED_SECRET,
  275. kemctx, kemctxlen);
  276. OPENSSL_cleanse(prk, prklen);
  277. return ret;
  278. }
  279. /*
  280. * See Section 7.1.3 DeriveKeyPair.
  281. *
  282. * This function is used by ecx keygen.
  283. * (For this reason it does not use any of the state stored in PROV_ECX_CTX).
  284. *
  285. * Params:
  286. * ecx An initialized ecx key.
  287. * privout The buffer to store the generated private key into (it is assumed
  288. * this is of length ecx->keylen).
  289. * ikm buffer containing the input key material (seed). This must be non NULL.
  290. * ikmlen size of the ikm buffer in bytes
  291. * Returns:
  292. * 1 if successful or 0 otherwise.
  293. */
  294. int ossl_ecx_dhkem_derive_private(ECX_KEY *ecx, unsigned char *privout,
  295. const unsigned char *ikm, size_t ikmlen)
  296. {
  297. int ret = 0;
  298. EVP_KDF_CTX *kdfctx = NULL;
  299. unsigned char prk[EVP_MAX_MD_SIZE];
  300. uint8_t suiteid[2];
  301. const OSSL_HPKE_KEM_INFO *info = get_kem_info(ecx);
  302. /* ikmlen should have a length of at least Nsk */
  303. if (ikmlen < info->Nsk) {
  304. ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH,
  305. "ikm length is :%zu, should be at least %zu",
  306. ikmlen, info->Nsk);
  307. goto err;
  308. }
  309. kdfctx = ossl_kdf_ctx_create("HKDF", info->mdname, ecx->libctx, ecx->propq);
  310. if (kdfctx == NULL)
  311. return 0;
  312. suiteid[0] = info->kem_id / 256;
  313. suiteid[1] = info->kem_id % 256;
  314. if (!ossl_hpke_labeled_extract(kdfctx, prk, info->Nsecret,
  315. NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
  316. OSSL_DHKEM_LABEL_DKP_PRK, ikm, ikmlen))
  317. goto err;
  318. if (!ossl_hpke_labeled_expand(kdfctx, privout, info->Nsk, prk, info->Nsecret,
  319. LABEL_KEM, suiteid, sizeof(suiteid),
  320. OSSL_DHKEM_LABEL_SK, NULL, 0))
  321. goto err;
  322. ret = 1;
  323. err:
  324. OPENSSL_cleanse(prk, sizeof(prk));
  325. EVP_KDF_CTX_free(kdfctx);
  326. return ret;
  327. }
  328. /*
  329. * Do a keygen operation without having to use EVP_PKEY.
  330. * Params:
  331. * ctx Context object
  332. * ikm The seed material - if this is NULL, then a random seed is used.
  333. * Returns:
  334. * The generated ECX key, or NULL on failure.
  335. */
  336. static ECX_KEY *derivekey(PROV_ECX_CTX *ctx,
  337. const unsigned char *ikm, size_t ikmlen)
  338. {
  339. int ok = 0;
  340. ECX_KEY *key;
  341. unsigned char *privkey;
  342. unsigned char *seed = (unsigned char *)ikm;
  343. size_t seedlen = ikmlen;
  344. unsigned char tmpbuf[OSSL_HPKE_MAX_PRIVATE];
  345. const OSSL_HPKE_KEM_INFO *info = ctx->info;
  346. key = ossl_ecx_key_new(ctx->libctx, ctx->recipient_key->type, 0, ctx->propq);
  347. if (key == NULL)
  348. return NULL;
  349. privkey = ossl_ecx_key_allocate_privkey(key);
  350. if (privkey == NULL)
  351. goto err;
  352. /* Generate a random seed if there is no input ikm */
  353. if (seed == NULL || seedlen == 0) {
  354. if (info->Nsk > sizeof(tmpbuf))
  355. goto err;
  356. if (RAND_priv_bytes_ex(ctx->libctx, tmpbuf, info->Nsk, 0) <= 0)
  357. goto err;
  358. seed = tmpbuf;
  359. seedlen = info->Nsk;
  360. }
  361. if (!ossl_ecx_dhkem_derive_private(key, privkey, seed, seedlen))
  362. goto err;
  363. if (!ossl_ecx_public_from_private(key))
  364. goto err;
  365. key->haspubkey = 1;
  366. ok = 1;
  367. err:
  368. if (!ok) {
  369. ossl_ecx_key_free(key);
  370. key = NULL;
  371. }
  372. if (seed != ikm)
  373. OPENSSL_cleanse(seed, seedlen);
  374. return key;
  375. }
  376. /*
  377. * Do an ecxdh key exchange.
  378. * dhkm = DH(sender, peer)
  379. *
  380. * NOTE: Instead of using EVP_PKEY_derive() API's, we use ECX_KEY operations
  381. * to avoid messy conversions back to EVP_PKEY.
  382. *
  383. * Returns the size of the secret if successful, or 0 otherwise,
  384. */
  385. static int generate_ecxdhkm(const ECX_KEY *sender, const ECX_KEY *peer,
  386. unsigned char *out, size_t maxout,
  387. unsigned int secretsz)
  388. {
  389. size_t len = 0;
  390. /* NOTE: ossl_ecx_compute_key checks for shared secret being all zeros */
  391. return ossl_ecx_compute_key((ECX_KEY *)peer, (ECX_KEY *)sender,
  392. sender->keylen, out, &len, maxout);
  393. }
  394. /*
  395. * Derive a secret using ECXDH (code is shared by the encap and decap)
  396. *
  397. * dhkm = Concat(ecxdh(privkey1, peerkey1), ecdh(privkey2, peerkey2)
  398. * kemctx = Concat(sender_pub, recipient_pub, ctx->sender_authkey)
  399. * secret = dhkem_extract_and_expand(kemid, dhkm, kemctx);
  400. *
  401. * Params:
  402. * ctx Object that contains algorithm state and constants.
  403. * secret The returned secret (with a length ctx->alg->secretlen bytes).
  404. * privkey1 A private key used for ECXDH key derivation.
  405. * peerkey1 A public key used for ECXDH key derivation with privkey1
  406. * privkey2 A optional private key used for a second ECXDH key derivation.
  407. * It can be NULL.
  408. * peerkey2 A optional public key used for a second ECXDH key derivation
  409. * with privkey2,. It can be NULL.
  410. * sender_pub The senders public key in encoded form.
  411. * recipient_pub The recipients public key in encoded form.
  412. * Notes:
  413. * The second ecdh() is only used for the HPKE auth modes when both privkey2
  414. * and peerkey2 are non NULL (i.e. ctx->sender_authkey is not NULL).
  415. */
  416. static int derive_secret(PROV_ECX_CTX *ctx, unsigned char *secret,
  417. const ECX_KEY *privkey1, const ECX_KEY *peerkey1,
  418. const ECX_KEY *privkey2, const ECX_KEY *peerkey2,
  419. const unsigned char *sender_pub,
  420. const unsigned char *recipient_pub)
  421. {
  422. int ret = 0;
  423. EVP_KDF_CTX *kdfctx = NULL;
  424. unsigned char *sender_authpub = NULL;
  425. unsigned char dhkm[MAX_ECX_KEYLEN * 2];
  426. unsigned char kemctx[MAX_ECX_KEYLEN * 3];
  427. size_t kemctxlen = 0, dhkmlen = 0;
  428. const OSSL_HPKE_KEM_INFO *info = ctx->info;
  429. int auth = ctx->sender_authkey != NULL;
  430. size_t encodedkeylen = info->Npk;
  431. if (!generate_ecxdhkm(privkey1, peerkey1, dhkm, sizeof(dhkm), encodedkeylen))
  432. goto err;
  433. dhkmlen = encodedkeylen;
  434. /* Concat the optional second ECXDH (used for Auth) */
  435. if (auth) {
  436. if (!generate_ecxdhkm(privkey2, peerkey2,
  437. dhkm + dhkmlen, sizeof(dhkm) - dhkmlen,
  438. encodedkeylen))
  439. goto err;
  440. /* Get the public key of the auth sender in encoded form */
  441. sender_authpub = ecx_pubkey(ctx->sender_authkey);
  442. if (sender_authpub == NULL)
  443. goto err;
  444. dhkmlen += encodedkeylen;
  445. }
  446. kemctxlen = encodedkeylen + dhkmlen;
  447. if (kemctxlen > sizeof(kemctx))
  448. goto err;
  449. /* kemctx is the concat of both sides encoded public key */
  450. memcpy(kemctx, sender_pub, encodedkeylen);
  451. memcpy(kemctx + encodedkeylen, recipient_pub, encodedkeylen);
  452. if (auth)
  453. memcpy(kemctx + 2 * encodedkeylen, sender_authpub, encodedkeylen);
  454. kdfctx = ossl_kdf_ctx_create(ctx->kdfname, info->mdname,
  455. ctx->libctx, ctx->propq);
  456. if (kdfctx == NULL)
  457. goto err;
  458. if (!dhkem_extract_and_expand(kdfctx, secret, info->Nsecret,
  459. info->kem_id, dhkm, dhkmlen,
  460. kemctx, kemctxlen))
  461. goto err;
  462. ret = 1;
  463. err:
  464. OPENSSL_cleanse(dhkm, dhkmlen);
  465. EVP_KDF_CTX_free(kdfctx);
  466. return ret;
  467. }
  468. /*
  469. * Do a DHKEM encapsulate operation.
  470. *
  471. * See Section 4.1 Encap() and AuthEncap()
  472. *
  473. * Params:
  474. * ctx A context object holding the recipients public key and the
  475. * optional senders auth private key.
  476. * enc A buffer to return the senders ephemeral public key.
  477. * Setting this to NULL allows the enclen and secretlen to return
  478. * values, without calculating the secret.
  479. * enclen Passes in the max size of the enc buffer and returns the
  480. * encoded public key length.
  481. * secret A buffer to return the calculated shared secret.
  482. * secretlen Passes in the max size of the secret buffer and returns the
  483. * secret length.
  484. * Returns: 1 on success or 0 otherwise.
  485. */
  486. static int dhkem_encap(PROV_ECX_CTX *ctx,
  487. unsigned char *enc, size_t *enclen,
  488. unsigned char *secret, size_t *secretlen)
  489. {
  490. int ret = 0;
  491. ECX_KEY *sender_ephemkey = NULL;
  492. unsigned char *sender_ephempub, *recipient_pub;
  493. const OSSL_HPKE_KEM_INFO *info = ctx->info;
  494. if (enc == NULL) {
  495. if (enclen == NULL && secretlen == NULL)
  496. return 0;
  497. if (enclen != NULL)
  498. *enclen = info->Nenc;
  499. if (secretlen != NULL)
  500. *secretlen = info->Nsecret;
  501. return 1;
  502. }
  503. if (*secretlen < info->Nsecret) {
  504. ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
  505. return 0;
  506. }
  507. if (*enclen < info->Nenc) {
  508. ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*enclen too small");
  509. return 0;
  510. }
  511. /* Create an ephemeral key */
  512. sender_ephemkey = derivekey(ctx, ctx->ikm, ctx->ikmlen);
  513. sender_ephempub = ecx_pubkey(sender_ephemkey);
  514. recipient_pub = ecx_pubkey(ctx->recipient_key);
  515. if (sender_ephempub == NULL || recipient_pub == NULL)
  516. goto err;
  517. if (!derive_secret(ctx, secret,
  518. sender_ephemkey, ctx->recipient_key,
  519. ctx->sender_authkey, ctx->recipient_key,
  520. sender_ephempub, recipient_pub))
  521. goto err;
  522. /* Return the public part of the ephemeral key */
  523. memcpy(enc, sender_ephempub, info->Nenc);
  524. *enclen = info->Nenc;
  525. *secretlen = info->Nsecret;
  526. ret = 1;
  527. err:
  528. ossl_ecx_key_free(sender_ephemkey);
  529. return ret;
  530. }
  531. /*
  532. * Do a DHKEM decapsulate operation.
  533. * See Section 4.1 Decap() and Auth Decap()
  534. *
  535. * Params:
  536. * ctx A context object holding the recipients private key and the
  537. * optional senders auth public key.
  538. * secret A buffer to return the calculated shared secret. Setting this to
  539. * NULL can be used to return the secretlen.
  540. * secretlen Passes in the max size of the secret buffer and returns the
  541. * secret length.
  542. * enc A buffer containing the senders ephemeral public key that was returned
  543. * from dhkem_encap().
  544. * enclen The length in bytes of enc.
  545. * Returns: 1 If the shared secret is returned or 0 on error.
  546. */
  547. static int dhkem_decap(PROV_ECX_CTX *ctx,
  548. unsigned char *secret, size_t *secretlen,
  549. const unsigned char *enc, size_t enclen)
  550. {
  551. int ret = 0;
  552. ECX_KEY *recipient_privkey = ctx->recipient_key;
  553. ECX_KEY *sender_ephempubkey = NULL;
  554. const OSSL_HPKE_KEM_INFO *info = ctx->info;
  555. unsigned char *recipient_pub;
  556. if (secret == NULL) {
  557. *secretlen = info->Nsecret;
  558. return 1;
  559. }
  560. if (*secretlen < info->Nsecret) {
  561. ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
  562. return 0;
  563. }
  564. if (enclen != info->Nenc) {
  565. ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid enc public key");
  566. return 0;
  567. }
  568. /* Get the public part of the ephemeral key created by encap */
  569. sender_ephempubkey = ecxkey_pubfromdata(ctx, enc, enclen);
  570. if (sender_ephempubkey == NULL)
  571. goto err;
  572. recipient_pub = ecx_pubkey(recipient_privkey);
  573. if (recipient_pub == NULL)
  574. goto err;
  575. if (!derive_secret(ctx, secret,
  576. ctx->recipient_key, sender_ephempubkey,
  577. ctx->recipient_key, ctx->sender_authkey,
  578. enc, recipient_pub))
  579. goto err;
  580. *secretlen = info->Nsecret;
  581. ret = 1;
  582. err:
  583. ossl_ecx_key_free(sender_ephempubkey);
  584. return ret;
  585. }
  586. static int ecxkem_encapsulate(void *vctx, unsigned char *out, size_t *outlen,
  587. unsigned char *secret, size_t *secretlen)
  588. {
  589. PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
  590. switch (ctx->mode) {
  591. case KEM_MODE_DHKEM:
  592. return dhkem_encap(ctx, out, outlen, secret, secretlen);
  593. default:
  594. ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
  595. return -2;
  596. }
  597. }
  598. static int ecxkem_decapsulate(void *vctx, unsigned char *out, size_t *outlen,
  599. const unsigned char *in, size_t inlen)
  600. {
  601. PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
  602. switch (ctx->mode) {
  603. case KEM_MODE_DHKEM:
  604. return dhkem_decap(vctx, out, outlen, in, inlen);
  605. default:
  606. ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
  607. return -2;
  608. }
  609. }
  610. const OSSL_DISPATCH ossl_ecx_asym_kem_functions[] = {
  611. { OSSL_FUNC_KEM_NEWCTX, (void (*)(void))ecxkem_newctx },
  612. { OSSL_FUNC_KEM_ENCAPSULATE_INIT,
  613. (void (*)(void))ecxkem_encapsulate_init },
  614. { OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))ecxkem_encapsulate },
  615. { OSSL_FUNC_KEM_DECAPSULATE_INIT,
  616. (void (*)(void))ecxkem_decapsulate_init },
  617. { OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))ecxkem_decapsulate },
  618. { OSSL_FUNC_KEM_FREECTX, (void (*)(void))ecxkem_freectx },
  619. { OSSL_FUNC_KEM_SET_CTX_PARAMS,
  620. (void (*)(void))ecxkem_set_ctx_params },
  621. { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS,
  622. (void (*)(void))ecxkem_settable_ctx_params },
  623. { OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT,
  624. (void (*)(void))ecxkem_auth_encapsulate_init },
  625. { OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT,
  626. (void (*)(void))ecxkem_auth_decapsulate_init },
  627. { 0, NULL }
  628. };