hpke_util.c 18 KB

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