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))) == 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 | }
|
---|