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