1 | /* |
2 | * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. |
3 | * Copyright 2019 Red Hat, Inc. |
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 | /* |
12 | * This implements https://csrc.nist.gov/publications/detail/sp/800-108/final |
13 | * section 5.1 ("counter mode") and section 5.2 ("feedback mode") in both HMAC |
14 | * and CMAC. That document does not name the KDFs it defines; the name is |
15 | * derived from |
16 | * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Key-Derivation |
17 | * |
18 | * Note that section 5.3 ("double-pipeline mode") is not implemented, though |
19 | * it would be possible to do so in the future. |
20 | * |
21 | * These versions all assume the counter is used. It would be relatively |
22 | * straightforward to expose a configuration handle should the need arise. |
23 | * |
24 | * Variable names attempt to match those of SP800-108. |
25 | */ |
26 | |
27 | #include <stdarg.h> |
28 | #include <stdlib.h> |
29 | #include <string.h> |
30 | |
31 | #include <openssl/core_names.h> |
32 | #include <openssl/evp.h> |
33 | #include <openssl/hmac.h> |
34 | #include <openssl/kdf.h> |
35 | #include <openssl/params.h> |
36 | |
37 | #include "internal/cryptlib.h" |
38 | #include "crypto/evp.h" |
39 | #include "internal/numbers.h" |
40 | #include "prov/implementations.h" |
41 | #include "prov/provider_ctx.h" |
42 | #include "prov/provider_util.h" |
43 | #include "prov/providercommonerr.h" |
44 | |
45 | #include "e_os.h" |
46 | |
47 | #define MIN(a, b) ((a) < (b)) ? (a) : (b) |
48 | |
49 | typedef enum { |
50 | COUNTER = 0, |
51 | FEEDBACK |
52 | } kbkdf_mode; |
53 | |
54 | /* Our context structure. */ |
55 | typedef struct { |
56 | void *provctx; |
57 | kbkdf_mode mode; |
58 | EVP_MAC_CTX *ctx_init; |
59 | |
60 | /* Names are lowercased versions of those found in SP800-108. */ |
61 | unsigned char *ki; |
62 | size_t ki_len; |
63 | unsigned char *label; |
64 | size_t label_len; |
65 | unsigned char *context; |
66 | size_t context_len; |
67 | unsigned char *iv; |
68 | size_t iv_len; |
69 | } KBKDF; |
70 | |
71 | /* Definitions needed for typechecking. */ |
72 | static OSSL_OP_kdf_newctx_fn kbkdf_new; |
73 | static OSSL_OP_kdf_freectx_fn kbkdf_free; |
74 | static OSSL_OP_kdf_reset_fn kbkdf_reset; |
75 | static OSSL_OP_kdf_derive_fn kbkdf_derive; |
76 | static OSSL_OP_kdf_settable_ctx_params_fn kbkdf_settable_ctx_params; |
77 | static OSSL_OP_kdf_set_ctx_params_fn kbkdf_set_ctx_params; |
78 | |
79 | /* Not all platforms have htobe32(). */ |
80 | static uint32_t be32(uint32_t host) |
81 | { |
82 | uint32_t big = 0; |
83 | const union { |
84 | long one; |
85 | char little; |
86 | } is_endian = { 1 }; |
87 | |
88 | if (!is_endian.little) |
89 | return host; |
90 | |
91 | big |= (host & 0xff000000) >> 24; |
92 | big |= (host & 0x00ff0000) >> 8; |
93 | big |= (host & 0x0000ff00) << 8; |
94 | big |= (host & 0x000000ff) << 24; |
95 | return big; |
96 | } |
97 | |
98 | static void *kbkdf_new(void *provctx) |
99 | { |
100 | KBKDF *ctx; |
101 | |
102 | ctx = OPENSSL_zalloc(sizeof(*ctx)); |
103 | if (ctx == NULL) { |
104 | ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); |
105 | return NULL; |
106 | } |
107 | |
108 | ctx->provctx = provctx; |
109 | return ctx; |
110 | } |
111 | |
112 | static void kbkdf_free(void *vctx) |
113 | { |
114 | KBKDF *ctx = (KBKDF *)vctx; |
115 | |
116 | if (ctx != NULL) { |
117 | kbkdf_reset(ctx); |
118 | OPENSSL_free(ctx); |
119 | } |
120 | } |
121 | |
122 | static void kbkdf_reset(void *vctx) |
123 | { |
124 | KBKDF *ctx = (KBKDF *)vctx; |
125 | |
126 | EVP_MAC_CTX_free(ctx->ctx_init); |
127 | OPENSSL_clear_free(ctx->context, ctx->context_len); |
128 | OPENSSL_clear_free(ctx->label, ctx->label_len); |
129 | OPENSSL_clear_free(ctx->ki, ctx->ki_len); |
130 | OPENSSL_clear_free(ctx->iv, ctx->iv_len); |
131 | memset(ctx, 0, sizeof(*ctx)); |
132 | } |
133 | |
134 | /* SP800-108 section 5.1 or section 5.2 depending on mode. */ |
135 | static int derive(EVP_MAC_CTX *ctx_init, kbkdf_mode mode, unsigned char *iv, |
136 | size_t iv_len, unsigned char *label, size_t label_len, |
137 | unsigned char *context, size_t context_len, |
138 | unsigned char *k_i, size_t h, uint32_t l, unsigned char *ko, |
139 | size_t ko_len) |
140 | { |
141 | int ret = 0; |
142 | EVP_MAC_CTX *ctx = NULL; |
143 | size_t written = 0, to_write, k_i_len = iv_len; |
144 | const unsigned char zero = 0; |
145 | uint32_t counter, i; |
146 | |
147 | /* Setup K(0) for feedback mode. */ |
148 | if (iv_len > 0) |
149 | memcpy(k_i, iv, iv_len); |
150 | |
151 | for (counter = 1; written < ko_len; counter++) { |
152 | i = be32(counter); |
153 | |
154 | ctx = EVP_MAC_CTX_dup(ctx_init); |
155 | if (ctx == NULL) |
156 | goto done; |
157 | |
158 | /* Perform feedback, if appropriate. */ |
159 | if (mode == FEEDBACK && !EVP_MAC_update(ctx, k_i, k_i_len)) |
160 | goto done; |
161 | |
162 | if (!EVP_MAC_update(ctx, (unsigned char *)&i, 4) |
163 | || !EVP_MAC_update(ctx, label, label_len) |
164 | || !EVP_MAC_update(ctx, &zero, 1) |
165 | || !EVP_MAC_update(ctx, context, context_len) |
166 | || !EVP_MAC_update(ctx, (unsigned char *)&l, 4) |
167 | || !EVP_MAC_final(ctx, k_i, NULL, h)) |
168 | goto done; |
169 | |
170 | to_write = ko_len - written; |
171 | memcpy(ko + written, k_i, MIN(to_write, h)); |
172 | written += h; |
173 | |
174 | k_i_len = h; |
175 | EVP_MAC_CTX_free(ctx); |
176 | ctx = NULL; |
177 | } |
178 | |
179 | ret = 1; |
180 | done: |
181 | EVP_MAC_CTX_free(ctx); |
182 | return ret; |
183 | } |
184 | |
185 | static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen) |
186 | { |
187 | KBKDF *ctx = (KBKDF *)vctx; |
188 | int ret = 0; |
189 | unsigned char *k_i = NULL; |
190 | uint32_t l = be32(keylen * 8); |
191 | size_t h = 0; |
192 | |
193 | /* label, context, and iv are permitted to be empty. Check everything |
194 | * else. */ |
195 | if (ctx->ctx_init == NULL) { |
196 | if (ctx->ki_len == 0 || ctx->ki == NULL) { |
197 | ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); |
198 | return 0; |
199 | } |
200 | /* Could either be missing MAC or missing message digest or missing |
201 | * cipher - arbitrarily, I pick this one. */ |
202 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MAC); |
203 | return 0; |
204 | } |
205 | |
206 | h = EVP_MAC_size(ctx->ctx_init); |
207 | if (h == 0) |
208 | goto done; |
209 | if (ctx->iv_len != 0 && ctx->iv_len != h) { |
210 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); |
211 | goto done; |
212 | } |
213 | |
214 | k_i = OPENSSL_zalloc(h); |
215 | if (k_i == NULL) |
216 | goto done; |
217 | |
218 | ret = derive(ctx->ctx_init, ctx->mode, ctx->iv, ctx->iv_len, ctx->label, |
219 | ctx->label_len, ctx->context, ctx->context_len, k_i, h, l, |
220 | key, keylen); |
221 | done: |
222 | if (ret != 1) |
223 | OPENSSL_cleanse(key, keylen); |
224 | OPENSSL_clear_free(k_i, h); |
225 | return ret; |
226 | } |
227 | |
228 | static int kbkdf_set_buffer(unsigned char **out, size_t *out_len, |
229 | const OSSL_PARAM *p) |
230 | { |
231 | if (p->data == NULL || p->data_size == 0) |
232 | return 1; |
233 | |
234 | OPENSSL_clear_free(*out, *out_len); |
235 | *out = NULL; |
236 | return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); |
237 | } |
238 | |
239 | static int kbkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) |
240 | { |
241 | KBKDF *ctx = (KBKDF *)vctx; |
242 | OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx); |
243 | const OSSL_PARAM *p; |
244 | OSSL_PARAM mparams[2]; |
245 | |
246 | if (!ossl_prov_macctx_load_from_params(&ctx->ctx_init, params, NULL, |
247 | NULL, NULL, libctx)) |
248 | return 0; |
249 | else if (ctx->ctx_init != NULL |
250 | && !EVP_MAC_is_a(EVP_MAC_CTX_mac(ctx->ctx_init), |
251 | OSSL_MAC_NAME_HMAC) |
252 | && !EVP_MAC_is_a(EVP_MAC_CTX_mac(ctx->ctx_init), |
253 | OSSL_MAC_NAME_CMAC)) { |
254 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MAC); |
255 | return 0; |
256 | } |
257 | |
258 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE); |
259 | if (p != NULL && strncasecmp("counter" , p->data, p->data_size) == 0) { |
260 | ctx->mode = COUNTER; |
261 | } else if (p != NULL |
262 | && strncasecmp("feedback" , p->data, p->data_size) == 0) { |
263 | ctx->mode = FEEDBACK; |
264 | } else if (p != NULL) { |
265 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); |
266 | return 0; |
267 | } |
268 | |
269 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY); |
270 | if (p != NULL && !kbkdf_set_buffer(&ctx->ki, &ctx->ki_len, p)) |
271 | return 0; |
272 | |
273 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT); |
274 | if (p != NULL && !kbkdf_set_buffer(&ctx->label, &ctx->label_len, p)) |
275 | return 0; |
276 | |
277 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO); |
278 | if (p != NULL && !kbkdf_set_buffer(&ctx->context, &ctx->context_len, p)) |
279 | return 0; |
280 | |
281 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SEED); |
282 | if (p != NULL && !kbkdf_set_buffer(&ctx->iv, &ctx->iv_len, p)) |
283 | return 0; |
284 | |
285 | /* Set up digest context, if we can. */ |
286 | if (ctx->ctx_init != NULL && ctx->ki_len != 0) { |
287 | mparams[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, |
288 | ctx->ki, ctx->ki_len); |
289 | mparams[1] = OSSL_PARAM_construct_end(); |
290 | |
291 | if (!EVP_MAC_CTX_set_params(ctx->ctx_init, mparams) |
292 | || !EVP_MAC_init(ctx->ctx_init)) |
293 | return 0; |
294 | } |
295 | |
296 | return 1; |
297 | } |
298 | |
299 | static const OSSL_PARAM *kbkdf_settable_ctx_params(void) |
300 | { |
301 | static const OSSL_PARAM known_settable_ctx_params[] = { |
302 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), |
303 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), |
304 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), |
305 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0), |
306 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), |
307 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CIPHER, NULL, 0), |
308 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MAC, NULL, 0), |
309 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), |
310 | |
311 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), |
312 | OSSL_PARAM_END, |
313 | }; |
314 | return known_settable_ctx_params; |
315 | } |
316 | |
317 | static int kbkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) |
318 | { |
319 | OSSL_PARAM *p; |
320 | |
321 | p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE); |
322 | if (p == NULL) |
323 | return -2; |
324 | |
325 | /* KBKDF can produce results as large as you like. */ |
326 | return OSSL_PARAM_set_size_t(p, SIZE_MAX); |
327 | } |
328 | |
329 | static const OSSL_PARAM *kbkdf_gettable_ctx_params(void) |
330 | { |
331 | static const OSSL_PARAM known_gettable_ctx_params[] = |
332 | { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), OSSL_PARAM_END }; |
333 | return known_gettable_ctx_params; |
334 | } |
335 | |
336 | const OSSL_DISPATCH kdf_kbkdf_functions[] = { |
337 | { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kbkdf_new }, |
338 | { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kbkdf_free }, |
339 | { OSSL_FUNC_KDF_RESET, (void(*)(void))kbkdf_reset }, |
340 | { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kbkdf_derive }, |
341 | { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, |
342 | (void(*)(void))kbkdf_settable_ctx_params }, |
343 | { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kbkdf_set_ctx_params }, |
344 | { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, |
345 | (void(*)(void))kbkdf_gettable_ctx_params }, |
346 | { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kbkdf_get_ctx_params }, |
347 | { 0, NULL }, |
348 | }; |
349 | |