]>
Commit | Line | Data |
---|---|---|
b7466c13 | 1 | /* |
da1c088f | 2 | * Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved. |
b7466c13 P |
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 <openssl/trace.h> | |
11 | #include <stdlib.h> | |
12 | #include <stdarg.h> | |
13 | #include <string.h> | |
14 | #include <openssl/evp.h> | |
15 | #include <openssl/kdf.h> | |
16 | #include <openssl/core_names.h> | |
2741128e | 17 | #include <openssl/proverr.h> |
b7466c13 P |
18 | #include "internal/cryptlib.h" |
19 | #include "internal/numbers.h" | |
20 | #include "crypto/evp.h" | |
21 | #include "prov/provider_ctx.h" | |
2b9e4e95 | 22 | #include "prov/providercommon.h" |
b7466c13 P |
23 | #include "prov/implementations.h" |
24 | #include "prov/provider_util.h" | |
25 | ||
26 | static OSSL_FUNC_kdf_newctx_fn kdf_pkcs12_new; | |
d3aaf4e9 | 27 | static OSSL_FUNC_kdf_dupctx_fn kdf_pkcs12_dup; |
b7466c13 P |
28 | static OSSL_FUNC_kdf_freectx_fn kdf_pkcs12_free; |
29 | static OSSL_FUNC_kdf_reset_fn kdf_pkcs12_reset; | |
30 | static OSSL_FUNC_kdf_derive_fn kdf_pkcs12_derive; | |
31 | static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pkcs12_settable_ctx_params; | |
32 | static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pkcs12_set_ctx_params; | |
33 | static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pkcs12_gettable_ctx_params; | |
34 | static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pkcs12_get_ctx_params; | |
35 | ||
36 | typedef struct { | |
37 | void *provctx; | |
38 | PROV_DIGEST digest; | |
39 | unsigned char *pass; | |
40 | size_t pass_len; | |
41 | unsigned char *salt; | |
42 | size_t salt_len; | |
43 | uint64_t iter; | |
44 | int id; | |
45 | } KDF_PKCS12; | |
46 | ||
47 | /* PKCS12 compatible key/IV generation */ | |
48 | ||
49 | static int pkcs12kdf_derive(const unsigned char *pass, size_t passlen, | |
50 | const unsigned char *salt, size_t saltlen, | |
51 | int id, uint64_t iter, const EVP_MD *md_type, | |
52 | unsigned char *out, size_t n) | |
53 | { | |
54 | unsigned char *B = NULL, *D = NULL, *I = NULL, *p = NULL, *Ai = NULL; | |
55 | size_t Slen, Plen, Ilen; | |
56 | size_t i, j, k, u, v; | |
57 | uint64_t iter_cnt; | |
58 | int ret = 0, ui, vi; | |
59 | EVP_MD_CTX *ctx = NULL; | |
60 | ||
61 | ctx = EVP_MD_CTX_new(); | |
62 | if (ctx == NULL) { | |
e077455e | 63 | ERR_raise(ERR_LIB_PROV, ERR_R_EVP_LIB); |
b7466c13 P |
64 | goto end; |
65 | } | |
ed576acd TM |
66 | vi = EVP_MD_get_block_size(md_type); |
67 | ui = EVP_MD_get_size(md_type); | |
9f81ef9c | 68 | if (ui <= 0 || vi <= 0) { |
b7466c13 P |
69 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_SIZE); |
70 | goto end; | |
71 | } | |
72 | u = (size_t)ui; | |
73 | v = (size_t)vi; | |
74 | D = OPENSSL_malloc(v); | |
75 | Ai = OPENSSL_malloc(u); | |
76 | B = OPENSSL_malloc(v + 1); | |
77 | Slen = v * ((saltlen + v - 1) / v); | |
78 | if (passlen != 0) | |
79 | Plen = v * ((passlen + v - 1) / v); | |
80 | else | |
81 | Plen = 0; | |
82 | Ilen = Slen + Plen; | |
83 | I = OPENSSL_malloc(Ilen); | |
e077455e | 84 | if (D == NULL || Ai == NULL || B == NULL || I == NULL) |
b7466c13 | 85 | goto end; |
b7466c13 P |
86 | for (i = 0; i < v; i++) |
87 | D[i] = id; | |
88 | p = I; | |
89 | for (i = 0; i < Slen; i++) | |
90 | *p++ = salt[i % saltlen]; | |
91 | for (i = 0; i < Plen; i++) | |
92 | *p++ = pass[i % passlen]; | |
93 | for (;;) { | |
94 | if (!EVP_DigestInit_ex(ctx, md_type, NULL) | |
95 | || !EVP_DigestUpdate(ctx, D, v) | |
96 | || !EVP_DigestUpdate(ctx, I, Ilen) | |
97 | || !EVP_DigestFinal_ex(ctx, Ai, NULL)) | |
98 | goto end; | |
99 | for (iter_cnt = 1; iter_cnt < iter; iter_cnt++) { | |
100 | if (!EVP_DigestInit_ex(ctx, md_type, NULL) | |
101 | || !EVP_DigestUpdate(ctx, Ai, u) | |
102 | || !EVP_DigestFinal_ex(ctx, Ai, NULL)) | |
103 | goto end; | |
104 | } | |
105 | memcpy(out, Ai, n < u ? n : u); | |
106 | if (u >= n) { | |
107 | ret = 1; | |
108 | break; | |
109 | } | |
110 | n -= u; | |
111 | out += u; | |
112 | for (j = 0; j < v; j++) | |
113 | B[j] = Ai[j % u]; | |
114 | for (j = 0; j < Ilen; j += v) { | |
115 | unsigned char *Ij = I + j; | |
116 | uint16_t c = 1; | |
117 | ||
118 | /* Work out Ij = Ij + B + 1 */ | |
119 | for (k = v; k > 0;) { | |
120 | k--; | |
121 | c += Ij[k] + B[k]; | |
122 | Ij[k] = (unsigned char)c; | |
123 | c >>= 8; | |
124 | } | |
125 | } | |
126 | } | |
127 | ||
128 | end: | |
129 | OPENSSL_free(Ai); | |
130 | OPENSSL_free(B); | |
131 | OPENSSL_free(D); | |
132 | OPENSSL_free(I); | |
133 | EVP_MD_CTX_free(ctx); | |
134 | return ret; | |
135 | } | |
136 | ||
137 | static void *kdf_pkcs12_new(void *provctx) | |
138 | { | |
139 | KDF_PKCS12 *ctx; | |
140 | ||
2b9e4e95 P |
141 | if (!ossl_prov_is_running()) |
142 | return NULL; | |
143 | ||
b7466c13 | 144 | ctx = OPENSSL_zalloc(sizeof(*ctx)); |
e077455e | 145 | if (ctx == NULL) |
b7466c13 | 146 | return NULL; |
b7466c13 P |
147 | ctx->provctx = provctx; |
148 | return ctx; | |
149 | } | |
150 | ||
151 | static void kdf_pkcs12_cleanup(KDF_PKCS12 *ctx) | |
152 | { | |
153 | ossl_prov_digest_reset(&ctx->digest); | |
154 | OPENSSL_free(ctx->salt); | |
155 | OPENSSL_clear_free(ctx->pass, ctx->pass_len); | |
156 | memset(ctx, 0, sizeof(*ctx)); | |
157 | } | |
158 | ||
159 | static void kdf_pkcs12_free(void *vctx) | |
160 | { | |
161 | KDF_PKCS12 *ctx = (KDF_PKCS12 *)vctx; | |
162 | ||
163 | if (ctx != NULL) { | |
164 | kdf_pkcs12_cleanup(ctx); | |
165 | OPENSSL_free(ctx); | |
166 | } | |
167 | } | |
168 | ||
169 | static void kdf_pkcs12_reset(void *vctx) | |
170 | { | |
171 | KDF_PKCS12 *ctx = (KDF_PKCS12 *)vctx; | |
172 | void *provctx = ctx->provctx; | |
173 | ||
174 | kdf_pkcs12_cleanup(ctx); | |
175 | ctx->provctx = provctx; | |
176 | } | |
177 | ||
d3aaf4e9 P |
178 | static void *kdf_pkcs12_dup(void *vctx) |
179 | { | |
180 | const KDF_PKCS12 *src = (const KDF_PKCS12 *)vctx; | |
181 | KDF_PKCS12 *dest; | |
182 | ||
183 | dest = kdf_pkcs12_new(src->provctx); | |
184 | if (dest != NULL) { | |
185 | if (!ossl_prov_memdup(src->salt, src->salt_len, | |
186 | &dest->salt, &dest->salt_len) | |
187 | || !ossl_prov_memdup(src->pass, src->pass_len, | |
188 | &dest->pass , &dest->pass_len) | |
189 | || !ossl_prov_digest_copy(&dest->digest, &src->digest)) | |
190 | goto err; | |
191 | dest->iter = src->iter; | |
192 | dest->id = src->id; | |
193 | } | |
194 | return dest; | |
195 | ||
196 | err: | |
197 | kdf_pkcs12_free(dest); | |
198 | return NULL; | |
199 | } | |
200 | ||
b7466c13 P |
201 | static int pkcs12kdf_set_membuf(unsigned char **buffer, size_t *buflen, |
202 | const OSSL_PARAM *p) | |
203 | { | |
204 | OPENSSL_clear_free(*buffer, *buflen); | |
d2217c88 TM |
205 | *buffer = NULL; |
206 | *buflen = 0; | |
207 | ||
b7466c13 | 208 | if (p->data_size == 0) { |
e077455e | 209 | if ((*buffer = OPENSSL_malloc(1)) == NULL) |
b7466c13 | 210 | return 0; |
b7466c13 | 211 | } else if (p->data != NULL) { |
b7466c13 P |
212 | if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen)) |
213 | return 0; | |
214 | } | |
215 | return 1; | |
216 | } | |
217 | ||
3469b388 P |
218 | static int kdf_pkcs12_derive(void *vctx, unsigned char *key, size_t keylen, |
219 | const OSSL_PARAM params[]) | |
b7466c13 P |
220 | { |
221 | KDF_PKCS12 *ctx = (KDF_PKCS12 *)vctx; | |
2b9e4e95 P |
222 | const EVP_MD *md; |
223 | ||
3469b388 | 224 | if (!ossl_prov_is_running() || !kdf_pkcs12_set_ctx_params(ctx, params)) |
2b9e4e95 | 225 | return 0; |
b7466c13 P |
226 | |
227 | if (ctx->pass == NULL) { | |
228 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); | |
229 | return 0; | |
230 | } | |
231 | ||
232 | if (ctx->salt == NULL) { | |
233 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); | |
234 | return 0; | |
235 | } | |
236 | ||
2b9e4e95 | 237 | md = ossl_prov_digest_md(&ctx->digest); |
b7466c13 P |
238 | return pkcs12kdf_derive(ctx->pass, ctx->pass_len, ctx->salt, ctx->salt_len, |
239 | ctx->id, ctx->iter, md, key, keylen); | |
240 | } | |
241 | ||
242 | static int kdf_pkcs12_set_ctx_params(void *vctx, const OSSL_PARAM params[]) | |
243 | { | |
244 | const OSSL_PARAM *p; | |
245 | KDF_PKCS12 *ctx = vctx; | |
a829b735 | 246 | OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); |
b7466c13 | 247 | |
c983a0e5 P |
248 | if (params == NULL) |
249 | return 1; | |
250 | ||
b7466c13 P |
251 | if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) |
252 | return 0; | |
253 | ||
254 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) | |
255 | if (!pkcs12kdf_set_membuf(&ctx->pass, &ctx->pass_len, p)) | |
256 | return 0; | |
257 | ||
258 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) | |
1287dabd | 259 | if (!pkcs12kdf_set_membuf(&ctx->salt, &ctx->salt_len, p)) |
b7466c13 P |
260 | return 0; |
261 | ||
262 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PKCS12_ID)) != NULL) | |
263 | if (!OSSL_PARAM_get_int(p, &ctx->id)) | |
264 | return 0; | |
265 | ||
266 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_ITER)) != NULL) | |
267 | if (!OSSL_PARAM_get_uint64(p, &ctx->iter)) | |
268 | return 0; | |
269 | return 1; | |
270 | } | |
271 | ||
1e8e5c60 P |
272 | static const OSSL_PARAM *kdf_pkcs12_settable_ctx_params( |
273 | ossl_unused void *ctx, ossl_unused void *provctx) | |
b7466c13 P |
274 | { |
275 | static const OSSL_PARAM known_settable_ctx_params[] = { | |
276 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), | |
277 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), | |
278 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0), | |
279 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), | |
280 | OSSL_PARAM_uint64(OSSL_KDF_PARAM_ITER, NULL), | |
281 | OSSL_PARAM_int(OSSL_KDF_PARAM_PKCS12_ID, NULL), | |
282 | OSSL_PARAM_END | |
283 | }; | |
284 | return known_settable_ctx_params; | |
285 | } | |
286 | ||
287 | static int kdf_pkcs12_get_ctx_params(void *vctx, OSSL_PARAM params[]) | |
288 | { | |
289 | OSSL_PARAM *p; | |
290 | ||
291 | if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) | |
292 | return OSSL_PARAM_set_size_t(p, SIZE_MAX); | |
293 | return -2; | |
294 | } | |
295 | ||
1e8e5c60 P |
296 | static const OSSL_PARAM *kdf_pkcs12_gettable_ctx_params( |
297 | ossl_unused void *ctx, ossl_unused void *provctx) | |
b7466c13 P |
298 | { |
299 | static const OSSL_PARAM known_gettable_ctx_params[] = { | |
300 | OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), | |
301 | OSSL_PARAM_END | |
302 | }; | |
303 | return known_gettable_ctx_params; | |
304 | } | |
305 | ||
1be63951 | 306 | const OSSL_DISPATCH ossl_kdf_pkcs12_functions[] = { |
b7466c13 | 307 | { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pkcs12_new }, |
d3aaf4e9 | 308 | { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_pkcs12_dup }, |
b7466c13 P |
309 | { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pkcs12_free }, |
310 | { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pkcs12_reset }, | |
311 | { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pkcs12_derive }, | |
312 | { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, | |
313 | (void(*)(void))kdf_pkcs12_settable_ctx_params }, | |
314 | { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pkcs12_set_ctx_params }, | |
315 | { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, | |
316 | (void(*)(void))kdf_pkcs12_gettable_ctx_params }, | |
317 | { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pkcs12_get_ctx_params }, | |
1e6bd31e | 318 | OSSL_DISPATCH_END |
b7466c13 | 319 | }; |