/src/openssl32/crypto/hpke/hpke_util.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #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 | 0 | #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 | 0 | { |
158 | 0 | int i, sz = OSSL_NELEM(hpke_kem_tab); |
159 | |
|
160 | 0 | for (i = 0; i < sz; ++i) { |
161 | 0 | const char *group = hpke_kem_tab[i].groupname; |
162 | |
|
163 | 0 | if (group == NULL) |
164 | 0 | group = hpke_kem_tab[i].keytype; |
165 | 0 | if (OPENSSL_strcasecmp(curve, group) == 0) |
166 | 0 | return &hpke_kem_tab[i]; |
167 | 0 | } |
168 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE); |
169 | 0 | return NULL; |
170 | 0 | } |
171 | | |
172 | | const OSSL_HPKE_KEM_INFO *ossl_HPKE_KEM_INFO_find_id(uint16_t kemid) |
173 | 0 | { |
174 | 0 | 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 | 0 | if (kemid == OSSL_HPKE_KEM_ID_RESERVED) { |
181 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE); |
182 | 0 | return NULL; |
183 | 0 | } |
184 | 0 | for (i = 0; i != sz; ++i) { |
185 | 0 | if (hpke_kem_tab[i].kem_id == kemid) |
186 | 0 | return &hpke_kem_tab[i]; |
187 | 0 | } |
188 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE); |
189 | 0 | return NULL; |
190 | 0 | } |
191 | | |
192 | | const OSSL_HPKE_KEM_INFO *ossl_HPKE_KEM_INFO_find_random(OSSL_LIB_CTX *ctx) |
193 | 0 | { |
194 | 0 | uint32_t rval = 0; |
195 | 0 | int err = 0; |
196 | 0 | size_t sz = OSSL_NELEM(hpke_kem_tab); |
197 | |
|
198 | 0 | rval = ossl_rand_uniform_uint32(ctx, sz, &err); |
199 | 0 | return (err == 1 ? NULL : &hpke_kem_tab[rval]); |
200 | 0 | } |
201 | | |
202 | | const OSSL_HPKE_KDF_INFO *ossl_HPKE_KDF_INFO_find_id(uint16_t kdfid) |
203 | 0 | { |
204 | 0 | int i, sz = OSSL_NELEM(hpke_kdf_tab); |
205 | |
|
206 | 0 | for (i = 0; i != sz; ++i) { |
207 | 0 | if (hpke_kdf_tab[i].kdf_id == kdfid) |
208 | 0 | return &hpke_kdf_tab[i]; |
209 | 0 | } |
210 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KDF); |
211 | 0 | return NULL; |
212 | 0 | } |
213 | | |
214 | | const OSSL_HPKE_KDF_INFO *ossl_HPKE_KDF_INFO_find_random(OSSL_LIB_CTX *ctx) |
215 | 0 | { |
216 | 0 | uint32_t rval = 0; |
217 | 0 | int err = 0; |
218 | 0 | size_t sz = OSSL_NELEM(hpke_kdf_tab); |
219 | |
|
220 | 0 | rval = ossl_rand_uniform_uint32(ctx, sz, &err); |
221 | 0 | return (err == 1 ? NULL : &hpke_kdf_tab[rval]); |
222 | 0 | } |
223 | | |
224 | | const OSSL_HPKE_AEAD_INFO *ossl_HPKE_AEAD_INFO_find_id(uint16_t aeadid) |
225 | 0 | { |
226 | 0 | int i, sz = OSSL_NELEM(hpke_aead_tab); |
227 | |
|
228 | 0 | for (i = 0; i != sz; ++i) { |
229 | 0 | if (hpke_aead_tab[i].aead_id == aeadid) |
230 | 0 | return &hpke_aead_tab[i]; |
231 | 0 | } |
232 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_AEAD); |
233 | 0 | return NULL; |
234 | 0 | } |
235 | | |
236 | | const OSSL_HPKE_AEAD_INFO *ossl_HPKE_AEAD_INFO_find_random(OSSL_LIB_CTX *ctx) |
237 | 0 | { |
238 | 0 | uint32_t rval = 0; |
239 | 0 | int err = 0; |
240 | | /* the minus 1 below is so we don't pick the EXPORTONLY codepoint */ |
241 | 0 | size_t sz = OSSL_NELEM(hpke_aead_tab) - 1; |
242 | |
|
243 | 0 | rval = ossl_rand_uniform_uint32(ctx, sz, &err); |
244 | 0 | return (err == 1 ? NULL : &hpke_aead_tab[rval]); |
245 | 0 | } |
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 | 0 | { |
253 | 0 | int ret; |
254 | 0 | OSSL_PARAM params[5], *p = params; |
255 | |
|
256 | 0 | *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode); |
257 | 0 | if (salt != NULL) |
258 | 0 | *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, |
259 | 0 | (char *)salt, saltlen); |
260 | 0 | if (ikm != NULL) |
261 | 0 | *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, |
262 | 0 | (char *)ikm, ikmlen); |
263 | 0 | if (info != NULL) |
264 | 0 | *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, |
265 | 0 | (char *)info, infolen); |
266 | 0 | *p = OSSL_PARAM_construct_end(); |
267 | 0 | ret = EVP_KDF_derive(kctx, out, outlen, params) > 0; |
268 | 0 | if (!ret) |
269 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); |
270 | 0 | return ret; |
271 | 0 | } |
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 | 0 | { |
278 | 0 | return kdf_derive(kctx, prk, prklen, EVP_KDF_HKDF_MODE_EXTRACT_ONLY, |
279 | 0 | salt, saltlen, ikm, ikmlen, NULL, 0); |
280 | 0 | } |
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 | 0 | { |
288 | 0 | return kdf_derive(kctx, okm, okmlen, EVP_KDF_HKDF_MODE_EXPAND_ONLY, |
289 | 0 | NULL, 0, prk, prklen, info, infolen); |
290 | 0 | } |
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 | 0 | { |
303 | 0 | int ret = 0; |
304 | 0 | size_t label_hpkev1len = 0; |
305 | 0 | size_t protocol_labellen = 0; |
306 | 0 | size_t labellen = 0; |
307 | 0 | size_t labeled_ikmlen = 0; |
308 | 0 | unsigned char *labeled_ikm = NULL; |
309 | 0 | WPACKET pkt; |
310 | |
|
311 | 0 | label_hpkev1len = strlen(LABEL_HPKEV1); |
312 | 0 | protocol_labellen = strlen(protocol_label); |
313 | 0 | labellen = strlen(label); |
314 | 0 | labeled_ikmlen = label_hpkev1len + protocol_labellen |
315 | 0 | + suiteidlen + labellen + ikmlen; |
316 | 0 | labeled_ikm = OPENSSL_malloc(labeled_ikmlen); |
317 | 0 | if (labeled_ikm == NULL) |
318 | 0 | return 0; |
319 | | |
320 | | /* labeled_ikm = concat("HPKE-v1", suiteid, label, ikm) */ |
321 | 0 | if (!WPACKET_init_static_len(&pkt, labeled_ikm, labeled_ikmlen, 0) |
322 | 0 | || !WPACKET_memcpy(&pkt, LABEL_HPKEV1, label_hpkev1len) |
323 | 0 | || !WPACKET_memcpy(&pkt, protocol_label, protocol_labellen) |
324 | 0 | || !WPACKET_memcpy(&pkt, suiteid, suiteidlen) |
325 | 0 | || !WPACKET_memcpy(&pkt, label, labellen) |
326 | 0 | || !WPACKET_memcpy(&pkt, ikm, ikmlen) |
327 | 0 | || !WPACKET_get_total_written(&pkt, &labeled_ikmlen) |
328 | 0 | || !WPACKET_finish(&pkt)) { |
329 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); |
330 | 0 | goto end; |
331 | 0 | } |
332 | | |
333 | 0 | ret = ossl_hpke_kdf_extract(kctx, prk, prklen, salt, saltlen, |
334 | 0 | labeled_ikm, labeled_ikmlen); |
335 | 0 | end: |
336 | 0 | WPACKET_cleanup(&pkt); |
337 | 0 | OPENSSL_cleanse(labeled_ikm, labeled_ikmlen); |
338 | 0 | OPENSSL_free(labeled_ikm); |
339 | 0 | return ret; |
340 | 0 | } |
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 | 0 | { |
353 | 0 | int ret = 0; |
354 | 0 | size_t label_hpkev1len = 0; |
355 | 0 | size_t protocol_labellen = 0; |
356 | 0 | size_t labellen = 0; |
357 | 0 | size_t labeled_infolen = 0; |
358 | 0 | unsigned char *labeled_info = NULL; |
359 | 0 | WPACKET pkt; |
360 | |
|
361 | 0 | label_hpkev1len = strlen(LABEL_HPKEV1); |
362 | 0 | protocol_labellen = strlen(protocol_label); |
363 | 0 | labellen = strlen(label); |
364 | 0 | labeled_infolen = 2 + okmlen + prklen + label_hpkev1len |
365 | 0 | + protocol_labellen + suiteidlen + labellen + infolen; |
366 | 0 | labeled_info = OPENSSL_malloc(labeled_infolen); |
367 | 0 | if (labeled_info == NULL) |
368 | 0 | return 0; |
369 | | |
370 | | /* labeled_info = concat(okmlen, "HPKE-v1", suiteid, label, info) */ |
371 | 0 | if (!WPACKET_init_static_len(&pkt, labeled_info, labeled_infolen, 0) |
372 | 0 | || !WPACKET_put_bytes_u16(&pkt, okmlen) |
373 | 0 | || !WPACKET_memcpy(&pkt, LABEL_HPKEV1, label_hpkev1len) |
374 | 0 | || !WPACKET_memcpy(&pkt, protocol_label, protocol_labellen) |
375 | 0 | || !WPACKET_memcpy(&pkt, suiteid, suiteidlen) |
376 | 0 | || !WPACKET_memcpy(&pkt, label, labellen) |
377 | 0 | || !WPACKET_memcpy(&pkt, info, infolen) |
378 | 0 | || !WPACKET_get_total_written(&pkt, &labeled_infolen) |
379 | 0 | || !WPACKET_finish(&pkt)) { |
380 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); |
381 | 0 | goto end; |
382 | 0 | } |
383 | | |
384 | 0 | ret = ossl_hpke_kdf_expand(kctx, okm, okmlen, |
385 | 0 | prk, prklen, labeled_info, labeled_infolen); |
386 | 0 | end: |
387 | 0 | WPACKET_cleanup(&pkt); |
388 | 0 | OPENSSL_free(labeled_info); |
389 | 0 | return ret; |
390 | 0 | } |
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 | 0 | { |
396 | 0 | EVP_KDF *kdf; |
397 | 0 | EVP_KDF_CTX *kctx = NULL; |
398 | |
|
399 | 0 | kdf = EVP_KDF_fetch(libctx, kdfname, propq); |
400 | 0 | if (kdf == NULL) { |
401 | 0 | ERR_raise(ERR_LIB_CRYPTO, ERR_R_FETCH_FAILED); |
402 | 0 | return NULL; |
403 | 0 | } |
404 | 0 | kctx = EVP_KDF_CTX_new(kdf); |
405 | 0 | EVP_KDF_free(kdf); |
406 | 0 | if (kctx != NULL && mdname != NULL) { |
407 | 0 | OSSL_PARAM params[3], *p = params; |
408 | |
|
409 | 0 | if (mdname != NULL) |
410 | 0 | *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, |
411 | 0 | (char *)mdname, 0); |
412 | 0 | if (propq != NULL) |
413 | 0 | *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_PROPERTIES, |
414 | 0 | (char *)propq, 0); |
415 | 0 | *p = OSSL_PARAM_construct_end(); |
416 | 0 | if (EVP_KDF_CTX_set_params(kctx, params) <= 0) { |
417 | 0 | EVP_KDF_CTX_free(kctx); |
418 | 0 | return NULL; |
419 | 0 | } |
420 | 0 | } |
421 | 0 | return kctx; |
422 | 0 | } |
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 | 0 | { |
434 | 0 | size_t i, j; |
435 | |
|
436 | 0 | for (i = 0; i < arrsize; ++i) { |
437 | 0 | for (j = 0; j < OSSL_NELEM(synp[i].synonyms); ++j) { |
438 | 0 | if (OPENSSL_strcasecmp(st, synp[i].synonyms[j]) == 0) |
439 | 0 | return synp[i].id; |
440 | 0 | } |
441 | 0 | } |
442 | 0 | return 0; |
443 | 0 | } |
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 | 0 | { |
453 | 0 | uint16_t kem = 0, kdf = 0, aead = 0; |
454 | 0 | char *st = NULL, *instrcp = NULL; |
455 | 0 | size_t inplen; |
456 | 0 | int labels = 0, result = 0; |
457 | 0 | int delim_count = 0; |
458 | |
|
459 | 0 | if (suitestr == NULL || suitestr[0] == 0x00 || suite == NULL) { |
460 | 0 | ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER); |
461 | 0 | return 0; |
462 | 0 | } |
463 | 0 | inplen = OPENSSL_strnlen(suitestr, OSSL_HPKE_MAX_SUITESTR); |
464 | 0 | if (inplen >= OSSL_HPKE_MAX_SUITESTR) { |
465 | 0 | ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); |
466 | 0 | return 0; |
467 | 0 | } |
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 | 0 | if (suitestr[inplen - 1] == OSSL_HPKE_STR_DELIMCHAR) |
474 | 0 | return 0; |
475 | | /* We want exactly two delimiters in the input string */ |
476 | 0 | for (st = (char *)suitestr; *st != '\0'; st++) { |
477 | 0 | if (*st == OSSL_HPKE_STR_DELIMCHAR) |
478 | 0 | delim_count++; |
479 | 0 | } |
480 | 0 | if (delim_count != 2) |
481 | 0 | return 0; |
482 | | |
483 | | /* Duplicate `suitestr` to allow its parsing */ |
484 | 0 | instrcp = OPENSSL_memdup(suitestr, inplen + 1); |
485 | 0 | if (instrcp == NULL) |
486 | 0 | goto fail; |
487 | | |
488 | | /* See if it contains a mix of our strings and numbers */ |
489 | 0 | st = instrcp; |
490 | |
|
491 | 0 | while (st != NULL && labels < 3) { |
492 | 0 | char *cp = strchr(st, OSSL_HPKE_STR_DELIMCHAR); |
493 | | |
494 | | /* add a NUL like strtok would if we're not at the end */ |
495 | 0 | if (cp != NULL) |
496 | 0 | *cp = '\0'; |
497 | | |
498 | | /* check if string is known or number and if so handle appropriately */ |
499 | 0 | if (labels == 0 |
500 | 0 | && (kem = synonyms_name2id(st, kemstrtab, |
501 | 0 | OSSL_NELEM(kemstrtab))) == 0) |
502 | 0 | goto fail; |
503 | 0 | else if (labels == 1 |
504 | 0 | && (kdf = synonyms_name2id(st, kdfstrtab, |
505 | 0 | OSSL_NELEM(kdfstrtab))) == 0) |
506 | 0 | goto fail; |
507 | 0 | else if (labels == 2 |
508 | 0 | && (aead = synonyms_name2id(st, aeadstrtab, |
509 | 0 | OSSL_NELEM(aeadstrtab))) == 0) |
510 | 0 | goto fail; |
511 | | |
512 | 0 | if (cp == NULL) |
513 | 0 | st = NULL; |
514 | 0 | else |
515 | 0 | st = cp + 1; |
516 | 0 | ++labels; |
517 | 0 | } |
518 | 0 | if (st != NULL || labels != 3) |
519 | 0 | goto fail; |
520 | 0 | suite->kem_id = kem; |
521 | 0 | suite->kdf_id = kdf; |
522 | 0 | suite->aead_id = aead; |
523 | 0 | result = 1; |
524 | |
|
525 | 0 | fail: |
526 | 0 | OPENSSL_free(instrcp); |
527 | 0 | return result; |
528 | 0 | } |