]>
Commit | Line | Data |
---|---|---|
5a285add DM |
1 | /* |
2 | * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. | |
4 | * | |
5 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
6 | * this file except in compliance with the License. You can obtain a copy | |
7 | * in the file LICENSE in the source distribution or at | |
8 | * https://www.openssl.org/source/license.html | |
9 | */ | |
10 | ||
11 | #include <string.h> | |
12 | #include <openssl/evp.h> | |
13 | #include <openssl/err.h> | |
a9419205 | 14 | #include <openssl/buffer.h> |
5a285add | 15 | #include <openssl/kdf.h> |
7707526b P |
16 | #include <openssl/core.h> |
17 | #include <openssl/core_names.h> | |
18 | #include <openssl/params.h> | |
cee719c2 | 19 | #include "internal/numbers.h" |
25f2138b | 20 | #include "crypto/evp.h" |
5a285add | 21 | |
7707526b P |
22 | #define MAX_PARAM 20 |
23 | ||
24 | typedef struct { | |
25 | EVP_KDF_CTX *kctx; | |
a9419205 RL |
26 | /* |
27 | * EVP_PKEY implementations collect bits of certain data | |
28 | */ | |
29 | BUF_MEM *collected_seed; | |
30 | BUF_MEM *collected_info; | |
7707526b P |
31 | } EVP_PKEY_KDF_CTX; |
32 | ||
a9419205 | 33 | static void pkey_kdf_free_collected(EVP_PKEY_KDF_CTX *pkctx) |
7707526b | 34 | { |
a9419205 RL |
35 | BUF_MEM_free(pkctx->collected_seed); |
36 | pkctx->collected_seed = NULL; | |
37 | BUF_MEM_free(pkctx->collected_info); | |
38 | pkctx->collected_info = NULL; | |
7707526b P |
39 | } |
40 | ||
5a285add DM |
41 | static int pkey_kdf_init(EVP_PKEY_CTX *ctx) |
42 | { | |
7707526b | 43 | EVP_PKEY_KDF_CTX *pkctx; |
5a285add | 44 | EVP_KDF_CTX *kctx; |
7707526b P |
45 | const char *kdf_name = OBJ_nid2sn(ctx->pmeth->pkey_id); |
46 | EVP_KDF *kdf; | |
5a285add | 47 | |
7707526b P |
48 | pkctx = OPENSSL_zalloc(sizeof(*pkctx)); |
49 | if (pkctx == NULL) | |
5a285add DM |
50 | return 0; |
51 | ||
7707526b P |
52 | kdf = EVP_KDF_fetch(NULL, kdf_name, NULL); |
53 | kctx = EVP_KDF_CTX_new(kdf); | |
54 | EVP_KDF_free(kdf); | |
55 | if (kctx == NULL) { | |
56 | OPENSSL_free(pkctx); | |
57 | return 0; | |
58 | } | |
59 | ||
60 | pkctx->kctx = kctx; | |
61 | ctx->data = pkctx; | |
5a285add DM |
62 | return 1; |
63 | } | |
64 | ||
65 | static void pkey_kdf_cleanup(EVP_PKEY_CTX *ctx) | |
66 | { | |
7707526b | 67 | EVP_PKEY_KDF_CTX *pkctx = ctx->data; |
5a285add | 68 | |
7707526b | 69 | EVP_KDF_CTX_free(pkctx->kctx); |
a9419205 | 70 | pkey_kdf_free_collected(pkctx); |
7707526b | 71 | OPENSSL_free(pkctx); |
5a285add DM |
72 | } |
73 | ||
ea643c95 RL |
74 | static int collect(BUF_MEM **collector, void *data, size_t datalen) |
75 | { | |
76 | size_t i; | |
77 | ||
78 | if (*collector == NULL) | |
79 | *collector = BUF_MEM_new(); | |
80 | if (*collector == NULL) { | |
81 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); | |
82 | return 0; | |
83 | } | |
84 | ||
7eeceeaa MC |
85 | if (data != NULL && datalen > 0) { |
86 | i = (*collector)->length; /* BUF_MEM_grow() changes it! */ | |
87 | ||
88 | if (!BUF_MEM_grow(*collector, i + datalen)) | |
89 | return 0; | |
53598b22 | 90 | memcpy((*collector)->data + i, data, datalen); |
7eeceeaa | 91 | } |
ea643c95 RL |
92 | return 1; |
93 | } | |
94 | ||
5a285add DM |
95 | static int pkey_kdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) |
96 | { | |
7707526b | 97 | EVP_PKEY_KDF_CTX *pkctx = ctx->data; |
a9419205 | 98 | EVP_KDF_CTX *kctx = pkctx->kctx; |
7707526b P |
99 | enum { T_OCTET_STRING, T_UINT64, T_DIGEST, T_INT } cmd; |
100 | const char *name, *mdname; | |
a9419205 RL |
101 | BUF_MEM **collector = NULL; |
102 | OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
5a285add DM |
103 | |
104 | switch (type) { | |
105 | case EVP_PKEY_CTRL_PASS: | |
7707526b P |
106 | cmd = T_OCTET_STRING; |
107 | name = OSSL_KDF_PARAM_PASSWORD; | |
5a285add DM |
108 | break; |
109 | case EVP_PKEY_CTRL_HKDF_SALT: | |
110 | case EVP_PKEY_CTRL_SCRYPT_SALT: | |
7707526b P |
111 | cmd = T_OCTET_STRING; |
112 | name = OSSL_KDF_PARAM_SALT; | |
5a285add DM |
113 | break; |
114 | case EVP_PKEY_CTRL_TLS_MD: | |
115 | case EVP_PKEY_CTRL_HKDF_MD: | |
7707526b P |
116 | cmd = T_DIGEST; |
117 | name = OSSL_KDF_PARAM_DIGEST; | |
5a285add DM |
118 | break; |
119 | case EVP_PKEY_CTRL_TLS_SECRET: | |
7707526b P |
120 | cmd = T_OCTET_STRING; |
121 | name = OSSL_KDF_PARAM_SECRET; | |
a9419205 RL |
122 | /* |
123 | * Perform the semantics described in | |
124 | * EVP_PKEY_CTX_add1_tls1_prf_seed(3) | |
125 | */ | |
f575bd2a | 126 | if (ctx->pmeth->pkey_id == NID_tls1_prf) { |
a9419205 | 127 | BUF_MEM_free(pkctx->collected_seed); |
f575bd2a P |
128 | pkctx->collected_seed = NULL; |
129 | } | |
5a285add DM |
130 | break; |
131 | case EVP_PKEY_CTRL_TLS_SEED: | |
7707526b P |
132 | cmd = T_OCTET_STRING; |
133 | name = OSSL_KDF_PARAM_SEED; | |
a9419205 | 134 | collector = &pkctx->collected_seed; |
5a285add DM |
135 | break; |
136 | case EVP_PKEY_CTRL_HKDF_KEY: | |
7707526b P |
137 | cmd = T_OCTET_STRING; |
138 | name = OSSL_KDF_PARAM_KEY; | |
5a285add DM |
139 | break; |
140 | case EVP_PKEY_CTRL_HKDF_INFO: | |
7707526b P |
141 | cmd = T_OCTET_STRING; |
142 | name = OSSL_KDF_PARAM_INFO; | |
a9419205 | 143 | collector = &pkctx->collected_info; |
5a285add DM |
144 | break; |
145 | case EVP_PKEY_CTRL_HKDF_MODE: | |
7707526b P |
146 | cmd = T_INT; |
147 | name = OSSL_KDF_PARAM_MODE; | |
5a285add DM |
148 | break; |
149 | case EVP_PKEY_CTRL_SCRYPT_N: | |
7707526b P |
150 | cmd = T_UINT64; |
151 | name = OSSL_KDF_PARAM_SCRYPT_N; | |
5a285add DM |
152 | break; |
153 | case EVP_PKEY_CTRL_SCRYPT_R: | |
7707526b P |
154 | cmd = T_UINT64; /* Range checking occurs on the provider side */ |
155 | name = OSSL_KDF_PARAM_SCRYPT_R; | |
5a285add DM |
156 | break; |
157 | case EVP_PKEY_CTRL_SCRYPT_P: | |
7707526b P |
158 | cmd = T_UINT64; /* Range checking occurs on the provider side */ |
159 | name = OSSL_KDF_PARAM_SCRYPT_P; | |
5a285add DM |
160 | break; |
161 | case EVP_PKEY_CTRL_SCRYPT_MAXMEM_BYTES: | |
7707526b P |
162 | cmd = T_UINT64; |
163 | name = OSSL_KDF_PARAM_SCRYPT_MAXMEM; | |
5a285add DM |
164 | break; |
165 | default: | |
166 | return -2; | |
167 | } | |
168 | ||
a9419205 | 169 | if (collector != NULL) { |
a9419205 RL |
170 | switch (cmd) { |
171 | case T_OCTET_STRING: | |
ea643c95 | 172 | return collect(collector, p2, p1); |
a9419205 RL |
173 | default: |
174 | OPENSSL_assert("You shouldn't be here"); | |
175 | break; | |
176 | } | |
177 | return 1; | |
178 | } | |
179 | ||
5a285add | 180 | switch (cmd) { |
7707526b | 181 | case T_OCTET_STRING: |
a9419205 RL |
182 | params[0] = |
183 | OSSL_PARAM_construct_octet_string(name, (unsigned char *)p2, | |
184 | (size_t)p1); | |
7707526b | 185 | break; |
5a285add | 186 | |
7707526b P |
187 | case T_DIGEST: |
188 | mdname = EVP_MD_name((const EVP_MD *)p2); | |
a9419205 RL |
189 | params[0] = OSSL_PARAM_construct_utf8_string(name, (char *)mdname, |
190 | strlen(mdname) + 1); | |
7707526b | 191 | break; |
5a285add | 192 | |
7707526b P |
193 | /* |
194 | * These are special because the helper macros pass a pointer to the | |
195 | * stack, so a local copy is required. | |
196 | */ | |
197 | case T_INT: | |
a9419205 | 198 | params[0] = OSSL_PARAM_construct_int(name, &p1); |
7707526b | 199 | break; |
5a285add | 200 | |
7707526b | 201 | case T_UINT64: |
a9419205 | 202 | params[0] = OSSL_PARAM_construct_uint64(name, (uint64_t *)p2); |
7707526b | 203 | break; |
5a285add | 204 | } |
a9419205 RL |
205 | |
206 | return EVP_KDF_CTX_set_params(kctx, params); | |
5a285add DM |
207 | } |
208 | ||
209 | static int pkey_kdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, | |
210 | const char *value) | |
211 | { | |
7707526b P |
212 | EVP_PKEY_KDF_CTX *pkctx = ctx->data; |
213 | EVP_KDF_CTX *kctx = pkctx->kctx; | |
214 | const EVP_KDF *kdf = EVP_KDF_CTX_kdf(kctx); | |
ea643c95 | 215 | BUF_MEM **collector = NULL; |
7707526b | 216 | const OSSL_PARAM *defs = EVP_KDF_CTX_settable_params(kdf); |
a9419205 RL |
217 | OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; |
218 | int ok = 0; | |
5a285add | 219 | |
7707526b | 220 | /* Deal with ctrl name aliasing */ |
5a285add | 221 | if (strcmp(type, "md") == 0) |
7707526b P |
222 | type = OSSL_KDF_PARAM_DIGEST; |
223 | /* scrypt uses 'N', params uses 'n' */ | |
224 | if (strcmp(type, "N") == 0) | |
225 | type = OSSL_KDF_PARAM_SCRYPT_N; | |
226 | ||
a9419205 RL |
227 | if (!OSSL_PARAM_allocate_from_text(¶ms[0], defs, type, |
228 | value, strlen(value))) | |
7707526b | 229 | return 0; |
ea643c95 RL |
230 | |
231 | /* | |
232 | * We do the same special casing of seed and info here as in | |
233 | * pkey_kdf_ctrl() | |
234 | */ | |
235 | if (strcmp(params[0].key, OSSL_KDF_PARAM_SEED) == 0) | |
236 | collector = &pkctx->collected_seed; | |
237 | else if (strcmp(params[0].key, OSSL_KDF_PARAM_INFO) == 0) | |
238 | collector = &pkctx->collected_info; | |
239 | ||
240 | if (collector != NULL) | |
241 | ok = collect(collector, params[0].data, params[0].data_size); | |
242 | else | |
243 | ok = EVP_KDF_CTX_set_params(kctx, params); | |
a9419205 RL |
244 | OPENSSL_free(params[0].data); |
245 | return ok; | |
5a285add DM |
246 | } |
247 | ||
248 | static int pkey_kdf_derive_init(EVP_PKEY_CTX *ctx) | |
249 | { | |
7707526b | 250 | EVP_PKEY_KDF_CTX *pkctx = ctx->data; |
5a285add | 251 | |
a9419205 RL |
252 | pkey_kdf_free_collected(pkctx); |
253 | if (pkctx->kctx != NULL) | |
254 | EVP_KDF_reset(pkctx->kctx); | |
5a285add DM |
255 | return 1; |
256 | } | |
257 | ||
258 | /* | |
259 | * For fixed-output algorithms the keylen parameter is an "out" parameter | |
260 | * otherwise it is an "in" parameter. | |
261 | */ | |
262 | static int pkey_kdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, | |
263 | size_t *keylen) | |
264 | { | |
7707526b P |
265 | EVP_PKEY_KDF_CTX *pkctx = ctx->data; |
266 | EVP_KDF_CTX *kctx = pkctx->kctx; | |
5a285add | 267 | size_t outlen = EVP_KDF_size(kctx); |
7707526b | 268 | int r; |
5a285add | 269 | |
a9419205 RL |
270 | if (pkctx->collected_seed != NULL) { |
271 | OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
272 | ||
273 | params[0] = | |
274 | OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SEED, | |
275 | pkctx->collected_seed->data, | |
276 | pkctx->collected_seed->length); | |
277 | ||
278 | r = EVP_KDF_CTX_set_params(kctx, params); | |
279 | pkey_kdf_free_collected(pkctx); | |
280 | if (!r) | |
281 | return 0; | |
282 | } | |
283 | if (pkctx->collected_info != NULL) { | |
284 | OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
285 | ||
286 | params[0] = | |
287 | OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, | |
288 | pkctx->collected_info->data, | |
289 | pkctx->collected_info->length); | |
290 | ||
291 | r = EVP_KDF_CTX_set_params(kctx, params); | |
292 | pkey_kdf_free_collected(pkctx); | |
7707526b P |
293 | if (!r) |
294 | return 0; | |
295 | } | |
5a285add DM |
296 | if (outlen == 0 || outlen == SIZE_MAX) { |
297 | /* Variable-output algorithm */ | |
298 | if (key == NULL) | |
299 | return 0; | |
300 | } else { | |
301 | /* Fixed-output algorithm */ | |
302 | *keylen = outlen; | |
303 | if (key == NULL) | |
304 | return 1; | |
305 | } | |
306 | return EVP_KDF_derive(kctx, key, *keylen); | |
307 | } | |
308 | ||
309 | #ifndef OPENSSL_NO_SCRYPT | |
19bd1fa1 | 310 | static const EVP_PKEY_METHOD scrypt_pkey_meth = { |
5a285add DM |
311 | EVP_PKEY_SCRYPT, |
312 | 0, | |
313 | pkey_kdf_init, | |
314 | 0, | |
315 | pkey_kdf_cleanup, | |
316 | ||
317 | 0, 0, | |
318 | 0, 0, | |
319 | ||
320 | 0, | |
321 | 0, | |
322 | ||
323 | 0, | |
324 | 0, | |
325 | ||
326 | 0, 0, | |
327 | ||
328 | 0, 0, 0, 0, | |
329 | ||
330 | 0, 0, | |
331 | ||
332 | 0, 0, | |
333 | ||
334 | pkey_kdf_derive_init, | |
335 | pkey_kdf_derive, | |
336 | pkey_kdf_ctrl, | |
337 | pkey_kdf_ctrl_str | |
338 | }; | |
19bd1fa1 PS |
339 | |
340 | const EVP_PKEY_METHOD *scrypt_pkey_method(void) | |
341 | { | |
342 | return &scrypt_pkey_meth; | |
343 | } | |
5a285add DM |
344 | #endif |
345 | ||
19bd1fa1 | 346 | static const EVP_PKEY_METHOD tls1_prf_pkey_meth = { |
5a285add DM |
347 | EVP_PKEY_TLS1_PRF, |
348 | 0, | |
349 | pkey_kdf_init, | |
350 | 0, | |
351 | pkey_kdf_cleanup, | |
352 | ||
353 | 0, 0, | |
354 | 0, 0, | |
355 | ||
356 | 0, | |
357 | 0, | |
358 | ||
359 | 0, | |
360 | 0, | |
361 | ||
362 | 0, 0, | |
363 | ||
364 | 0, 0, 0, 0, | |
365 | ||
366 | 0, 0, | |
367 | ||
368 | 0, 0, | |
369 | ||
370 | pkey_kdf_derive_init, | |
371 | pkey_kdf_derive, | |
372 | pkey_kdf_ctrl, | |
373 | pkey_kdf_ctrl_str | |
374 | }; | |
375 | ||
19bd1fa1 PS |
376 | const EVP_PKEY_METHOD *tls1_prf_pkey_method(void) |
377 | { | |
378 | return &tls1_prf_pkey_meth; | |
379 | } | |
380 | ||
381 | static const EVP_PKEY_METHOD hkdf_pkey_meth = { | |
5a285add DM |
382 | EVP_PKEY_HKDF, |
383 | 0, | |
384 | pkey_kdf_init, | |
385 | 0, | |
386 | pkey_kdf_cleanup, | |
387 | ||
388 | 0, 0, | |
389 | 0, 0, | |
390 | ||
391 | 0, | |
392 | 0, | |
393 | ||
394 | 0, | |
395 | 0, | |
396 | ||
397 | 0, 0, | |
398 | ||
399 | 0, 0, 0, 0, | |
400 | ||
401 | 0, 0, | |
402 | ||
403 | 0, 0, | |
404 | ||
405 | pkey_kdf_derive_init, | |
406 | pkey_kdf_derive, | |
407 | pkey_kdf_ctrl, | |
408 | pkey_kdf_ctrl_str | |
409 | }; | |
410 | ||
19bd1fa1 PS |
411 | const EVP_PKEY_METHOD *hkdf_pkey_method(void) |
412 | { | |
413 | return &hkdf_pkey_meth; | |
414 | } |