Coverage Report

Created: 2023-04-12 06:22

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