hpke.c 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  1. /*
  2. * Copyright 2022-2024 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. /* An OpenSSL-based HPKE implementation of RFC9180 */
  10. #include <string.h>
  11. #include <openssl/rand.h>
  12. #include <openssl/kdf.h>
  13. #include <openssl/core_names.h>
  14. #include <openssl/hpke.h>
  15. #include <openssl/sha.h>
  16. #include <openssl/evp.h>
  17. #include <openssl/err.h>
  18. #include "internal/hpke_util.h"
  19. #include "internal/nelem.h"
  20. #include "internal/common.h"
  21. /* default buffer size for keys and internal buffers we use */
  22. #define OSSL_HPKE_MAXSIZE 512
  23. /* Define HPKE labels from RFC9180 in hex for EBCDIC compatibility */
  24. /* "HPKE" - "suite_id" label for section 5.1 */
  25. static const char OSSL_HPKE_SEC51LABEL[] = "\x48\x50\x4b\x45";
  26. /* "psk_id_hash" - in key_schedule_context */
  27. static const char OSSL_HPKE_PSKIDHASH_LABEL[] = "\x70\x73\x6b\x5f\x69\x64\x5f\x68\x61\x73\x68";
  28. /* "info_hash" - in key_schedule_context */
  29. static const char OSSL_HPKE_INFOHASH_LABEL[] = "\x69\x6e\x66\x6f\x5f\x68\x61\x73\x68";
  30. /* "base_nonce" - base nonce calc label */
  31. static const char OSSL_HPKE_NONCE_LABEL[] = "\x62\x61\x73\x65\x5f\x6e\x6f\x6e\x63\x65";
  32. /* "exp" - internal exporter secret generation label */
  33. static const char OSSL_HPKE_EXP_LABEL[] = "\x65\x78\x70";
  34. /* "sec" - external label for exporting secret */
  35. static const char OSSL_HPKE_EXP_SEC_LABEL[] = "\x73\x65\x63";
  36. /* "key" - label for use when generating key from shared secret */
  37. static const char OSSL_HPKE_KEY_LABEL[] = "\x6b\x65\x79";
  38. /* "secret" - for generating shared secret */
  39. static const char OSSL_HPKE_SECRET_LABEL[] = "\x73\x65\x63\x72\x65\x74";
  40. /**
  41. * @brief sender or receiver context
  42. */
  43. struct ossl_hpke_ctx_st
  44. {
  45. OSSL_LIB_CTX *libctx; /* library context */
  46. char *propq; /* properties */
  47. int mode; /* HPKE mode */
  48. OSSL_HPKE_SUITE suite; /* suite */
  49. const OSSL_HPKE_KEM_INFO *kem_info;
  50. const OSSL_HPKE_KDF_INFO *kdf_info;
  51. const OSSL_HPKE_AEAD_INFO *aead_info;
  52. EVP_CIPHER *aead_ciph;
  53. int role; /* sender(0) or receiver(1) */
  54. uint64_t seq; /* aead sequence number */
  55. unsigned char *shared_secret; /* KEM output, zz */
  56. size_t shared_secretlen;
  57. unsigned char *key; /* final aead key */
  58. size_t keylen;
  59. unsigned char *nonce; /* aead base nonce */
  60. size_t noncelen;
  61. unsigned char *exportersec; /* exporter secret */
  62. size_t exporterseclen;
  63. char *pskid; /* PSK stuff */
  64. unsigned char *psk;
  65. size_t psklen;
  66. EVP_PKEY *authpriv; /* sender's authentication private key */
  67. unsigned char *authpub; /* auth public key */
  68. size_t authpublen;
  69. unsigned char *ikme; /* IKM for sender deterministic key gen */
  70. size_t ikmelen;
  71. };
  72. /**
  73. * @brief check if KEM uses NIST curve or not
  74. * @param kem_id is the externally supplied kem_id
  75. * @return 1 for NIST curves, 0 for other
  76. */
  77. static int hpke_kem_id_nist_curve(uint16_t kem_id)
  78. {
  79. const OSSL_HPKE_KEM_INFO *kem_info;
  80. kem_info = ossl_HPKE_KEM_INFO_find_id(kem_id);
  81. return kem_info != NULL && kem_info->groupname != NULL;
  82. }
  83. /**
  84. * @brief wrapper to import NIST curve public key as easily as x25519/x448
  85. * @param libctx is the context to use
  86. * @param propq is a properties string
  87. * @param gname is the curve groupname
  88. * @param buf is the binary buffer with the (uncompressed) public value
  89. * @param buflen is the length of the private key buffer
  90. * @return a working EVP_PKEY * or NULL
  91. *
  92. * Note that this could be a useful function to make public in
  93. * future, but would likely require a name change.
  94. */
  95. static EVP_PKEY *evp_pkey_new_raw_nist_public_key(OSSL_LIB_CTX *libctx,
  96. const char *propq,
  97. const char *gname,
  98. const unsigned char *buf,
  99. size_t buflen)
  100. {
  101. OSSL_PARAM params[2];
  102. EVP_PKEY *ret = NULL;
  103. EVP_PKEY_CTX *cctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
  104. params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
  105. (char *)gname, 0);
  106. params[1] = OSSL_PARAM_construct_end();
  107. if (cctx == NULL
  108. || EVP_PKEY_paramgen_init(cctx) <= 0
  109. || EVP_PKEY_CTX_set_params(cctx, params) <= 0
  110. || EVP_PKEY_paramgen(cctx, &ret) <= 0
  111. || EVP_PKEY_set1_encoded_public_key(ret, buf, buflen) != 1) {
  112. EVP_PKEY_CTX_free(cctx);
  113. EVP_PKEY_free(ret);
  114. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  115. return NULL;
  116. }
  117. EVP_PKEY_CTX_free(cctx);
  118. return ret;
  119. }
  120. /**
  121. * @brief do the AEAD decryption
  122. * @param hctx is the context to use
  123. * @param iv is the initialisation vector
  124. * @param aad is the additional authenticated data
  125. * @param aadlen is the length of the aad
  126. * @param ct is the ciphertext buffer
  127. * @param ctlen is the ciphertext length (including tag).
  128. * @param pt is the output buffer
  129. * @param ptlen input/output, better be big enough on input, exact on output
  130. * @return 1 on success, 0 otherwise
  131. */
  132. static int hpke_aead_dec(OSSL_HPKE_CTX *hctx, const unsigned char *iv,
  133. const unsigned char *aad, size_t aadlen,
  134. const unsigned char *ct, size_t ctlen,
  135. unsigned char *pt, size_t *ptlen)
  136. {
  137. int erv = 0;
  138. EVP_CIPHER_CTX *ctx = NULL;
  139. int len = 0;
  140. size_t taglen;
  141. taglen = hctx->aead_info->taglen;
  142. if (ctlen <= taglen || *ptlen < ctlen - taglen) {
  143. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  144. return 0;
  145. }
  146. /* Create and initialise the context */
  147. if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
  148. return 0;
  149. /* Initialise the decryption operation. */
  150. if (EVP_DecryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) {
  151. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  152. goto err;
  153. }
  154. if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
  155. hctx->noncelen, NULL) != 1) {
  156. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  157. goto err;
  158. }
  159. /* Initialise key and IV */
  160. if (EVP_DecryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) {
  161. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  162. goto err;
  163. }
  164. /* Provide AAD. */
  165. if (aadlen != 0 && aad != NULL) {
  166. if (EVP_DecryptUpdate(ctx, NULL, &len, aad, aadlen) != 1) {
  167. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  168. goto err;
  169. }
  170. }
  171. if (EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen - taglen) != 1) {
  172. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  173. goto err;
  174. }
  175. *ptlen = len;
  176. if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
  177. taglen, (void *)(ct + ctlen - taglen))) {
  178. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  179. goto err;
  180. }
  181. /* Finalise decryption. */
  182. if (EVP_DecryptFinal_ex(ctx, pt + len, &len) <= 0) {
  183. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  184. goto err;
  185. }
  186. erv = 1;
  187. err:
  188. if (erv != 1)
  189. OPENSSL_cleanse(pt, *ptlen);
  190. EVP_CIPHER_CTX_free(ctx);
  191. return erv;
  192. }
  193. /**
  194. * @brief do AEAD encryption as per the RFC
  195. * @param hctx is the context to use
  196. * @param iv is the initialisation vector
  197. * @param aad is the additional authenticated data
  198. * @param aadlen is the length of the aad
  199. * @param pt is the plaintext buffer
  200. * @param ptlen is the length of pt
  201. * @param ct is the output buffer
  202. * @param ctlen input/output, needs space for tag on input, exact on output
  203. * @return 1 for success, 0 otherwise
  204. */
  205. static int hpke_aead_enc(OSSL_HPKE_CTX *hctx, const unsigned char *iv,
  206. const unsigned char *aad, size_t aadlen,
  207. const unsigned char *pt, size_t ptlen,
  208. unsigned char *ct, size_t *ctlen)
  209. {
  210. int erv = 0;
  211. EVP_CIPHER_CTX *ctx = NULL;
  212. int len;
  213. size_t taglen = 0;
  214. unsigned char tag[EVP_MAX_AEAD_TAG_LENGTH];
  215. taglen = hctx->aead_info->taglen;
  216. if (*ctlen <= taglen || ptlen > *ctlen - taglen) {
  217. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  218. return 0;
  219. }
  220. if (!ossl_assert(taglen <= sizeof(tag))) {
  221. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  222. return 0;
  223. }
  224. /* Create and initialise the context */
  225. if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
  226. return 0;
  227. /* Initialise the encryption operation. */
  228. if (EVP_EncryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) {
  229. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  230. goto err;
  231. }
  232. if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
  233. hctx->noncelen, NULL) != 1) {
  234. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  235. goto err;
  236. }
  237. /* Initialise key and IV */
  238. if (EVP_EncryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) {
  239. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  240. goto err;
  241. }
  242. /* Provide any AAD data. */
  243. if (aadlen != 0 && aad != NULL) {
  244. if (EVP_EncryptUpdate(ctx, NULL, &len, aad, aadlen) != 1) {
  245. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  246. goto err;
  247. }
  248. }
  249. if (EVP_EncryptUpdate(ctx, ct, &len, pt, ptlen) != 1) {
  250. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  251. goto err;
  252. }
  253. *ctlen = len;
  254. /* Finalise the encryption. */
  255. if (EVP_EncryptFinal_ex(ctx, ct + len, &len) != 1) {
  256. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  257. goto err;
  258. }
  259. *ctlen += len;
  260. /* Get tag. Not a duplicate so needs to be added to the ciphertext */
  261. if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, tag) != 1) {
  262. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  263. goto err;
  264. }
  265. memcpy(ct + *ctlen, tag, taglen);
  266. *ctlen += taglen;
  267. erv = 1;
  268. err:
  269. if (erv != 1)
  270. OPENSSL_cleanse(ct, *ctlen);
  271. EVP_CIPHER_CTX_free(ctx);
  272. return erv;
  273. }
  274. /**
  275. * @brief check mode is in-range and supported
  276. * @param mode is the caller's chosen mode
  277. * @return 1 for good mode, 0 otherwise
  278. */
  279. static int hpke_mode_check(unsigned int mode)
  280. {
  281. switch (mode) {
  282. case OSSL_HPKE_MODE_BASE:
  283. case OSSL_HPKE_MODE_PSK:
  284. case OSSL_HPKE_MODE_AUTH:
  285. case OSSL_HPKE_MODE_PSKAUTH:
  286. break;
  287. default:
  288. return 0;
  289. }
  290. return 1;
  291. }
  292. /**
  293. * @brief check if a suite is supported locally
  294. * @param suite is the suite to check
  295. * @return 1 for good, 0 otherwise
  296. */
  297. static int hpke_suite_check(OSSL_HPKE_SUITE suite,
  298. const OSSL_HPKE_KEM_INFO **kem_info,
  299. const OSSL_HPKE_KDF_INFO **kdf_info,
  300. const OSSL_HPKE_AEAD_INFO **aead_info)
  301. {
  302. const OSSL_HPKE_KEM_INFO *kem_info_;
  303. const OSSL_HPKE_KDF_INFO *kdf_info_;
  304. const OSSL_HPKE_AEAD_INFO *aead_info_;
  305. /* check KEM, KDF and AEAD are supported here */
  306. if ((kem_info_ = ossl_HPKE_KEM_INFO_find_id(suite.kem_id)) == NULL)
  307. return 0;
  308. if ((kdf_info_ = ossl_HPKE_KDF_INFO_find_id(suite.kdf_id)) == NULL)
  309. return 0;
  310. if ((aead_info_ = ossl_HPKE_AEAD_INFO_find_id(suite.aead_id)) == NULL)
  311. return 0;
  312. if (kem_info != NULL)
  313. *kem_info = kem_info_;
  314. if (kdf_info != NULL)
  315. *kdf_info = kdf_info_;
  316. if (aead_info != NULL)
  317. *aead_info = aead_info_;
  318. return 1;
  319. }
  320. /*
  321. * @brief randomly pick a suite
  322. * @param libctx is the context to use
  323. * @param propq is a properties string
  324. * @param suite is the result
  325. * @return 1 for success, 0 otherwise
  326. */
  327. static int hpke_random_suite(OSSL_LIB_CTX *libctx,
  328. const char *propq,
  329. OSSL_HPKE_SUITE *suite)
  330. {
  331. const OSSL_HPKE_KEM_INFO *kem_info = NULL;
  332. const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
  333. const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
  334. /* random kem, kdf and aead */
  335. kem_info = ossl_HPKE_KEM_INFO_find_random(libctx);
  336. if (kem_info == NULL)
  337. return 0;
  338. suite->kem_id = kem_info->kem_id;
  339. kdf_info = ossl_HPKE_KDF_INFO_find_random(libctx);
  340. if (kdf_info == NULL)
  341. return 0;
  342. suite->kdf_id = kdf_info->kdf_id;
  343. aead_info = ossl_HPKE_AEAD_INFO_find_random(libctx);
  344. if (aead_info == NULL)
  345. return 0;
  346. suite->aead_id = aead_info->aead_id;
  347. return 1;
  348. }
  349. /*
  350. * @brief tell the caller how big the ciphertext will be
  351. *
  352. * AEAD algorithms add a tag for data authentication.
  353. * Those are almost always, but not always, 16 octets
  354. * long, and who knows what will be true in the future.
  355. * So this function allows a caller to find out how
  356. * much data expansion they will see with a given suite.
  357. *
  358. * "enc" is the name used in RFC9180 for the encapsulated
  359. * public value of the sender, who calls OSSL_HPKE_seal(),
  360. * that is sent to the recipient, who calls OSSL_HPKE_open().
  361. *
  362. * @param suite is the suite to be used
  363. * @param enclen points to what will be enc length
  364. * @param clearlen is the length of plaintext
  365. * @param cipherlen points to what will be ciphertext length (including tag)
  366. * @return 1 for success, 0 otherwise
  367. */
  368. static int hpke_expansion(OSSL_HPKE_SUITE suite,
  369. size_t *enclen,
  370. size_t clearlen,
  371. size_t *cipherlen)
  372. {
  373. const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
  374. const OSSL_HPKE_KEM_INFO *kem_info = NULL;
  375. if (cipherlen == NULL || enclen == NULL) {
  376. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  377. return 0;
  378. }
  379. if (hpke_suite_check(suite, &kem_info, NULL, &aead_info) != 1) {
  380. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  381. return 0;
  382. }
  383. *cipherlen = clearlen + aead_info->taglen;
  384. *enclen = kem_info->Nenc;
  385. return 1;
  386. }
  387. /*
  388. * @brief expand and XOR the 64-bit unsigned seq with (nonce) buffer
  389. * @param ctx is the HPKE context
  390. * @param buf is the buffer for the XOR'd seq and nonce
  391. * @param blen is the size of buf
  392. * @return 0 for error, otherwise blen
  393. */
  394. static size_t hpke_seqnonce2buf(OSSL_HPKE_CTX *ctx,
  395. unsigned char *buf, size_t blen)
  396. {
  397. size_t i;
  398. uint64_t seq_copy;
  399. if (ctx == NULL || blen < sizeof(seq_copy) || blen != ctx->noncelen)
  400. return 0;
  401. seq_copy = ctx->seq;
  402. memset(buf, 0, blen);
  403. for (i = 0; i < sizeof(seq_copy); i++) {
  404. buf[blen - i - 1] = seq_copy & 0xff;
  405. seq_copy >>= 8;
  406. }
  407. for (i = 0; i < blen; i++)
  408. buf[i] ^= ctx->nonce[i];
  409. return blen;
  410. }
  411. /*
  412. * @brief call the underlying KEM to encap
  413. * @param ctx is the OSSL_HPKE_CTX
  414. * @param enc is a buffer for the sender's ephemeral public value
  415. * @param enclen is the size of enc on input, number of octets used on output
  416. * @param pub is the recipient's public value
  417. * @param publen is the length of pub
  418. * @return 1 for success, 0 for error
  419. */
  420. static int hpke_encap(OSSL_HPKE_CTX *ctx, unsigned char *enc, size_t *enclen,
  421. const unsigned char *pub, size_t publen)
  422. {
  423. int erv = 0;
  424. OSSL_PARAM params[3], *p = params;
  425. size_t lsslen = 0, lenclen = 0;
  426. EVP_PKEY_CTX *pctx = NULL;
  427. EVP_PKEY *pkR = NULL;
  428. const OSSL_HPKE_KEM_INFO *kem_info = NULL;
  429. if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0
  430. || pub == NULL || publen == 0) {
  431. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  432. return 0;
  433. }
  434. if (ctx->shared_secret != NULL) {
  435. /* only run the KEM once per OSSL_HPKE_CTX */
  436. ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
  437. return 0;
  438. }
  439. kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
  440. if (kem_info == NULL) {
  441. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  442. return 0;
  443. }
  444. if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
  445. pkR = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
  446. kem_info->groupname,
  447. pub, publen);
  448. } else {
  449. pkR = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
  450. kem_info->keytype,
  451. ctx->propq, pub, publen);
  452. }
  453. if (pkR == NULL) {
  454. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  455. goto err;
  456. }
  457. pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkR, ctx->propq);
  458. if (pctx == NULL) {
  459. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  460. goto err;
  461. }
  462. *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
  463. OSSL_KEM_PARAM_OPERATION_DHKEM,
  464. 0);
  465. if (ctx->ikme != NULL) {
  466. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME,
  467. ctx->ikme, ctx->ikmelen);
  468. }
  469. *p = OSSL_PARAM_construct_end();
  470. if (ctx->mode == OSSL_HPKE_MODE_AUTH
  471. || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
  472. if (EVP_PKEY_auth_encapsulate_init(pctx, ctx->authpriv,
  473. params) != 1) {
  474. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  475. goto err;
  476. }
  477. } else {
  478. if (EVP_PKEY_encapsulate_init(pctx, params) != 1) {
  479. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  480. goto err;
  481. }
  482. }
  483. lenclen = *enclen;
  484. if (EVP_PKEY_encapsulate(pctx, NULL, &lenclen, NULL, &lsslen) != 1) {
  485. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  486. goto err;
  487. }
  488. if (lenclen > *enclen) {
  489. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  490. goto err;
  491. }
  492. ctx->shared_secret = OPENSSL_malloc(lsslen);
  493. if (ctx->shared_secret == NULL)
  494. goto err;
  495. ctx->shared_secretlen = lsslen;
  496. if (EVP_PKEY_encapsulate(pctx, enc, enclen, ctx->shared_secret,
  497. &ctx->shared_secretlen) != 1) {
  498. ctx->shared_secretlen = 0;
  499. OPENSSL_free(ctx->shared_secret);
  500. ctx->shared_secret = NULL;
  501. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  502. goto err;
  503. }
  504. erv = 1;
  505. err:
  506. EVP_PKEY_CTX_free(pctx);
  507. EVP_PKEY_free(pkR);
  508. return erv;
  509. }
  510. /*
  511. * @brief call the underlying KEM to decap
  512. * @param ctx is the OSSL_HPKE_CTX
  513. * @param enc is a buffer for the sender's ephemeral public value
  514. * @param enclen is the length of enc
  515. * @param priv is the recipient's private value
  516. * @return 1 for success, 0 for error
  517. */
  518. static int hpke_decap(OSSL_HPKE_CTX *ctx,
  519. const unsigned char *enc, size_t enclen,
  520. EVP_PKEY *priv)
  521. {
  522. int erv = 0;
  523. EVP_PKEY_CTX *pctx = NULL;
  524. EVP_PKEY *spub = NULL;
  525. OSSL_PARAM params[2], *p = params;
  526. size_t lsslen = 0;
  527. if (ctx == NULL || enc == NULL || enclen == 0 || priv == NULL) {
  528. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  529. return 0;
  530. }
  531. if (ctx->shared_secret != NULL) {
  532. /* only run the KEM once per OSSL_HPKE_CTX */
  533. ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
  534. return 0;
  535. }
  536. pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, priv, ctx->propq);
  537. if (pctx == NULL) {
  538. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  539. goto err;
  540. }
  541. *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
  542. OSSL_KEM_PARAM_OPERATION_DHKEM,
  543. 0);
  544. *p = OSSL_PARAM_construct_end();
  545. if (ctx->mode == OSSL_HPKE_MODE_AUTH
  546. || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
  547. const OSSL_HPKE_KEM_INFO *kem_info = NULL;
  548. kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
  549. if (kem_info == NULL) {
  550. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  551. goto err;
  552. }
  553. if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
  554. spub = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
  555. kem_info->groupname,
  556. ctx->authpub,
  557. ctx->authpublen);
  558. } else {
  559. spub = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
  560. kem_info->keytype,
  561. ctx->propq,
  562. ctx->authpub,
  563. ctx->authpublen);
  564. }
  565. if (spub == NULL) {
  566. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  567. goto err;
  568. }
  569. if (EVP_PKEY_auth_decapsulate_init(pctx, spub, params) != 1) {
  570. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  571. goto err;
  572. }
  573. } else {
  574. if (EVP_PKEY_decapsulate_init(pctx, params) != 1) {
  575. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  576. goto err;
  577. }
  578. }
  579. if (EVP_PKEY_decapsulate(pctx, NULL, &lsslen, enc, enclen) != 1) {
  580. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  581. goto err;
  582. }
  583. ctx->shared_secret = OPENSSL_malloc(lsslen);
  584. if (ctx->shared_secret == NULL)
  585. goto err;
  586. if (EVP_PKEY_decapsulate(pctx, ctx->shared_secret, &lsslen,
  587. enc, enclen) != 1) {
  588. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  589. goto err;
  590. }
  591. ctx->shared_secretlen = lsslen;
  592. erv = 1;
  593. err:
  594. EVP_PKEY_CTX_free(pctx);
  595. EVP_PKEY_free(spub);
  596. if (erv == 0) {
  597. OPENSSL_free(ctx->shared_secret);
  598. ctx->shared_secret = NULL;
  599. ctx->shared_secretlen = 0;
  600. }
  601. return erv;
  602. }
  603. /*
  604. * @brief do "middle" of HPKE, between KEM and AEAD
  605. * @param ctx is the OSSL_HPKE_CTX
  606. * @param info is a buffer for the added binding information
  607. * @param infolen is the length of info
  608. * @return 0 for error, 1 for success
  609. *
  610. * This does all the HPKE extracts and expands as defined in RFC9180
  611. * section 5.1, (badly termed there as a "key schedule") and sets the
  612. * ctx fields for the shared_secret, nonce, key and exporter_secret
  613. */
  614. static int hpke_do_middle(OSSL_HPKE_CTX *ctx,
  615. const unsigned char *info, size_t infolen)
  616. {
  617. int erv = 0;
  618. size_t ks_contextlen = OSSL_HPKE_MAXSIZE;
  619. unsigned char ks_context[OSSL_HPKE_MAXSIZE];
  620. size_t halflen = 0;
  621. size_t pskidlen = 0;
  622. const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
  623. const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
  624. size_t secretlen = OSSL_HPKE_MAXSIZE;
  625. unsigned char secret[OSSL_HPKE_MAXSIZE];
  626. EVP_KDF_CTX *kctx = NULL;
  627. unsigned char suitebuf[6];
  628. const char *mdname = NULL;
  629. /* only let this be done once */
  630. if (ctx->exportersec != NULL) {
  631. ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
  632. return 0;
  633. }
  634. if (ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id) == NULL) {
  635. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  636. return 0;
  637. }
  638. aead_info = ossl_HPKE_AEAD_INFO_find_id(ctx->suite.aead_id);
  639. if (aead_info == NULL) {
  640. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  641. return 0;
  642. }
  643. kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id);
  644. if (kdf_info == NULL) {
  645. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  646. return 0;
  647. }
  648. mdname = kdf_info->mdname;
  649. /* create key schedule context */
  650. memset(ks_context, 0, sizeof(ks_context));
  651. ks_context[0] = (unsigned char)(ctx->mode % 256);
  652. ks_contextlen--; /* remaining space */
  653. halflen = kdf_info->Nh;
  654. if ((2 * halflen) > ks_contextlen) {
  655. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  656. return 0;
  657. }
  658. /* check a psk was set if in that mode */
  659. if (ctx->mode == OSSL_HPKE_MODE_PSK
  660. || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
  661. if (ctx->psk == NULL || ctx->psklen == 0 || ctx->pskid == NULL) {
  662. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  663. return 0;
  664. }
  665. }
  666. kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
  667. if (kctx == NULL) {
  668. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  669. return 0;
  670. }
  671. pskidlen = (ctx->psk == NULL ? 0 : strlen(ctx->pskid));
  672. /* full suite details as per RFC9180 sec 5.1 */
  673. suitebuf[0] = ctx->suite.kem_id / 256;
  674. suitebuf[1] = ctx->suite.kem_id % 256;
  675. suitebuf[2] = ctx->suite.kdf_id / 256;
  676. suitebuf[3] = ctx->suite.kdf_id % 256;
  677. suitebuf[4] = ctx->suite.aead_id / 256;
  678. suitebuf[5] = ctx->suite.aead_id % 256;
  679. /* Extract and Expand variously... */
  680. if (ossl_hpke_labeled_extract(kctx, ks_context + 1, halflen,
  681. NULL, 0, OSSL_HPKE_SEC51LABEL,
  682. suitebuf, sizeof(suitebuf),
  683. OSSL_HPKE_PSKIDHASH_LABEL,
  684. (unsigned char *)ctx->pskid, pskidlen) != 1) {
  685. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  686. goto err;
  687. }
  688. if (ossl_hpke_labeled_extract(kctx, ks_context + 1 + halflen, halflen,
  689. NULL, 0, OSSL_HPKE_SEC51LABEL,
  690. suitebuf, sizeof(suitebuf),
  691. OSSL_HPKE_INFOHASH_LABEL,
  692. (unsigned char *)info, infolen) != 1) {
  693. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  694. goto err;
  695. }
  696. ks_contextlen = 1 + 2 * halflen;
  697. secretlen = kdf_info->Nh;
  698. if (secretlen > OSSL_HPKE_MAXSIZE) {
  699. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  700. goto err;
  701. }
  702. if (ossl_hpke_labeled_extract(kctx, secret, secretlen,
  703. ctx->shared_secret, ctx->shared_secretlen,
  704. OSSL_HPKE_SEC51LABEL,
  705. suitebuf, sizeof(suitebuf),
  706. OSSL_HPKE_SECRET_LABEL,
  707. ctx->psk, ctx->psklen) != 1) {
  708. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  709. goto err;
  710. }
  711. if (ctx->suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) {
  712. /* we only need nonce/key for non export AEADs */
  713. ctx->noncelen = aead_info->Nn;
  714. ctx->nonce = OPENSSL_malloc(ctx->noncelen);
  715. if (ctx->nonce == NULL)
  716. goto err;
  717. if (ossl_hpke_labeled_expand(kctx, ctx->nonce, ctx->noncelen,
  718. secret, secretlen, OSSL_HPKE_SEC51LABEL,
  719. suitebuf, sizeof(suitebuf),
  720. OSSL_HPKE_NONCE_LABEL,
  721. ks_context, ks_contextlen) != 1) {
  722. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  723. goto err;
  724. }
  725. ctx->keylen = aead_info->Nk;
  726. ctx->key = OPENSSL_malloc(ctx->keylen);
  727. if (ctx->key == NULL)
  728. goto err;
  729. if (ossl_hpke_labeled_expand(kctx, ctx->key, ctx->keylen,
  730. secret, secretlen, OSSL_HPKE_SEC51LABEL,
  731. suitebuf, sizeof(suitebuf),
  732. OSSL_HPKE_KEY_LABEL,
  733. ks_context, ks_contextlen) != 1) {
  734. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  735. goto err;
  736. }
  737. }
  738. ctx->exporterseclen = kdf_info->Nh;
  739. ctx->exportersec = OPENSSL_malloc(ctx->exporterseclen);
  740. if (ctx->exportersec == NULL)
  741. goto err;
  742. if (ossl_hpke_labeled_expand(kctx, ctx->exportersec, ctx->exporterseclen,
  743. secret, secretlen, OSSL_HPKE_SEC51LABEL,
  744. suitebuf, sizeof(suitebuf),
  745. OSSL_HPKE_EXP_LABEL,
  746. ks_context, ks_contextlen) != 1) {
  747. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  748. goto err;
  749. }
  750. erv = 1;
  751. err:
  752. OPENSSL_cleanse(ks_context, OSSL_HPKE_MAXSIZE);
  753. OPENSSL_cleanse(secret, OSSL_HPKE_MAXSIZE);
  754. EVP_KDF_CTX_free(kctx);
  755. return erv;
  756. }
  757. /*
  758. * externally visible functions from below here, API documentation is
  759. * in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication
  760. */
  761. OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role,
  762. OSSL_LIB_CTX *libctx, const char *propq)
  763. {
  764. OSSL_HPKE_CTX *ctx = NULL;
  765. const OSSL_HPKE_KEM_INFO *kem_info;
  766. const OSSL_HPKE_KDF_INFO *kdf_info;
  767. const OSSL_HPKE_AEAD_INFO *aead_info;
  768. if (hpke_mode_check(mode) != 1) {
  769. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  770. return NULL;
  771. }
  772. if (hpke_suite_check(suite, &kem_info, &kdf_info, &aead_info) != 1) {
  773. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  774. return NULL;
  775. }
  776. if (role != OSSL_HPKE_ROLE_SENDER && role != OSSL_HPKE_ROLE_RECEIVER) {
  777. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  778. return 0;
  779. }
  780. ctx = OPENSSL_zalloc(sizeof(*ctx));
  781. if (ctx == NULL)
  782. return NULL;
  783. ctx->libctx = libctx;
  784. if (propq != NULL) {
  785. ctx->propq = OPENSSL_strdup(propq);
  786. if (ctx->propq == NULL)
  787. goto err;
  788. }
  789. if (suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) {
  790. ctx->aead_ciph = EVP_CIPHER_fetch(libctx, aead_info->name, propq);
  791. if (ctx->aead_ciph == NULL) {
  792. ERR_raise(ERR_LIB_CRYPTO, ERR_R_FETCH_FAILED);
  793. goto err;
  794. }
  795. }
  796. ctx->role = role;
  797. ctx->mode = mode;
  798. ctx->suite = suite;
  799. ctx->kem_info = kem_info;
  800. ctx->kdf_info = kdf_info;
  801. ctx->aead_info = aead_info;
  802. return ctx;
  803. err:
  804. EVP_CIPHER_free(ctx->aead_ciph);
  805. OPENSSL_free(ctx->propq);
  806. OPENSSL_free(ctx);
  807. return NULL;
  808. }
  809. void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX *ctx)
  810. {
  811. if (ctx == NULL)
  812. return;
  813. EVP_CIPHER_free(ctx->aead_ciph);
  814. OPENSSL_free(ctx->propq);
  815. OPENSSL_clear_free(ctx->exportersec, ctx->exporterseclen);
  816. OPENSSL_free(ctx->pskid);
  817. OPENSSL_clear_free(ctx->psk, ctx->psklen);
  818. OPENSSL_clear_free(ctx->key, ctx->keylen);
  819. OPENSSL_clear_free(ctx->nonce, ctx->noncelen);
  820. OPENSSL_clear_free(ctx->shared_secret, ctx->shared_secretlen);
  821. OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
  822. EVP_PKEY_free(ctx->authpriv);
  823. OPENSSL_free(ctx->authpub);
  824. OPENSSL_free(ctx);
  825. return;
  826. }
  827. int OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX *ctx,
  828. const char *pskid,
  829. const unsigned char *psk, size_t psklen)
  830. {
  831. if (ctx == NULL || pskid == NULL || psk == NULL || psklen == 0) {
  832. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  833. return 0;
  834. }
  835. if (psklen > OSSL_HPKE_MAX_PARMLEN) {
  836. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  837. return 0;
  838. }
  839. if (psklen < OSSL_HPKE_MIN_PSKLEN) {
  840. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  841. return 0;
  842. }
  843. if (strlen(pskid) > OSSL_HPKE_MAX_PARMLEN) {
  844. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  845. return 0;
  846. }
  847. if (strlen(pskid) == 0) {
  848. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  849. return 0;
  850. }
  851. if (ctx->mode != OSSL_HPKE_MODE_PSK
  852. && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
  853. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  854. return 0;
  855. }
  856. /* free previous values if any */
  857. OPENSSL_clear_free(ctx->psk, ctx->psklen);
  858. ctx->psk = OPENSSL_memdup(psk, psklen);
  859. if (ctx->psk == NULL)
  860. return 0;
  861. ctx->psklen = psklen;
  862. OPENSSL_free(ctx->pskid);
  863. ctx->pskid = OPENSSL_strdup(pskid);
  864. if (ctx->pskid == NULL) {
  865. OPENSSL_clear_free(ctx->psk, ctx->psklen);
  866. ctx->psk = NULL;
  867. ctx->psklen = 0;
  868. return 0;
  869. }
  870. return 1;
  871. }
  872. int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX *ctx,
  873. const unsigned char *ikme, size_t ikmelen)
  874. {
  875. if (ctx == NULL || ikme == NULL) {
  876. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
  877. return 0;
  878. }
  879. if (ikmelen == 0 || ikmelen > OSSL_HPKE_MAX_PARMLEN) {
  880. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  881. return 0;
  882. }
  883. if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
  884. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  885. return 0;
  886. }
  887. OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
  888. ctx->ikme = OPENSSL_memdup(ikme, ikmelen);
  889. if (ctx->ikme == NULL)
  890. return 0;
  891. ctx->ikmelen = ikmelen;
  892. return 1;
  893. }
  894. int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX *ctx, EVP_PKEY *priv)
  895. {
  896. if (ctx == NULL || priv == NULL) {
  897. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
  898. return 0;
  899. }
  900. if (ctx->mode != OSSL_HPKE_MODE_AUTH
  901. && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
  902. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  903. return 0;
  904. }
  905. if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
  906. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  907. return 0;
  908. }
  909. EVP_PKEY_free(ctx->authpriv);
  910. ctx->authpriv = EVP_PKEY_dup(priv);
  911. if (ctx->authpriv == NULL)
  912. return 0;
  913. return 1;
  914. }
  915. int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX *ctx,
  916. const unsigned char *pub, size_t publen)
  917. {
  918. int erv = 0;
  919. EVP_PKEY *pubp = NULL;
  920. unsigned char *lpub = NULL;
  921. size_t lpublen = 0;
  922. const OSSL_HPKE_KEM_INFO *kem_info = NULL;
  923. if (ctx == NULL || pub == NULL || publen == 0) {
  924. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
  925. return 0;
  926. }
  927. if (ctx->mode != OSSL_HPKE_MODE_AUTH
  928. && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
  929. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  930. return 0;
  931. }
  932. if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
  933. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  934. return 0;
  935. }
  936. /* check the value seems like a good public key for this kem */
  937. kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
  938. if (kem_info == NULL)
  939. return 0;
  940. if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
  941. pubp = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
  942. kem_info->groupname,
  943. pub, publen);
  944. } else {
  945. pubp = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
  946. kem_info->keytype,
  947. ctx->propq,
  948. pub, publen);
  949. }
  950. if (pubp == NULL) {
  951. /* can happen based on external input - buffer value may be garbage */
  952. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  953. goto err;
  954. }
  955. /*
  956. * extract out the public key in encoded form so we
  957. * should be fine even if given compressed form
  958. */
  959. lpub = OPENSSL_malloc(OSSL_HPKE_MAXSIZE);
  960. if (lpub == NULL)
  961. goto err;
  962. if (EVP_PKEY_get_octet_string_param(pubp,
  963. OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
  964. lpub, OSSL_HPKE_MAXSIZE, &lpublen)
  965. != 1) {
  966. OPENSSL_free(lpub);
  967. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  968. goto err;
  969. }
  970. /* free up old value */
  971. OPENSSL_free(ctx->authpub);
  972. ctx->authpub = lpub;
  973. ctx->authpublen = lpublen;
  974. erv = 1;
  975. err:
  976. EVP_PKEY_free(pubp);
  977. return erv;
  978. }
  979. int OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX *ctx, uint64_t *seq)
  980. {
  981. if (ctx == NULL || seq == NULL) {
  982. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
  983. return 0;
  984. }
  985. *seq = ctx->seq;
  986. return 1;
  987. }
  988. int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX *ctx, uint64_t seq)
  989. {
  990. if (ctx == NULL) {
  991. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
  992. return 0;
  993. }
  994. /*
  995. * We disallow senders from doing this as it's dangerous
  996. * Receivers are ok to use this, as no harm should ensue
  997. * if they go wrong.
  998. */
  999. if (ctx->role == OSSL_HPKE_ROLE_SENDER) {
  1000. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1001. return 0;
  1002. }
  1003. ctx->seq = seq;
  1004. return 1;
  1005. }
  1006. int OSSL_HPKE_encap(OSSL_HPKE_CTX *ctx,
  1007. unsigned char *enc, size_t *enclen,
  1008. const unsigned char *pub, size_t publen,
  1009. const unsigned char *info, size_t infolen)
  1010. {
  1011. int erv = 1;
  1012. size_t minenc = 0;
  1013. if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0
  1014. || pub == NULL || publen == 0) {
  1015. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1016. return 0;
  1017. }
  1018. if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
  1019. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1020. return 0;
  1021. }
  1022. if (infolen > OSSL_HPKE_MAX_INFOLEN) {
  1023. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1024. return 0;
  1025. }
  1026. if (infolen > 0 && info == NULL) {
  1027. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1028. return 0;
  1029. }
  1030. minenc = OSSL_HPKE_get_public_encap_size(ctx->suite);
  1031. if (minenc == 0 || minenc > *enclen) {
  1032. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1033. return 0;
  1034. }
  1035. if (ctx->shared_secret != NULL) {
  1036. /* only allow one encap per OSSL_HPKE_CTX */
  1037. ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
  1038. return 0;
  1039. }
  1040. if (hpke_encap(ctx, enc, enclen, pub, publen) != 1) {
  1041. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1042. return 0;
  1043. }
  1044. /*
  1045. * note that the info is not part of the context as it
  1046. * only needs to be used once here so doesn't need to
  1047. * be stored
  1048. */
  1049. erv = hpke_do_middle(ctx, info, infolen);
  1050. return erv;
  1051. }
  1052. int OSSL_HPKE_decap(OSSL_HPKE_CTX *ctx,
  1053. const unsigned char *enc, size_t enclen,
  1054. EVP_PKEY *recippriv,
  1055. const unsigned char *info, size_t infolen)
  1056. {
  1057. int erv = 1;
  1058. size_t minenc = 0;
  1059. if (ctx == NULL || enc == NULL || enclen == 0 || recippriv == NULL) {
  1060. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1061. return 0;
  1062. }
  1063. if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
  1064. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1065. return 0;
  1066. }
  1067. if (infolen > OSSL_HPKE_MAX_INFOLEN) {
  1068. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1069. return 0;
  1070. }
  1071. if (infolen > 0 && info == NULL) {
  1072. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1073. return 0;
  1074. }
  1075. minenc = OSSL_HPKE_get_public_encap_size(ctx->suite);
  1076. if (minenc == 0 || minenc > enclen) {
  1077. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1078. return 0;
  1079. }
  1080. if (ctx->shared_secret != NULL) {
  1081. /* only allow one encap per OSSL_HPKE_CTX */
  1082. ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
  1083. return 0;
  1084. }
  1085. erv = hpke_decap(ctx, enc, enclen, recippriv);
  1086. if (erv != 1) {
  1087. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1088. return 0;
  1089. }
  1090. /*
  1091. * note that the info is not part of the context as it
  1092. * only needs to be used once here so doesn't need to
  1093. * be stored
  1094. */
  1095. erv = hpke_do_middle(ctx, info, infolen);
  1096. return erv;
  1097. }
  1098. int OSSL_HPKE_seal(OSSL_HPKE_CTX *ctx,
  1099. unsigned char *ct, size_t *ctlen,
  1100. const unsigned char *aad, size_t aadlen,
  1101. const unsigned char *pt, size_t ptlen)
  1102. {
  1103. unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
  1104. size_t seqlen = 0;
  1105. if (ctx == NULL || ct == NULL || ctlen == NULL || *ctlen == 0
  1106. || pt == NULL || ptlen == 0) {
  1107. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1108. return 0;
  1109. }
  1110. if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
  1111. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1112. return 0;
  1113. }
  1114. if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
  1115. ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
  1116. return 0;
  1117. }
  1118. if (ctx->key == NULL || ctx->nonce == NULL) {
  1119. /* need to have done an encap first, info can be NULL */
  1120. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1121. return 0;
  1122. }
  1123. seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
  1124. if (seqlen == 0) {
  1125. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1126. return 0;
  1127. }
  1128. if (hpke_aead_enc(ctx, seqbuf, aad, aadlen, pt, ptlen, ct, ctlen) != 1) {
  1129. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1130. OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
  1131. return 0;
  1132. } else {
  1133. ctx->seq++;
  1134. }
  1135. OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
  1136. return 1;
  1137. }
  1138. int OSSL_HPKE_open(OSSL_HPKE_CTX *ctx,
  1139. unsigned char *pt, size_t *ptlen,
  1140. const unsigned char *aad, size_t aadlen,
  1141. const unsigned char *ct, size_t ctlen)
  1142. {
  1143. unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
  1144. size_t seqlen = 0;
  1145. if (ctx == NULL || pt == NULL || ptlen == NULL || *ptlen == 0
  1146. || ct == NULL || ctlen == 0) {
  1147. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1148. return 0;
  1149. }
  1150. if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
  1151. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1152. return 0;
  1153. }
  1154. if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
  1155. ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
  1156. return 0;
  1157. }
  1158. if (ctx->key == NULL || ctx->nonce == NULL) {
  1159. /* need to have done an encap first, info can be NULL */
  1160. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1161. return 0;
  1162. }
  1163. seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
  1164. if (seqlen == 0) {
  1165. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1166. return 0;
  1167. }
  1168. if (hpke_aead_dec(ctx, seqbuf, aad, aadlen, ct, ctlen, pt, ptlen) != 1) {
  1169. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1170. OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
  1171. return 0;
  1172. }
  1173. ctx->seq++;
  1174. OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
  1175. return 1;
  1176. }
  1177. int OSSL_HPKE_export(OSSL_HPKE_CTX *ctx,
  1178. unsigned char *secret, size_t secretlen,
  1179. const unsigned char *label, size_t labellen)
  1180. {
  1181. int erv = 0;
  1182. EVP_KDF_CTX *kctx = NULL;
  1183. unsigned char suitebuf[6];
  1184. const char *mdname = NULL;
  1185. const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
  1186. if (ctx == NULL || secret == NULL || secretlen == 0) {
  1187. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1188. return 0;
  1189. }
  1190. if (labellen > OSSL_HPKE_MAX_PARMLEN) {
  1191. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1192. return 0;
  1193. }
  1194. if (labellen > 0 && label == NULL) {
  1195. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1196. return 0;
  1197. }
  1198. if (ctx->exportersec == NULL) {
  1199. ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
  1200. return 0;
  1201. }
  1202. kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id);
  1203. if (kdf_info == NULL) {
  1204. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1205. return 0;
  1206. }
  1207. mdname = kdf_info->mdname;
  1208. kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
  1209. if (kctx == NULL) {
  1210. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1211. return 0;
  1212. }
  1213. /* full suiteid as per RFC9180 sec 5.3 */
  1214. suitebuf[0] = ctx->suite.kem_id / 256;
  1215. suitebuf[1] = ctx->suite.kem_id % 256;
  1216. suitebuf[2] = ctx->suite.kdf_id / 256;
  1217. suitebuf[3] = ctx->suite.kdf_id % 256;
  1218. suitebuf[4] = ctx->suite.aead_id / 256;
  1219. suitebuf[5] = ctx->suite.aead_id % 256;
  1220. erv = ossl_hpke_labeled_expand(kctx, secret, secretlen,
  1221. ctx->exportersec, ctx->exporterseclen,
  1222. OSSL_HPKE_SEC51LABEL,
  1223. suitebuf, sizeof(suitebuf),
  1224. OSSL_HPKE_EXP_SEC_LABEL,
  1225. label, labellen);
  1226. EVP_KDF_CTX_free(kctx);
  1227. if (erv != 1)
  1228. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1229. return erv;
  1230. }
  1231. int OSSL_HPKE_keygen(OSSL_HPKE_SUITE suite,
  1232. unsigned char *pub, size_t *publen, EVP_PKEY **priv,
  1233. const unsigned char *ikm, size_t ikmlen,
  1234. OSSL_LIB_CTX *libctx, const char *propq)
  1235. {
  1236. int erv = 0; /* Our error return value - 1 is success */
  1237. EVP_PKEY_CTX *pctx = NULL;
  1238. EVP_PKEY *skR = NULL;
  1239. const OSSL_HPKE_KEM_INFO *kem_info = NULL;
  1240. OSSL_PARAM params[3], *p = params;
  1241. if (pub == NULL || publen == NULL || *publen == 0 || priv == NULL) {
  1242. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1243. return 0;
  1244. }
  1245. if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1) {
  1246. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1247. return 0;
  1248. }
  1249. if ((ikmlen > 0 && ikm == NULL)
  1250. || (ikmlen == 0 && ikm != NULL)
  1251. || ikmlen > OSSL_HPKE_MAX_PARMLEN) {
  1252. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1253. return 0;
  1254. }
  1255. if (hpke_kem_id_nist_curve(suite.kem_id) == 1) {
  1256. *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
  1257. (char *)kem_info->groupname, 0);
  1258. pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
  1259. } else {
  1260. pctx = EVP_PKEY_CTX_new_from_name(libctx, kem_info->keytype, propq);
  1261. }
  1262. if (pctx == NULL
  1263. || EVP_PKEY_keygen_init(pctx) <= 0) {
  1264. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1265. goto err;
  1266. }
  1267. if (ikm != NULL)
  1268. *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
  1269. (char *)ikm, ikmlen);
  1270. *p = OSSL_PARAM_construct_end();
  1271. if (EVP_PKEY_CTX_set_params(pctx, params) <= 0) {
  1272. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1273. goto err;
  1274. }
  1275. if (EVP_PKEY_generate(pctx, &skR) <= 0) {
  1276. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1277. goto err;
  1278. }
  1279. EVP_PKEY_CTX_free(pctx);
  1280. pctx = NULL;
  1281. if (EVP_PKEY_get_octet_string_param(skR, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
  1282. pub, *publen, publen) != 1) {
  1283. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1284. goto err;
  1285. }
  1286. *priv = skR;
  1287. erv = 1;
  1288. err:
  1289. if (erv != 1)
  1290. EVP_PKEY_free(skR);
  1291. EVP_PKEY_CTX_free(pctx);
  1292. return erv;
  1293. }
  1294. int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite)
  1295. {
  1296. return hpke_suite_check(suite, NULL, NULL, NULL);
  1297. }
  1298. int OSSL_HPKE_get_grease_value(const OSSL_HPKE_SUITE *suite_in,
  1299. OSSL_HPKE_SUITE *suite,
  1300. unsigned char *enc, size_t *enclen,
  1301. unsigned char *ct, size_t ctlen,
  1302. OSSL_LIB_CTX *libctx, const char *propq)
  1303. {
  1304. OSSL_HPKE_SUITE chosen;
  1305. size_t plen = 0;
  1306. const OSSL_HPKE_KEM_INFO *kem_info = NULL;
  1307. const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
  1308. EVP_PKEY *fakepriv = NULL;
  1309. if (enc == NULL || enclen == 0
  1310. || ct == NULL || ctlen == 0 || suite == NULL) {
  1311. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  1312. return 0;
  1313. }
  1314. if (suite_in == NULL) {
  1315. /* choose a random suite */
  1316. if (hpke_random_suite(libctx, propq, &chosen) != 1) {
  1317. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1318. goto err;
  1319. }
  1320. } else {
  1321. chosen = *suite_in;
  1322. }
  1323. if (hpke_suite_check(chosen, &kem_info, NULL, &aead_info) != 1) {
  1324. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1325. goto err;
  1326. }
  1327. *suite = chosen;
  1328. /* make sure room for tag and one plaintext octet */
  1329. if (aead_info->taglen >= ctlen) {
  1330. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1331. goto err;
  1332. }
  1333. /* publen */
  1334. plen = kem_info->Npk;
  1335. if (plen > *enclen) {
  1336. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1337. goto err;
  1338. }
  1339. /*
  1340. * In order for our enc to look good for sure, we generate and then
  1341. * delete a real key for that curve - bit OTT but it ensures we do
  1342. * get the encoding right (e.g. 0x04 as 1st octet for NIST curves in
  1343. * uncompressed form) and that the value really does map to a point on
  1344. * the relevant curve.
  1345. */
  1346. if (OSSL_HPKE_keygen(chosen, enc, enclen, &fakepriv, NULL, 0,
  1347. libctx, propq) != 1) {
  1348. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1349. goto err;
  1350. }
  1351. EVP_PKEY_free(fakepriv);
  1352. if (RAND_bytes_ex(libctx, ct, ctlen, 0) <= 0) {
  1353. ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
  1354. goto err;
  1355. }
  1356. return 1;
  1357. err:
  1358. return 0;
  1359. }
  1360. int OSSL_HPKE_str2suite(const char *str, OSSL_HPKE_SUITE *suite)
  1361. {
  1362. return ossl_hpke_str2suite(str, suite);
  1363. }
  1364. size_t OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite, size_t clearlen)
  1365. {
  1366. size_t enclen = 0;
  1367. size_t cipherlen = 0;
  1368. if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
  1369. return 0;
  1370. return cipherlen;
  1371. }
  1372. size_t OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite)
  1373. {
  1374. size_t enclen = 0;
  1375. size_t cipherlen = 0;
  1376. size_t clearlen = 16;
  1377. if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
  1378. return 0;
  1379. return enclen;
  1380. }
  1381. size_t OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite)
  1382. {
  1383. const OSSL_HPKE_KEM_INFO *kem_info = NULL;
  1384. if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1)
  1385. return 0;
  1386. if (kem_info == NULL)
  1387. return 0;
  1388. return kem_info->Nsk;
  1389. }