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