hpke_util.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. /*
  2. * Copyright 2022-2023 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. #include <string.h>
  10. #include <openssl/core_names.h>
  11. #include <openssl/kdf.h>
  12. #include <openssl/params.h>
  13. #include <openssl/err.h>
  14. #include <openssl/proverr.h>
  15. #include <openssl/hpke.h>
  16. #include <openssl/sha.h>
  17. #include <openssl/rand.h>
  18. #include "crypto/ecx.h"
  19. #include "internal/hpke_util.h"
  20. #include "internal/packet.h"
  21. #include "internal/nelem.h"
  22. /*
  23. * Delimiter used in OSSL_HPKE_str2suite
  24. */
  25. #define OSSL_HPKE_STR_DELIMCHAR ','
  26. /*
  27. * table with identifier and synonym strings
  28. * right now, there are 4 synonyms for each - a name, a hex string
  29. * a hex string with a leading zero and a decimal string - more
  30. * could be added but that seems like enough
  31. */
  32. typedef struct {
  33. uint16_t id;
  34. char *synonyms[4];
  35. } synonymttab_t;
  36. /* max length of string we'll try map to a suite */
  37. #define OSSL_HPKE_MAX_SUITESTR 38
  38. /* Define HPKE labels from RFC9180 in hex for EBCDIC compatibility */
  39. /* ASCII: "HPKE-v1", in hex for EBCDIC compatibility */
  40. static const char LABEL_HPKEV1[] = "\x48\x50\x4B\x45\x2D\x76\x31";
  41. /*
  42. * Note that if additions are made to the set of IANA codepoints
  43. * and the tables below, corresponding additions should also be
  44. * made to the synonymtab tables a little further down so that
  45. * OSSL_HPKE_str2suite() continues to function correctly.
  46. *
  47. * The canonical place to check for IANA registered codepoints
  48. * is: https://www.iana.org/assignments/hpke/hpke.xhtml
  49. */
  50. /*
  51. * @brief table of KEMs
  52. * See RFC9180 Section 7.1 "Table 2 KEM IDs"
  53. */
  54. static const OSSL_HPKE_KEM_INFO hpke_kem_tab[] = {
  55. #ifndef OPENSSL_NO_EC
  56. { OSSL_HPKE_KEM_ID_P256, "EC", OSSL_HPKE_KEMSTR_P256,
  57. LN_sha256, SHA256_DIGEST_LENGTH, 65, 65, 32, 0xFF },
  58. { OSSL_HPKE_KEM_ID_P384, "EC", OSSL_HPKE_KEMSTR_P384,
  59. LN_sha384, SHA384_DIGEST_LENGTH, 97, 97, 48, 0xFF },
  60. { OSSL_HPKE_KEM_ID_P521, "EC", OSSL_HPKE_KEMSTR_P521,
  61. LN_sha512, SHA512_DIGEST_LENGTH, 133, 133, 66, 0x01 },
  62. # ifndef OPENSSL_NO_ECX
  63. { OSSL_HPKE_KEM_ID_X25519, OSSL_HPKE_KEMSTR_X25519, NULL,
  64. LN_sha256, SHA256_DIGEST_LENGTH,
  65. X25519_KEYLEN, X25519_KEYLEN, X25519_KEYLEN, 0x00 },
  66. { OSSL_HPKE_KEM_ID_X448, OSSL_HPKE_KEMSTR_X448, NULL,
  67. LN_sha512, SHA512_DIGEST_LENGTH,
  68. X448_KEYLEN, X448_KEYLEN, X448_KEYLEN, 0x00 }
  69. # endif
  70. #else
  71. { OSSL_HPKE_KEM_ID_RESERVED, NULL, NULL, NULL, 0, 0, 0, 0, 0x00 }
  72. #endif
  73. };
  74. /*
  75. * @brief table of AEADs
  76. * See RFC9180 Section 7.2 "Table 3 KDF IDs"
  77. */
  78. static const OSSL_HPKE_AEAD_INFO hpke_aead_tab[] = {
  79. { OSSL_HPKE_AEAD_ID_AES_GCM_128, LN_aes_128_gcm, 16, 16,
  80. OSSL_HPKE_MAX_NONCELEN },
  81. { OSSL_HPKE_AEAD_ID_AES_GCM_256, LN_aes_256_gcm, 16, 32,
  82. OSSL_HPKE_MAX_NONCELEN },
  83. #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
  84. { OSSL_HPKE_AEAD_ID_CHACHA_POLY1305, LN_chacha20_poly1305, 16, 32,
  85. OSSL_HPKE_MAX_NONCELEN },
  86. #endif
  87. { OSSL_HPKE_AEAD_ID_EXPORTONLY, NULL, 0, 0, 0 }
  88. };
  89. /*
  90. * @brief table of KDFs
  91. * See RFC9180 Section 7.3 "Table 5 AEAD IDs"
  92. */
  93. static const OSSL_HPKE_KDF_INFO hpke_kdf_tab[] = {
  94. { OSSL_HPKE_KDF_ID_HKDF_SHA256, LN_sha256, SHA256_DIGEST_LENGTH },
  95. { OSSL_HPKE_KDF_ID_HKDF_SHA384, LN_sha384, SHA384_DIGEST_LENGTH },
  96. { OSSL_HPKE_KDF_ID_HKDF_SHA512, LN_sha512, SHA512_DIGEST_LENGTH }
  97. };
  98. /**
  99. * Synonym tables for KEMs, KDFs and AEADs: idea is to allow
  100. * mapping strings to suites with a little flexibility in terms
  101. * of allowing a name or a couple of forms of number (for
  102. * the IANA codepoint). If new IANA codepoints are allocated
  103. * then these tables should be updated at the same time as the
  104. * others above.
  105. *
  106. * The function to use these is ossl_hpke_str2suite() further down
  107. * this file and shouldn't need modification so long as the table
  108. * sizes (i.e. allow exactly 4 synonyms) don't change.
  109. */
  110. static const synonymttab_t kemstrtab[] = {
  111. {OSSL_HPKE_KEM_ID_P256,
  112. {OSSL_HPKE_KEMSTR_P256, "0x10", "0x10", "16" }},
  113. {OSSL_HPKE_KEM_ID_P384,
  114. {OSSL_HPKE_KEMSTR_P384, "0x11", "0x11", "17" }},
  115. {OSSL_HPKE_KEM_ID_P521,
  116. {OSSL_HPKE_KEMSTR_P521, "0x12", "0x12", "18" }},
  117. # ifndef OPENSSL_NO_ECX
  118. {OSSL_HPKE_KEM_ID_X25519,
  119. {OSSL_HPKE_KEMSTR_X25519, "0x20", "0x20", "32" }},
  120. {OSSL_HPKE_KEM_ID_X448,
  121. {OSSL_HPKE_KEMSTR_X448, "0x21", "0x21", "33" }}
  122. # endif
  123. };
  124. static const synonymttab_t kdfstrtab[] = {
  125. {OSSL_HPKE_KDF_ID_HKDF_SHA256,
  126. {OSSL_HPKE_KDFSTR_256, "0x1", "0x01", "1"}},
  127. {OSSL_HPKE_KDF_ID_HKDF_SHA384,
  128. {OSSL_HPKE_KDFSTR_384, "0x2", "0x02", "2"}},
  129. {OSSL_HPKE_KDF_ID_HKDF_SHA512,
  130. {OSSL_HPKE_KDFSTR_512, "0x3", "0x03", "3"}}
  131. };
  132. static const synonymttab_t aeadstrtab[] = {
  133. {OSSL_HPKE_AEAD_ID_AES_GCM_128,
  134. {OSSL_HPKE_AEADSTR_AES128GCM, "0x1", "0x01", "1"}},
  135. {OSSL_HPKE_AEAD_ID_AES_GCM_256,
  136. {OSSL_HPKE_AEADSTR_AES256GCM, "0x2", "0x02", "2"}},
  137. {OSSL_HPKE_AEAD_ID_CHACHA_POLY1305,
  138. {OSSL_HPKE_AEADSTR_CP, "0x3", "0x03", "3"}},
  139. {OSSL_HPKE_AEAD_ID_EXPORTONLY,
  140. {OSSL_HPKE_AEADSTR_EXP, "ff", "0xff", "255"}}
  141. };
  142. /* Return an object containing KEM constants associated with a EC curve name */
  143. const OSSL_HPKE_KEM_INFO *ossl_HPKE_KEM_INFO_find_curve(const char *curve)
  144. {
  145. int i, sz = OSSL_NELEM(hpke_kem_tab);
  146. for (i = 0; i < sz; ++i) {
  147. const char *group = hpke_kem_tab[i].groupname;
  148. if (group == NULL)
  149. group = hpke_kem_tab[i].keytype;
  150. if (OPENSSL_strcasecmp(curve, group) == 0)
  151. return &hpke_kem_tab[i];
  152. }
  153. ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE);
  154. return NULL;
  155. }
  156. const OSSL_HPKE_KEM_INFO *ossl_HPKE_KEM_INFO_find_id(uint16_t kemid)
  157. {
  158. int i, sz = OSSL_NELEM(hpke_kem_tab);
  159. /*
  160. * this check can happen if we're in a no-ec build and there are no
  161. * KEMS available
  162. */
  163. if (kemid == OSSL_HPKE_KEM_ID_RESERVED) {
  164. ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE);
  165. return NULL;
  166. }
  167. for (i = 0; i != sz; ++i) {
  168. if (hpke_kem_tab[i].kem_id == kemid)
  169. return &hpke_kem_tab[i];
  170. }
  171. ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE);
  172. return NULL;
  173. }
  174. const OSSL_HPKE_KEM_INFO *ossl_HPKE_KEM_INFO_find_random(OSSL_LIB_CTX *ctx)
  175. {
  176. unsigned char rval = 0;
  177. int sz = OSSL_NELEM(hpke_kem_tab);
  178. if (RAND_bytes_ex(ctx, &rval, sizeof(rval), 0) <= 0)
  179. return NULL;
  180. return &hpke_kem_tab[rval % sz];
  181. }
  182. const OSSL_HPKE_KDF_INFO *ossl_HPKE_KDF_INFO_find_id(uint16_t kdfid)
  183. {
  184. int i, sz = OSSL_NELEM(hpke_kdf_tab);
  185. for (i = 0; i != sz; ++i) {
  186. if (hpke_kdf_tab[i].kdf_id == kdfid)
  187. return &hpke_kdf_tab[i];
  188. }
  189. ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KDF);
  190. return NULL;
  191. }
  192. const OSSL_HPKE_KDF_INFO *ossl_HPKE_KDF_INFO_find_random(OSSL_LIB_CTX *ctx)
  193. {
  194. unsigned char rval = 0;
  195. int sz = OSSL_NELEM(hpke_kdf_tab);
  196. if (RAND_bytes_ex(ctx, &rval, sizeof(rval), 0) <= 0)
  197. return NULL;
  198. return &hpke_kdf_tab[rval % sz];
  199. }
  200. const OSSL_HPKE_AEAD_INFO *ossl_HPKE_AEAD_INFO_find_id(uint16_t aeadid)
  201. {
  202. int i, sz = OSSL_NELEM(hpke_aead_tab);
  203. for (i = 0; i != sz; ++i) {
  204. if (hpke_aead_tab[i].aead_id == aeadid)
  205. return &hpke_aead_tab[i];
  206. }
  207. ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_AEAD);
  208. return NULL;
  209. }
  210. const OSSL_HPKE_AEAD_INFO *ossl_HPKE_AEAD_INFO_find_random(OSSL_LIB_CTX *ctx)
  211. {
  212. unsigned char rval = 0;
  213. /* the minus 1 below is so we don't pick the EXPORTONLY codepoint */
  214. int sz = OSSL_NELEM(hpke_aead_tab) - 1;
  215. if (RAND_bytes_ex(ctx, &rval, sizeof(rval), 0) <= 0)
  216. return NULL;
  217. return &hpke_aead_tab[rval % sz];
  218. }
  219. static int kdf_derive(EVP_KDF_CTX *kctx,
  220. unsigned char *out, size_t outlen, int mode,
  221. const unsigned char *salt, size_t saltlen,
  222. const unsigned char *ikm, size_t ikmlen,
  223. const unsigned char *info, size_t infolen)
  224. {
  225. int ret;
  226. OSSL_PARAM params[5], *p = params;
  227. *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
  228. if (salt != NULL)
  229. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
  230. (char *)salt, saltlen);
  231. if (ikm != NULL)
  232. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
  233. (char *)ikm, ikmlen);
  234. if (info != NULL)
  235. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
  236. (char *)info, infolen);
  237. *p = OSSL_PARAM_construct_end();
  238. ret = EVP_KDF_derive(kctx, out, outlen, params) > 0;
  239. if (!ret)
  240. ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION);
  241. return ret;
  242. }
  243. int ossl_hpke_kdf_extract(EVP_KDF_CTX *kctx,
  244. unsigned char *prk, size_t prklen,
  245. const unsigned char *salt, size_t saltlen,
  246. const unsigned char *ikm, size_t ikmlen)
  247. {
  248. return kdf_derive(kctx, prk, prklen, EVP_KDF_HKDF_MODE_EXTRACT_ONLY,
  249. salt, saltlen, ikm, ikmlen, NULL, 0);
  250. }
  251. /* Common code to perform a HKDF expand */
  252. int ossl_hpke_kdf_expand(EVP_KDF_CTX *kctx,
  253. unsigned char *okm, size_t okmlen,
  254. const unsigned char *prk, size_t prklen,
  255. const unsigned char *info, size_t infolen)
  256. {
  257. return kdf_derive(kctx, okm, okmlen, EVP_KDF_HKDF_MODE_EXPAND_ONLY,
  258. NULL, 0, prk, prklen, info, infolen);
  259. }
  260. /*
  261. * See RFC 9180 Section 4 LabelExtract()
  262. */
  263. int ossl_hpke_labeled_extract(EVP_KDF_CTX *kctx,
  264. unsigned char *prk, size_t prklen,
  265. const unsigned char *salt, size_t saltlen,
  266. const char *protocol_label,
  267. const unsigned char *suiteid, size_t suiteidlen,
  268. const char *label,
  269. const unsigned char *ikm, size_t ikmlen)
  270. {
  271. int ret = 0;
  272. size_t label_hpkev1len = 0;
  273. size_t protocol_labellen = 0;
  274. size_t labellen = 0;
  275. size_t labeled_ikmlen = 0;
  276. unsigned char *labeled_ikm = NULL;
  277. WPACKET pkt;
  278. label_hpkev1len = strlen(LABEL_HPKEV1);
  279. protocol_labellen = strlen(protocol_label);
  280. labellen = strlen(label);
  281. labeled_ikmlen = label_hpkev1len + protocol_labellen
  282. + suiteidlen + labellen + ikmlen;
  283. labeled_ikm = OPENSSL_malloc(labeled_ikmlen);
  284. if (labeled_ikm == NULL)
  285. return 0;
  286. /* labeled_ikm = concat("HPKE-v1", suiteid, label, ikm) */
  287. if (!WPACKET_init_static_len(&pkt, labeled_ikm, labeled_ikmlen, 0)
  288. || !WPACKET_memcpy(&pkt, LABEL_HPKEV1, label_hpkev1len)
  289. || !WPACKET_memcpy(&pkt, protocol_label, protocol_labellen)
  290. || !WPACKET_memcpy(&pkt, suiteid, suiteidlen)
  291. || !WPACKET_memcpy(&pkt, label, labellen)
  292. || !WPACKET_memcpy(&pkt, ikm, ikmlen)
  293. || !WPACKET_get_total_written(&pkt, &labeled_ikmlen)
  294. || !WPACKET_finish(&pkt)) {
  295. ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
  296. goto end;
  297. }
  298. ret = ossl_hpke_kdf_extract(kctx, prk, prklen, salt, saltlen,
  299. labeled_ikm, labeled_ikmlen);
  300. end:
  301. WPACKET_cleanup(&pkt);
  302. OPENSSL_cleanse(labeled_ikm, labeled_ikmlen);
  303. OPENSSL_free(labeled_ikm);
  304. return ret;
  305. }
  306. /*
  307. * See RFC 9180 Section 4 LabelExpand()
  308. */
  309. int ossl_hpke_labeled_expand(EVP_KDF_CTX *kctx,
  310. unsigned char *okm, size_t okmlen,
  311. const unsigned char *prk, size_t prklen,
  312. const char *protocol_label,
  313. const unsigned char *suiteid, size_t suiteidlen,
  314. const char *label,
  315. const unsigned char *info, size_t infolen)
  316. {
  317. int ret = 0;
  318. size_t label_hpkev1len = 0;
  319. size_t protocol_labellen = 0;
  320. size_t labellen = 0;
  321. size_t labeled_infolen = 0;
  322. unsigned char *labeled_info = NULL;
  323. WPACKET pkt;
  324. label_hpkev1len = strlen(LABEL_HPKEV1);
  325. protocol_labellen = strlen(protocol_label);
  326. labellen = strlen(label);
  327. labeled_infolen = 2 + okmlen + prklen + label_hpkev1len
  328. + protocol_labellen + suiteidlen + labellen + infolen;
  329. labeled_info = OPENSSL_malloc(labeled_infolen);
  330. if (labeled_info == NULL)
  331. return 0;
  332. /* labeled_info = concat(okmlen, "HPKE-v1", suiteid, label, info) */
  333. if (!WPACKET_init_static_len(&pkt, labeled_info, labeled_infolen, 0)
  334. || !WPACKET_put_bytes_u16(&pkt, okmlen)
  335. || !WPACKET_memcpy(&pkt, LABEL_HPKEV1, label_hpkev1len)
  336. || !WPACKET_memcpy(&pkt, protocol_label, protocol_labellen)
  337. || !WPACKET_memcpy(&pkt, suiteid, suiteidlen)
  338. || !WPACKET_memcpy(&pkt, label, labellen)
  339. || !WPACKET_memcpy(&pkt, info, infolen)
  340. || !WPACKET_get_total_written(&pkt, &labeled_infolen)
  341. || !WPACKET_finish(&pkt)) {
  342. ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
  343. goto end;
  344. }
  345. ret = ossl_hpke_kdf_expand(kctx, okm, okmlen,
  346. prk, prklen, labeled_info, labeled_infolen);
  347. end:
  348. WPACKET_cleanup(&pkt);
  349. OPENSSL_free(labeled_info);
  350. return ret;
  351. }
  352. /* Common code to create a HKDF ctx */
  353. EVP_KDF_CTX *ossl_kdf_ctx_create(const char *kdfname, const char *mdname,
  354. OSSL_LIB_CTX *libctx, const char *propq)
  355. {
  356. EVP_KDF *kdf;
  357. EVP_KDF_CTX *kctx = NULL;
  358. kdf = EVP_KDF_fetch(libctx, kdfname, propq);
  359. if (kdf == NULL) {
  360. ERR_raise(ERR_LIB_CRYPTO, ERR_R_FETCH_FAILED);
  361. return NULL;
  362. }
  363. kctx = EVP_KDF_CTX_new(kdf);
  364. EVP_KDF_free(kdf);
  365. if (kctx != NULL && mdname != NULL) {
  366. OSSL_PARAM params[3], *p = params;
  367. if (mdname != NULL)
  368. *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
  369. (char *)mdname, 0);
  370. if (propq != NULL)
  371. *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_PROPERTIES,
  372. (char *)propq, 0);
  373. *p = OSSL_PARAM_construct_end();
  374. if (EVP_KDF_CTX_set_params(kctx, params) <= 0) {
  375. EVP_KDF_CTX_free(kctx);
  376. return NULL;
  377. }
  378. }
  379. return kctx;
  380. }
  381. /*
  382. * @brief look for a label into the synonym tables, and return its id
  383. * @param st is the string value
  384. * @param synp is the synonyms labels array
  385. * @param arrsize is the previous array size
  386. * @return 0 when not found, else the matching item id.
  387. */
  388. static uint16_t synonyms_name2id(const char *st, const synonymttab_t *synp,
  389. size_t arrsize)
  390. {
  391. size_t i, j;
  392. for (i = 0; i < arrsize; ++i) {
  393. for (j = 0; j < OSSL_NELEM(synp[i].synonyms); ++j) {
  394. if (OPENSSL_strcasecmp(st, synp[i].synonyms[j]) == 0)
  395. return synp[i].id;
  396. }
  397. }
  398. return 0;
  399. }
  400. /*
  401. * @brief map a string to a HPKE suite based on synonym tables
  402. * @param str is the string value
  403. * @param suite is the resulting suite
  404. * @return 1 for success, otherwise failure
  405. */
  406. int ossl_hpke_str2suite(const char *suitestr, OSSL_HPKE_SUITE *suite)
  407. {
  408. uint16_t kem = 0, kdf = 0, aead = 0;
  409. char *st = NULL, *instrcp = NULL;
  410. size_t inplen;
  411. int labels = 0, result = 0;
  412. int delim_count = 0;
  413. if (suitestr == NULL || suitestr[0] == 0x00 || suite == NULL) {
  414. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
  415. return 0;
  416. }
  417. inplen = OPENSSL_strnlen(suitestr, OSSL_HPKE_MAX_SUITESTR);
  418. if (inplen >= OSSL_HPKE_MAX_SUITESTR) {
  419. ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
  420. return 0;
  421. }
  422. /*
  423. * we don't want a delimiter at the end of the string;
  424. * strtok_r/s() doesn't care about that, so we should
  425. */
  426. if (suitestr[inplen - 1] == OSSL_HPKE_STR_DELIMCHAR)
  427. return 0;
  428. /* We want exactly two delimiters in the input string */
  429. for (st = (char *)suitestr; *st != '\0'; st++) {
  430. if (*st == OSSL_HPKE_STR_DELIMCHAR)
  431. delim_count++;
  432. }
  433. if (delim_count != 2)
  434. return 0;
  435. /* Duplicate `suitestr` to allow its parsing */
  436. instrcp = OPENSSL_memdup(suitestr, inplen + 1);
  437. if (instrcp == NULL)
  438. goto fail;
  439. /* See if it contains a mix of our strings and numbers */
  440. st = instrcp;
  441. while (st != NULL && labels < 3) {
  442. char *cp = strchr(st, OSSL_HPKE_STR_DELIMCHAR);
  443. /* add a NUL like strtok would if we're not at the end */
  444. if (cp != NULL)
  445. *cp = '\0';
  446. /* check if string is known or number and if so handle appropriately */
  447. if (labels == 0
  448. && (kem = synonyms_name2id(st, kemstrtab,
  449. OSSL_NELEM(kemstrtab))) == 0)
  450. goto fail;
  451. else if (labels == 1
  452. && (kdf = synonyms_name2id(st, kdfstrtab,
  453. OSSL_NELEM(kdfstrtab))) == 0)
  454. goto fail;
  455. else if (labels == 2
  456. && (aead = synonyms_name2id(st, aeadstrtab,
  457. OSSL_NELEM(aeadstrtab))) == 0)
  458. goto fail;
  459. if (cp == NULL)
  460. st = NULL;
  461. else
  462. st = cp + 1;
  463. ++labels;
  464. }
  465. if (st != NULL || labels != 3)
  466. goto fail;
  467. suite->kem_id = kem;
  468. suite->kdf_id = kdf;
  469. suite->aead_id = aead;
  470. result = 1;
  471. fail:
  472. OPENSSL_free(instrcp);
  473. return result;
  474. }