]>
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" | |
a1c03068 | 20 | #include "crypto/rand.h" |
ad062480 | 21 | #include "internal/hpke_util.h" |
78c44b05 | 22 | #include "internal/packet.h" |
ad062480 | 23 | #include "internal/nelem.h" |
a1c03068 | 24 | #include "internal/common.h" |
78c44b05 | 25 | |
26 | /* | |
ad062480 | 27 | * Delimiter used in OSSL_HPKE_str2suite |
78c44b05 | 28 | */ |
ad062480 | 29 | #define OSSL_HPKE_STR_DELIMCHAR ',' |
78c44b05 | 30 | |
31 | /* | |
ad062480 SF |
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 | |
78c44b05 | 36 | */ |
ad062480 SF |
37 | typedef struct { |
38 | uint16_t id; | |
39 | char *synonyms[4]; | |
40 | } synonymttab_t; | |
78c44b05 | 41 | |
ad062480 SF |
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 */ | |
78c44b05 | 46 | /* ASCII: "HPKE-v1", in hex for EBCDIC compatibility */ |
47 | static const char LABEL_HPKEV1[] = "\x48\x50\x4B\x45\x2D\x76\x31"; | |
48 | ||
ad062480 SF |
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 }, | |
4032cd9a | 71 | # ifndef OPENSSL_NO_ECX |
ad062480 SF |
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 } | |
4032cd9a | 78 | # endif |
ad062480 SF |
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 }, | |
36b4d7a6 | 93 | #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) |
ad062480 SF |
94 | { OSSL_HPKE_AEAD_ID_CHACHA_POLY1305, LN_chacha20_poly1305, 16, 32, |
95 | OSSL_HPKE_MAX_NONCELEN }, | |
ad062480 | 96 | #endif |
36b4d7a6 | 97 | { OSSL_HPKE_AEAD_ID_EXPORTONLY, NULL, 0, 0, 0 } |
ad062480 SF |
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 | |
eb4129e1 | 119 | * this file and shouldn't need modification so long as the table |
ad062480 SF |
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" }}, | |
4032cd9a | 129 | # ifndef OPENSSL_NO_ECX |
ad062480 SF |
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" }} | |
4032cd9a | 134 | # endif |
ad062480 SF |
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 | { | |
a1c03068 SF |
194 | uint32_t rval = 0; |
195 | int err = 0; | |
196 | size_t sz = OSSL_NELEM(hpke_kem_tab); | |
ad062480 | 197 | |
a1c03068 SF |
198 | rval = ossl_rand_uniform_uint32(ctx, sz, &err); |
199 | return (err == 1 ? NULL : &hpke_kem_tab[rval]); | |
ad062480 SF |
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 | { | |
a1c03068 SF |
216 | uint32_t rval = 0; |
217 | int err = 0; | |
218 | size_t sz = OSSL_NELEM(hpke_kdf_tab); | |
ad062480 | 219 | |
a1c03068 SF |
220 | rval = ossl_rand_uniform_uint32(ctx, sz, &err); |
221 | return (err == 1 ? NULL : &hpke_kdf_tab[rval]); | |
ad062480 SF |
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 | { | |
a1c03068 SF |
238 | uint32_t rval = 0; |
239 | int err = 0; | |
ad062480 | 240 | /* the minus 1 below is so we don't pick the EXPORTONLY codepoint */ |
a1c03068 | 241 | size_t sz = OSSL_NELEM(hpke_aead_tab) - 1; |
ad062480 | 242 | |
a1c03068 SF |
243 | rval = ossl_rand_uniform_uint32(ctx, sz, &err); |
244 | return (err == 1 ? NULL : &hpke_aead_tab[rval]); | |
ad062480 SF |
245 | } |
246 | ||
78c44b05 | 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, | |
ad062480 | 298 | const char *protocol_label, |
78c44b05 | 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; | |
ad062480 SF |
304 | size_t label_hpkev1len = 0; |
305 | size_t protocol_labellen = 0; | |
306 | size_t labellen = 0; | |
78c44b05 | 307 | size_t labeled_ikmlen = 0; |
ad062480 | 308 | unsigned char *labeled_ikm = NULL; |
78c44b05 | 309 | WPACKET pkt; |
310 | ||
ad062480 SF |
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 | ||
78c44b05 | 320 | /* labeled_ikm = concat("HPKE-v1", suiteid, label, ikm) */ |
ad062480 SF |
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) | |
78c44b05 | 324 | || !WPACKET_memcpy(&pkt, suiteid, suiteidlen) |
ad062480 | 325 | || !WPACKET_memcpy(&pkt, label, labellen) |
78c44b05 | 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); | |
ad062480 | 338 | OPENSSL_free(labeled_ikm); |
78c44b05 | 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, | |
ad062480 | 348 | const char *protocol_label, |
78c44b05 | 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; | |
ad062480 SF |
354 | size_t label_hpkev1len = 0; |
355 | size_t protocol_labellen = 0; | |
356 | size_t labellen = 0; | |
78c44b05 | 357 | size_t labeled_infolen = 0; |
ad062480 | 358 | unsigned char *labeled_info = NULL; |
78c44b05 | 359 | WPACKET pkt; |
360 | ||
ad062480 SF |
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 | ||
78c44b05 | 370 | /* labeled_info = concat(okmlen, "HPKE-v1", suiteid, label, info) */ |
ad062480 | 371 | if (!WPACKET_init_static_len(&pkt, labeled_info, labeled_infolen, 0) |
78c44b05 | 372 | || !WPACKET_put_bytes_u16(&pkt, okmlen) |
ad062480 SF |
373 | || !WPACKET_memcpy(&pkt, LABEL_HPKEV1, label_hpkev1len) |
374 | || !WPACKET_memcpy(&pkt, protocol_label, protocol_labellen) | |
78c44b05 | 375 | || !WPACKET_memcpy(&pkt, suiteid, suiteidlen) |
ad062480 | 376 | || !WPACKET_memcpy(&pkt, label, labellen) |
78c44b05 | 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); | |
ad062480 | 388 | OPENSSL_free(labeled_info); |
78c44b05 | 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); | |
0510f792 TM |
400 | if (kdf == NULL) { |
401 | ERR_raise(ERR_LIB_CRYPTO, ERR_R_FETCH_FAILED); | |
402 | return NULL; | |
403 | } | |
78c44b05 | 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 | } | |
ad062480 SF |
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))) == 0) | |
502 | goto fail; | |
503 | else if (labels == 1 | |
504 | && (kdf = synonyms_name2id(st, kdfstrtab, | |
505 | OSSL_NELEM(kdfstrtab))) == 0) | |
506 | goto fail; | |
507 | else if (labels == 2 | |
508 | && (aead = synonyms_name2id(st, aeadstrtab, | |
509 | OSSL_NELEM(aeadstrtab))) == 0) | |
510 | goto fail; | |
511 | ||
512 | if (cp == NULL) | |
513 | st = NULL; | |
514 | else | |
515 | st = cp + 1; | |
516 | ++labels; | |
517 | } | |
518 | if (st != NULL || labels != 3) | |
519 | goto fail; | |
520 | suite->kem_id = kem; | |
521 | suite->kdf_id = kdf; | |
522 | suite->aead_id = aead; | |
523 | result = 1; | |
524 | ||
525 | fail: | |
526 | OPENSSL_free(instrcp); | |
527 | return result; | |
528 | } |