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