]>
Commit | Line | Data |
---|---|---|
1aec7716 SL |
1 | /* |
2 | * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * Copyright (c) 2019, 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 "e_os.h" | |
12 | ||
13 | #ifndef OPENSSL_NO_CMS | |
14 | ||
15 | # include <stdlib.h> | |
16 | # include <stdarg.h> | |
17 | # include <string.h> | |
18 | # include <openssl/hmac.h> | |
19 | # include <openssl/cms.h> | |
20 | # include <openssl/evp.h> | |
21 | # include <openssl/kdf.h> | |
22 | # include <openssl/x509.h> | |
23 | # include <openssl/obj_mac.h> | |
e3405a4a | 24 | # include <openssl/core_names.h> |
1aec7716 | 25 | # include "internal/cryptlib.h" |
e3405a4a | 26 | # include "internal/numbers.h" |
1aec7716 | 27 | # include "internal/evp_int.h" |
e3405a4a P |
28 | # include "internal/provider_ctx.h" |
29 | # include "internal/providercommonerr.h" | |
30 | # include "internal/provider_algs.h" | |
1aec7716 SL |
31 | |
32 | # define X942KDF_MAX_INLEN (1 << 30) | |
33 | ||
e3405a4a P |
34 | static OSSL_OP_kdf_newctx_fn x942kdf_new; |
35 | static OSSL_OP_kdf_freectx_fn x942kdf_free; | |
36 | static OSSL_OP_kdf_reset_fn x942kdf_reset; | |
37 | static OSSL_OP_kdf_derive_fn x942kdf_derive; | |
38 | static OSSL_OP_kdf_settable_ctx_params_fn x942kdf_settable_ctx_params; | |
39 | static OSSL_OP_kdf_set_ctx_params_fn x942kdf_set_ctx_params; | |
40 | static OSSL_OP_kdf_gettable_ctx_params_fn x942kdf_gettable_ctx_params; | |
41 | static OSSL_OP_kdf_get_ctx_params_fn x942kdf_get_ctx_params; | |
42 | ||
43 | typedef struct { | |
44 | void *provctx; | |
45 | EVP_MD *md; | |
1aec7716 SL |
46 | unsigned char *secret; |
47 | size_t secret_len; | |
48 | int cek_nid; | |
49 | unsigned char *ukm; | |
50 | size_t ukm_len; | |
51 | size_t dkm_len; | |
e3405a4a | 52 | } KDF_X942; |
1aec7716 SL |
53 | |
54 | /* A table of allowed wrapping algorithms and the associated output lengths */ | |
55 | static const struct { | |
56 | int nid; | |
57 | size_t keklen; /* size in bytes */ | |
58 | } kek_algs[] = { | |
59 | { NID_id_smime_alg_CMS3DESwrap, 24 }, | |
60 | { NID_id_smime_alg_CMSRC2wrap, 16 }, | |
61 | { NID_id_aes128_wrap, 16 }, | |
62 | { NID_id_aes192_wrap, 24 }, | |
63 | { NID_id_aes256_wrap, 32 }, | |
64 | { NID_id_camellia128_wrap, 16 }, | |
65 | { NID_id_camellia192_wrap, 24 }, | |
66 | { NID_id_camellia256_wrap, 32 } | |
67 | }; | |
68 | ||
69 | /* Skip past an ASN1 structure: for OBJECT skip content octets too */ | |
70 | static int skip_asn1(unsigned char **pp, long *plen, int exptag) | |
71 | { | |
72 | int i, tag, xclass; | |
73 | long tmplen; | |
74 | const unsigned char *q = *pp; | |
75 | ||
76 | i = ASN1_get_object(&q, &tmplen, &tag, &xclass, *plen); | |
77 | if ((i & 0x80) != 0 || tag != exptag || xclass != V_ASN1_UNIVERSAL) | |
78 | return 0; | |
79 | if (tag == V_ASN1_OBJECT) | |
80 | q += tmplen; | |
81 | *pp = (unsigned char *)q; | |
82 | *plen -= q - *pp; | |
83 | return 1; | |
84 | } | |
85 | ||
86 | /* | |
87 | * Encode the other info structure. | |
88 | * | |
89 | * RFC2631 Section 2.1.2 Contains the following definition for otherinfo | |
90 | * | |
91 | * OtherInfo ::= SEQUENCE { | |
92 | * keyInfo KeySpecificInfo, | |
93 | * partyAInfo [0] OCTET STRING OPTIONAL, | |
94 | * suppPubInfo [2] OCTET STRING | |
95 | * } | |
96 | * | |
97 | * KeySpecificInfo ::= SEQUENCE { | |
98 | * algorithm OBJECT IDENTIFIER, | |
99 | * counter OCTET STRING SIZE (4..4) | |
100 | * } | |
101 | * | |
102 | * |nid| is the algorithm object identifier. | |
103 | * |keylen| is the length (in bytes) of the generated KEK. It is stored into | |
104 | * suppPubInfo (in bits). | |
105 | * |ukm| is the optional user keying material that is stored into partyAInfo. It | |
106 | * can be NULL. | |
107 | * |ukmlen| is the user keying material length (in bytes). | |
108 | * |der| is the returned encoded data. It must be freed by the caller. | |
109 | * |der_len| is the returned size of the encoded data. | |
110 | * |out_ctr| returns a pointer to the counter data which is embedded inside the | |
111 | * encoded data. This allows the counter bytes to be updated without re-encoding. | |
112 | * | |
113 | * Returns: 1 if successfully encoded, or 0 otherwise. | |
114 | * Assumptions: |der|, |der_len| & |out_ctr| are not NULL. | |
115 | */ | |
116 | static int x942_encode_otherinfo(int nid, size_t keylen, | |
117 | const unsigned char *ukm, size_t ukmlen, | |
118 | unsigned char **der, size_t *der_len, | |
119 | unsigned char **out_ctr) | |
120 | { | |
121 | unsigned char *p, *encoded = NULL; | |
122 | int ret = 0, encoded_len; | |
123 | long tlen; | |
124 | /* "magic" value to check offset is sane */ | |
125 | static unsigned char ctr[4] = { 0x00, 0x00, 0x00, 0x01 }; | |
126 | X509_ALGOR *ksi = NULL; | |
127 | ASN1_OBJECT *alg_oid = NULL; | |
128 | ASN1_OCTET_STRING *ctr_oct = NULL, *ukm_oct = NULL; | |
129 | ||
130 | /* set the KeySpecificInfo - which contains an algorithm oid and counter */ | |
131 | ksi = X509_ALGOR_new(); | |
132 | alg_oid = OBJ_dup(OBJ_nid2obj(nid)); | |
133 | ctr_oct = ASN1_OCTET_STRING_new(); | |
134 | if (ksi == NULL | |
135 | || alg_oid == NULL | |
136 | || ctr_oct == NULL | |
137 | || !ASN1_OCTET_STRING_set(ctr_oct, ctr, sizeof(ctr)) | |
138 | || !X509_ALGOR_set0(ksi, alg_oid, V_ASN1_OCTET_STRING, ctr_oct)) | |
139 | goto err; | |
140 | /* NULL these as they now belong to ksi */ | |
141 | alg_oid = NULL; | |
142 | ctr_oct = NULL; | |
143 | ||
144 | /* Set the optional partyAInfo */ | |
145 | if (ukm != NULL) { | |
146 | ukm_oct = ASN1_OCTET_STRING_new(); | |
147 | if (ukm_oct == NULL) | |
148 | goto err; | |
149 | ASN1_OCTET_STRING_set(ukm_oct, (unsigned char *)ukm, ukmlen); | |
150 | } | |
151 | /* Generate the OtherInfo DER data */ | |
152 | encoded_len = CMS_SharedInfo_encode(&encoded, ksi, ukm_oct, keylen); | |
153 | if (encoded_len <= 0) | |
154 | goto err; | |
155 | ||
156 | /* Parse the encoded data to find the offset of the counter data */ | |
157 | p = encoded; | |
158 | tlen = (long)encoded_len; | |
159 | if (skip_asn1(&p, &tlen, V_ASN1_SEQUENCE) | |
160 | && skip_asn1(&p, &tlen, V_ASN1_SEQUENCE) | |
161 | && skip_asn1(&p, &tlen, V_ASN1_OBJECT) | |
162 | && skip_asn1(&p, &tlen, V_ASN1_OCTET_STRING) | |
163 | && CRYPTO_memcmp(p, ctr, 4) == 0) { | |
164 | *out_ctr = p; | |
165 | *der = encoded; | |
166 | *der_len = (size_t)encoded_len; | |
167 | ret = 1; | |
168 | } | |
169 | err: | |
170 | if (ret != 1) | |
171 | OPENSSL_free(encoded); | |
172 | ASN1_OCTET_STRING_free(ctr_oct); | |
173 | ASN1_OCTET_STRING_free(ukm_oct); | |
174 | ASN1_OBJECT_free(alg_oid); | |
175 | X509_ALGOR_free(ksi); | |
176 | return ret; | |
177 | } | |
178 | ||
179 | static int x942kdf_hash_kdm(const EVP_MD *kdf_md, | |
180 | const unsigned char *z, size_t z_len, | |
181 | const unsigned char *other, size_t other_len, | |
182 | unsigned char *ctr, | |
183 | unsigned char *derived_key, size_t derived_key_len) | |
184 | { | |
185 | int ret = 0, hlen; | |
186 | size_t counter, out_len, len = derived_key_len; | |
187 | unsigned char mac[EVP_MAX_MD_SIZE]; | |
188 | unsigned char *out = derived_key; | |
189 | EVP_MD_CTX *ctx = NULL, *ctx_init = NULL; | |
190 | ||
191 | if (z_len > X942KDF_MAX_INLEN || other_len > X942KDF_MAX_INLEN | |
192 | || derived_key_len > X942KDF_MAX_INLEN | |
193 | || derived_key_len == 0) { | |
e3405a4a | 194 | ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); |
1aec7716 SL |
195 | return 0; |
196 | } | |
197 | ||
198 | hlen = EVP_MD_size(kdf_md); | |
199 | if (hlen <= 0) | |
200 | return 0; | |
201 | out_len = (size_t)hlen; | |
202 | ||
203 | ctx = EVP_MD_CTX_create(); | |
204 | ctx_init = EVP_MD_CTX_create(); | |
205 | if (ctx == NULL || ctx_init == NULL) | |
206 | goto end; | |
207 | ||
208 | if (!EVP_DigestInit(ctx_init, kdf_md)) | |
209 | goto end; | |
210 | ||
211 | for (counter = 1;; counter++) { | |
212 | /* updating the ctr modifies 4 bytes in the 'other' buffer */ | |
213 | ctr[0] = (unsigned char)((counter >> 24) & 0xff); | |
214 | ctr[1] = (unsigned char)((counter >> 16) & 0xff); | |
215 | ctr[2] = (unsigned char)((counter >> 8) & 0xff); | |
216 | ctr[3] = (unsigned char)(counter & 0xff); | |
217 | ||
218 | if (!EVP_MD_CTX_copy_ex(ctx, ctx_init) | |
219 | || !EVP_DigestUpdate(ctx, z, z_len) | |
220 | || !EVP_DigestUpdate(ctx, other, other_len)) | |
221 | goto end; | |
222 | if (len >= out_len) { | |
223 | if (!EVP_DigestFinal_ex(ctx, out, NULL)) | |
224 | goto end; | |
225 | out += out_len; | |
226 | len -= out_len; | |
227 | if (len == 0) | |
228 | break; | |
229 | } else { | |
230 | if (!EVP_DigestFinal_ex(ctx, mac, NULL)) | |
231 | goto end; | |
232 | memcpy(out, mac, len); | |
233 | break; | |
234 | } | |
235 | } | |
236 | ret = 1; | |
237 | end: | |
238 | EVP_MD_CTX_free(ctx); | |
239 | EVP_MD_CTX_free(ctx_init); | |
240 | OPENSSL_cleanse(mac, sizeof(mac)); | |
241 | return ret; | |
242 | } | |
243 | ||
e3405a4a | 244 | static void *x942kdf_new(void *provctx) |
1aec7716 | 245 | { |
e3405a4a | 246 | KDF_X942 *ctx; |
1aec7716 | 247 | |
e3405a4a P |
248 | if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) |
249 | ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); | |
250 | ctx->provctx = provctx; | |
251 | return ctx; | |
1aec7716 SL |
252 | } |
253 | ||
e3405a4a | 254 | static void x942kdf_reset(void *vctx) |
1aec7716 | 255 | { |
e3405a4a | 256 | KDF_X942 *ctx = (KDF_X942 *)vctx; |
1aec7716 | 257 | |
df2f8af4 | 258 | EVP_MD_meth_free(ctx->md); |
e3405a4a P |
259 | OPENSSL_clear_free(ctx->secret, ctx->secret_len); |
260 | OPENSSL_clear_free(ctx->ukm, ctx->ukm_len); | |
261 | memset(ctx, 0, sizeof(*ctx)); | |
1aec7716 SL |
262 | } |
263 | ||
e3405a4a | 264 | static void x942kdf_free(void *vctx) |
1aec7716 | 265 | { |
e3405a4a | 266 | KDF_X942 *ctx = (KDF_X942 *)vctx; |
1aec7716 | 267 | |
e3405a4a | 268 | x942kdf_reset(ctx); |
e3405a4a | 269 | OPENSSL_free(ctx); |
1aec7716 SL |
270 | } |
271 | ||
e3405a4a P |
272 | static int x942kdf_set_buffer(unsigned char **out, size_t *out_len, |
273 | const OSSL_PARAM *p) | |
1aec7716 | 274 | { |
e3405a4a | 275 | if (p->data_size == 0 || p->data == NULL) |
1aec7716 SL |
276 | return 1; |
277 | ||
e3405a4a P |
278 | OPENSSL_free(*out); |
279 | *out = NULL; | |
280 | return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); | |
1aec7716 SL |
281 | } |
282 | ||
e3405a4a | 283 | static size_t x942kdf_size(KDF_X942 *ctx) |
1aec7716 SL |
284 | { |
285 | int len; | |
286 | ||
e3405a4a P |
287 | if (ctx->md == NULL) { |
288 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); | |
1aec7716 SL |
289 | return 0; |
290 | } | |
e3405a4a | 291 | len = EVP_MD_size(ctx->md); |
1aec7716 SL |
292 | return (len <= 0) ? 0 : (size_t)len; |
293 | } | |
294 | ||
e3405a4a | 295 | static int x942kdf_derive(void *vctx, unsigned char *key, size_t keylen) |
1aec7716 | 296 | { |
e3405a4a | 297 | KDF_X942 *ctx = (KDF_X942 *)vctx; |
1aec7716 SL |
298 | int ret = 0; |
299 | unsigned char *ctr; | |
300 | unsigned char *der = NULL; | |
301 | size_t der_len = 0; | |
302 | ||
e3405a4a P |
303 | if (ctx->secret == NULL) { |
304 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); | |
1aec7716 SL |
305 | return 0; |
306 | } | |
e3405a4a P |
307 | if (ctx->md == NULL) { |
308 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); | |
1aec7716 SL |
309 | return 0; |
310 | } | |
e3405a4a P |
311 | if (ctx->cek_nid == NID_undef) { |
312 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG); | |
1aec7716 SL |
313 | return 0; |
314 | } | |
e3405a4a | 315 | if (ctx->ukm != NULL && ctx->ukm_len >= X942KDF_MAX_INLEN) { |
1aec7716 SL |
316 | /* |
317 | * Note the ukm length MUST be 512 bits. | |
318 | * For backwards compatibility the old check is being done. | |
319 | */ | |
e3405a4a | 320 | ERR_raise(ERR_LIB_PROV, PROV_R_INAVLID_UKM_LENGTH); |
1aec7716 SL |
321 | return 0; |
322 | } | |
e3405a4a P |
323 | if (keylen != ctx->dkm_len) { |
324 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG); | |
1aec7716 SL |
325 | return 0; |
326 | } | |
327 | /* generate the otherinfo der */ | |
e3405a4a P |
328 | if (!x942_encode_otherinfo(ctx->cek_nid, ctx->dkm_len, |
329 | ctx->ukm, ctx->ukm_len, | |
1aec7716 | 330 | &der, &der_len, &ctr)) { |
e3405a4a | 331 | ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING); |
1aec7716 SL |
332 | return 0; |
333 | } | |
e3405a4a | 334 | ret = x942kdf_hash_kdm(ctx->md, ctx->secret, ctx->secret_len, |
1aec7716 SL |
335 | der, der_len, ctr, key, keylen); |
336 | OPENSSL_free(der); | |
337 | return ret; | |
338 | } | |
339 | ||
e3405a4a P |
340 | static int x942kdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) |
341 | { | |
342 | const OSSL_PARAM *p; | |
343 | KDF_X942 *ctx = vctx; | |
344 | EVP_MD *md; | |
345 | const char *properties = NULL; | |
346 | size_t i; | |
347 | ||
348 | /* Grab search properties, this should be before the digest lookup */ | |
349 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES)) | |
350 | != NULL) { | |
351 | if (p->data_type != OSSL_PARAM_UTF8_STRING) | |
352 | return 0; | |
353 | properties = p->data; | |
354 | } | |
355 | /* Handle aliasing of digest parameter names */ | |
356 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { | |
357 | if (p->data_type != OSSL_PARAM_UTF8_STRING) | |
358 | return 0; | |
359 | md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data, | |
360 | properties); | |
361 | if (md == NULL) { | |
362 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); | |
363 | return 0; | |
364 | } | |
365 | EVP_MD_meth_free(ctx->md); | |
366 | ctx->md = md; | |
367 | } | |
368 | ||
369 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL | |
370 | || (p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) | |
371 | if (!x942kdf_set_buffer(&ctx->secret, &ctx->secret_len, p)) | |
372 | return 0; | |
373 | ||
374 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_UKM)) != NULL) | |
375 | if (!x942kdf_set_buffer(&ctx->ukm, &ctx->ukm_len, p)) | |
376 | return 0; | |
377 | ||
378 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG)) != NULL) { | |
379 | if (p->data_type != OSSL_PARAM_UTF8_STRING) | |
380 | return 0; | |
381 | ctx->cek_nid = OBJ_sn2nid(p->data); | |
382 | for (i = 0; i < OSSL_NELEM(kek_algs); i++) | |
383 | if (kek_algs[i].nid == ctx->cek_nid) | |
384 | goto cek_found; | |
385 | ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_CEK_ALG); | |
386 | return 0; | |
387 | cek_found: | |
388 | ctx->dkm_len = kek_algs[i].keklen; | |
389 | } | |
390 | return 1; | |
391 | } | |
392 | ||
393 | static const OSSL_PARAM *x942kdf_settable_ctx_params(void) | |
394 | { | |
395 | static const OSSL_PARAM known_settable_ctx_params[] = { | |
396 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), | |
397 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), | |
398 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0), | |
399 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), | |
400 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_UKM, NULL, 0), | |
401 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), | |
402 | OSSL_PARAM_END | |
403 | }; | |
404 | return known_settable_ctx_params; | |
405 | } | |
406 | ||
407 | static int x942kdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) | |
408 | { | |
409 | KDF_X942 *ctx = (KDF_X942 *)vctx; | |
410 | OSSL_PARAM *p; | |
411 | ||
412 | if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) | |
413 | return OSSL_PARAM_set_size_t(p, x942kdf_size(ctx)); | |
414 | return -2; | |
415 | } | |
416 | ||
417 | static const OSSL_PARAM *x942kdf_gettable_ctx_params(void) | |
418 | { | |
419 | static const OSSL_PARAM known_gettable_ctx_params[] = { | |
420 | OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), | |
421 | OSSL_PARAM_END | |
422 | }; | |
423 | return known_gettable_ctx_params; | |
424 | } | |
425 | ||
426 | const OSSL_DISPATCH kdf_x942_kdf_functions[] = { | |
427 | { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))x942kdf_new }, | |
428 | { OSSL_FUNC_KDF_FREECTX, (void(*)(void))x942kdf_free }, | |
429 | { OSSL_FUNC_KDF_RESET, (void(*)(void))x942kdf_reset }, | |
430 | { OSSL_FUNC_KDF_DERIVE, (void(*)(void))x942kdf_derive }, | |
431 | { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, | |
432 | (void(*)(void))x942kdf_settable_ctx_params }, | |
433 | { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))x942kdf_set_ctx_params }, | |
434 | { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, | |
435 | (void(*)(void))x942kdf_gettable_ctx_params }, | |
436 | { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))x942kdf_get_ctx_params }, | |
437 | { 0, NULL } | |
1aec7716 SL |
438 | }; |
439 | ||
440 | #endif /* OPENSSL_NO_CMS */ |