]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
b6461792 | 2 | * Copyright 2009-2024 The OpenSSL Project Authors. All Rights Reserved. |
d2a53c22 | 3 | * |
08ddd302 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
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 | |
d2a53c22 DSH |
8 | */ |
9 | ||
b39fc560 | 10 | #include "internal/cryptlib.h" |
d2a53c22 DSH |
11 | #include <openssl/asn1t.h> |
12 | #include <openssl/pem.h> | |
13 | #include <openssl/x509v3.h> | |
14 | #include <openssl/err.h> | |
15 | #include <openssl/cms.h> | |
16 | #include <openssl/rand.h> | |
17 | #include <openssl/aes.h> | |
ad57a13b | 18 | #include "internal/sizes.h" |
25f2138b | 19 | #include "crypto/asn1.h" |
ad57a13b | 20 | #include "cms_local.h" |
d2a53c22 | 21 | |
0f113f3e MC |
22 | int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri, |
23 | unsigned char *pass, ossl_ssize_t passlen) | |
24 | { | |
25 | CMS_PasswordRecipientInfo *pwri; | |
26 | if (ri->type != CMS_RECIPINFO_PASS) { | |
9311d0c4 | 27 | ERR_raise(ERR_LIB_CMS, CMS_R_NOT_PWRI); |
0f113f3e MC |
28 | return 0; |
29 | } | |
30 | ||
31 | pwri = ri->d.pwri; | |
32 | pwri->pass = pass; | |
33 | if (pass && passlen < 0) | |
34 | passlen = strlen((char *)pass); | |
35 | pwri->passlen = passlen; | |
36 | return 1; | |
37 | } | |
d2a53c22 DSH |
38 | |
39 | CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms, | |
0f113f3e MC |
40 | int iter, int wrap_nid, |
41 | int pbe_nid, | |
42 | unsigned char *pass, | |
43 | ossl_ssize_t passlen, | |
44 | const EVP_CIPHER *kekciph) | |
45 | { | |
924663c3 | 46 | STACK_OF(CMS_RecipientInfo) *ris; |
0f113f3e | 47 | CMS_RecipientInfo *ri = NULL; |
924663c3 | 48 | CMS_EncryptedContentInfo *ec; |
0f113f3e | 49 | CMS_PasswordRecipientInfo *pwri; |
846ec07d | 50 | EVP_CIPHER_CTX *ctx = NULL; |
0f113f3e MC |
51 | X509_ALGOR *encalg = NULL; |
52 | unsigned char iv[EVP_MAX_IV_LENGTH]; | |
53 | int ivlen; | |
53155f1c | 54 | const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms); |
0f113f3e | 55 | |
53155f1c | 56 | ec = ossl_cms_get0_env_enc_content(cms); |
924663c3 JZ |
57 | if (ec == NULL) |
58 | return NULL; | |
59 | ris = CMS_get0_RecipientInfos(cms); | |
60 | if (ris == NULL) | |
0f113f3e MC |
61 | return NULL; |
62 | ||
63 | if (wrap_nid <= 0) | |
64 | wrap_nid = NID_id_alg_PWRI_KEK; | |
65 | ||
66 | if (pbe_nid <= 0) | |
67 | pbe_nid = NID_id_pbkdf2; | |
68 | ||
69 | /* Get from enveloped data */ | |
70 | if (kekciph == NULL) | |
924663c3 | 71 | kekciph = ec->cipher; |
0f113f3e MC |
72 | |
73 | if (kekciph == NULL) { | |
9311d0c4 | 74 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_CIPHER); |
0f113f3e MC |
75 | return NULL; |
76 | } | |
77 | if (wrap_nid != NID_id_alg_PWRI_KEK) { | |
9311d0c4 | 78 | ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); |
0f113f3e MC |
79 | return NULL; |
80 | } | |
81 | ||
82 | /* Setup algorithm identifier for cipher */ | |
83 | encalg = X509_ALGOR_new(); | |
90945fa3 | 84 | if (encalg == NULL) { |
e077455e RL |
85 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); |
86 | goto err; | |
90945fa3 | 87 | } |
846ec07d | 88 | ctx = EVP_CIPHER_CTX_new(); |
9dddcd90 | 89 | if (ctx == NULL) { |
e077455e | 90 | ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); |
9dddcd90 | 91 | goto err; |
92 | } | |
0f113f3e | 93 | |
846ec07d | 94 | if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) { |
9311d0c4 | 95 | ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); |
0f113f3e MC |
96 | goto err; |
97 | } | |
98 | ||
ed576acd | 99 | ivlen = EVP_CIPHER_CTX_get_iv_length(ctx); |
83ab43da DB |
100 | if (ivlen < 0) { |
101 | ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); | |
102 | goto err; | |
103 | } | |
0f113f3e MC |
104 | |
105 | if (ivlen > 0) { | |
5cbd2ea3 | 106 | if (RAND_bytes_ex(ossl_cms_ctx_get0_libctx(cms_ctx), iv, ivlen, 0) <= 0) |
0f113f3e | 107 | goto err; |
846ec07d | 108 | if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) { |
9311d0c4 | 109 | ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); |
0f113f3e MC |
110 | goto err; |
111 | } | |
112 | encalg->parameter = ASN1_TYPE_new(); | |
113 | if (!encalg->parameter) { | |
e077455e | 114 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); |
0f113f3e MC |
115 | goto err; |
116 | } | |
846ec07d | 117 | if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) { |
9311d0c4 | 118 | ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); |
0f113f3e MC |
119 | goto err; |
120 | } | |
121 | } | |
122 | ||
ed576acd | 123 | encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_get_type(ctx)); |
0f113f3e | 124 | |
846ec07d RL |
125 | EVP_CIPHER_CTX_free(ctx); |
126 | ctx = NULL; | |
0f113f3e MC |
127 | |
128 | /* Initialize recipient info */ | |
129 | ri = M_ASN1_new_of(CMS_RecipientInfo); | |
e077455e RL |
130 | if (ri == NULL) { |
131 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); | |
132 | goto err; | |
133 | } | |
0f113f3e MC |
134 | |
135 | ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo); | |
e077455e RL |
136 | if (ri->d.pwri == NULL) { |
137 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); | |
138 | goto err; | |
139 | } | |
0f113f3e MC |
140 | ri->type = CMS_RECIPINFO_PASS; |
141 | ||
142 | pwri = ri->d.pwri; | |
c1669f41 | 143 | pwri->cms_ctx = cms_ctx; |
0f113f3e MC |
144 | /* Since this is overwritten, free up empty structure already there */ |
145 | X509_ALGOR_free(pwri->keyEncryptionAlgorithm); | |
146 | pwri->keyEncryptionAlgorithm = X509_ALGOR_new(); | |
e077455e RL |
147 | if (pwri->keyEncryptionAlgorithm == NULL) { |
148 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); | |
149 | goto err; | |
150 | } | |
0f113f3e MC |
151 | pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid); |
152 | pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new(); | |
e077455e RL |
153 | if (pwri->keyEncryptionAlgorithm->parameter == NULL) { |
154 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); | |
155 | goto err; | |
156 | } | |
0f113f3e MC |
157 | |
158 | if (!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR), | |
159 | &pwri->keyEncryptionAlgorithm->parameter-> | |
e077455e RL |
160 | value.sequence)) { |
161 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); | |
162 | goto err; | |
163 | } | |
0f113f3e MC |
164 | pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE; |
165 | ||
166 | X509_ALGOR_free(encalg); | |
167 | encalg = NULL; | |
168 | ||
169 | /* Setup PBE algorithm */ | |
170 | ||
171 | pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1); | |
172 | ||
12a765a5 | 173 | if (pwri->keyDerivationAlgorithm == NULL) |
0f113f3e MC |
174 | goto err; |
175 | ||
176 | CMS_RecipientInfo_set0_password(ri, pass, passlen); | |
177 | pwri->version = 0; | |
178 | ||
e077455e RL |
179 | if (!sk_CMS_RecipientInfo_push(ris, ri)) { |
180 | ERR_raise(ERR_LIB_CMS, ERR_R_CRYPTO_LIB); | |
181 | goto err; | |
182 | } | |
0f113f3e MC |
183 | |
184 | return ri; | |
185 | ||
0f113f3e | 186 | err: |
846ec07d | 187 | EVP_CIPHER_CTX_free(ctx); |
0f113f3e MC |
188 | if (ri) |
189 | M_ASN1_free_of(ri, CMS_RecipientInfo); | |
222561fe | 190 | X509_ALGOR_free(encalg); |
0f113f3e MC |
191 | return NULL; |
192 | ||
193 | } | |
194 | ||
195 | /* | |
196 | * This is an implementation of the key wrapping mechanism in RFC3211, at | |
197 | * some point this should go into EVP. | |
d2a53c22 DSH |
198 | */ |
199 | ||
200 | static int kek_unwrap_key(unsigned char *out, size_t *outlen, | |
0f113f3e MC |
201 | const unsigned char *in, size_t inlen, |
202 | EVP_CIPHER_CTX *ctx) | |
203 | { | |
ed576acd | 204 | size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx); |
0f113f3e MC |
205 | unsigned char *tmp; |
206 | int outl, rv = 0; | |
6f22bcd6 NH |
207 | |
208 | if (blocklen == 0) | |
209 | return 0; | |
210 | ||
0f113f3e MC |
211 | if (inlen < 2 * blocklen) { |
212 | /* too small */ | |
213 | return 0; | |
214 | } | |
215 | if (inlen % blocklen) { | |
216 | /* Invalid size */ | |
217 | return 0; | |
218 | } | |
e077455e | 219 | if ((tmp = OPENSSL_malloc(inlen)) == NULL) |
918bb865 | 220 | return 0; |
0f113f3e MC |
221 | /* setup IV by decrypting last two blocks */ |
222 | if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, | |
223 | in + inlen - 2 * blocklen, blocklen * 2) | |
224 | /* | |
225 | * Do a decrypt of last decrypted block to set IV to correct value | |
226 | * output it to start of buffer so we don't corrupt decrypted block | |
227 | * this works because buffer is at least two block lengths long. | |
228 | */ | |
229 | || !EVP_DecryptUpdate(ctx, tmp, &outl, | |
230 | tmp + inlen - blocklen, blocklen) | |
231 | /* Can now decrypt first n - 1 blocks */ | |
232 | || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen) | |
233 | ||
234 | /* Reset IV to original value */ | |
235 | || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) | |
236 | /* Decrypt again */ | |
237 | || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen)) | |
238 | goto err; | |
239 | /* Check check bytes */ | |
240 | if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { | |
241 | /* Check byte failure */ | |
242 | goto err; | |
243 | } | |
244 | if (inlen < (size_t)(tmp[0] - 4)) { | |
245 | /* Invalid length value */ | |
246 | goto err; | |
247 | } | |
248 | *outlen = (size_t)tmp[0]; | |
249 | memcpy(out, tmp + 4, *outlen); | |
250 | rv = 1; | |
251 | err: | |
4b45c6e5 | 252 | OPENSSL_clear_free(tmp, inlen); |
0f113f3e MC |
253 | return rv; |
254 | ||
255 | } | |
d2a53c22 DSH |
256 | |
257 | static int kek_wrap_key(unsigned char *out, size_t *outlen, | |
0f113f3e | 258 | const unsigned char *in, size_t inlen, |
c1669f41 | 259 | EVP_CIPHER_CTX *ctx, const CMS_CTX *cms_ctx) |
0f113f3e | 260 | { |
ed576acd | 261 | size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx); |
0f113f3e MC |
262 | size_t olen; |
263 | int dummy; | |
6f22bcd6 NH |
264 | |
265 | if (blocklen == 0) | |
266 | return 0; | |
267 | ||
0f113f3e MC |
268 | /* |
269 | * First decide length of output buffer: need header and round up to | |
270 | * multiple of block length. | |
271 | */ | |
272 | olen = (inlen + 4 + blocklen - 1) / blocklen; | |
273 | olen *= blocklen; | |
274 | if (olen < 2 * blocklen) { | |
275 | /* Key too small */ | |
276 | return 0; | |
277 | } | |
278 | if (inlen > 0xFF) { | |
279 | /* Key too large */ | |
280 | return 0; | |
281 | } | |
282 | if (out) { | |
283 | /* Set header */ | |
284 | out[0] = (unsigned char)inlen; | |
285 | out[1] = in[0] ^ 0xFF; | |
286 | out[2] = in[1] ^ 0xFF; | |
287 | out[3] = in[2] ^ 0xFF; | |
288 | memcpy(out + 4, in, inlen); | |
289 | /* Add random padding to end */ | |
266483d2 | 290 | if (olen > inlen + 4 |
53155f1c | 291 | && RAND_bytes_ex(ossl_cms_ctx_get0_libctx(cms_ctx), out + 4 + inlen, |
5cbd2ea3 | 292 | olen - 4 - inlen, 0) <= 0) |
266483d2 | 293 | return 0; |
0f113f3e MC |
294 | /* Encrypt twice */ |
295 | if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen) | |
296 | || !EVP_EncryptUpdate(ctx, out, &dummy, out, olen)) | |
297 | return 0; | |
298 | } | |
299 | ||
300 | *outlen = olen; | |
301 | ||
302 | return 1; | |
303 | } | |
d2a53c22 DSH |
304 | |
305 | /* Encrypt/Decrypt content key in PWRI recipient info */ | |
306 | ||
53155f1c SL |
307 | int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, |
308 | CMS_RecipientInfo *ri, int en_de) | |
0f113f3e MC |
309 | { |
310 | CMS_EncryptedContentInfo *ec; | |
311 | CMS_PasswordRecipientInfo *pwri; | |
0f113f3e MC |
312 | int r = 0; |
313 | X509_ALGOR *algtmp, *kekalg = NULL; | |
29f4c357 | 314 | EVP_CIPHER_CTX *kekctx = NULL; |
ad57a13b | 315 | char name[OSSL_MAX_NAME_SIZE]; |
c1669f41 | 316 | EVP_CIPHER *kekcipher; |
0f113f3e MC |
317 | unsigned char *key = NULL; |
318 | size_t keylen; | |
53155f1c | 319 | const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms); |
0f113f3e | 320 | |
53155f1c | 321 | ec = ossl_cms_get0_env_enc_content(cms); |
0f113f3e MC |
322 | |
323 | pwri = ri->d.pwri; | |
0f113f3e | 324 | |
12a765a5 | 325 | if (pwri->pass == NULL) { |
9311d0c4 | 326 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_PASSWORD); |
0f113f3e MC |
327 | return 0; |
328 | } | |
329 | algtmp = pwri->keyEncryptionAlgorithm; | |
330 | ||
331 | if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) { | |
9311d0c4 | 332 | ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); |
0f113f3e MC |
333 | return 0; |
334 | } | |
335 | ||
e93c8748 DSH |
336 | kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR), |
337 | algtmp->parameter); | |
338 | ||
0f113f3e | 339 | if (kekalg == NULL) { |
9311d0c4 | 340 | ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER); |
0f113f3e MC |
341 | return 0; |
342 | } | |
343 | ||
ad57a13b | 344 | OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0); |
53155f1c SL |
345 | kekcipher = EVP_CIPHER_fetch(ossl_cms_ctx_get0_libctx(cms_ctx), name, |
346 | ossl_cms_ctx_get0_propq(cms_ctx)); | |
0f113f3e | 347 | |
c1669f41 | 348 | if (kekcipher == NULL) { |
9311d0c4 | 349 | ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER); |
c1669f41 | 350 | goto err; |
0f113f3e MC |
351 | } |
352 | ||
29f4c357 MC |
353 | kekctx = EVP_CIPHER_CTX_new(); |
354 | if (kekctx == NULL) { | |
e077455e | 355 | ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); |
c1669f41 | 356 | goto err; |
29f4c357 | 357 | } |
0f113f3e | 358 | /* Fixup cipher based on AlgorithmIdentifier to set IV etc */ |
846ec07d | 359 | if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de)) |
0f113f3e | 360 | goto err; |
846ec07d | 361 | EVP_CIPHER_CTX_set_padding(kekctx, 0); |
49c9c1b3 | 362 | if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) { |
9311d0c4 | 363 | ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); |
0f113f3e MC |
364 | goto err; |
365 | } | |
366 | ||
367 | algtmp = pwri->keyDerivationAlgorithm; | |
368 | ||
369 | /* Finish password based key derivation to setup key in "ctx" */ | |
370 | ||
371 | if (EVP_PBE_CipherInit(algtmp->algorithm, | |
372 | (char *)pwri->pass, pwri->passlen, | |
846ec07d | 373 | algtmp->parameter, kekctx, en_de) < 0) { |
9311d0c4 | 374 | ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); |
0f113f3e MC |
375 | goto err; |
376 | } | |
377 | ||
378 | /* Finally wrap/unwrap the key */ | |
379 | ||
380 | if (en_de) { | |
381 | ||
c1669f41 | 382 | if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx, cms_ctx)) |
0f113f3e MC |
383 | goto err; |
384 | ||
385 | key = OPENSSL_malloc(keylen); | |
386 | ||
90945fa3 | 387 | if (key == NULL) |
0f113f3e MC |
388 | goto err; |
389 | ||
c1669f41 | 390 | if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx, cms_ctx)) |
0f113f3e MC |
391 | goto err; |
392 | pwri->encryptedKey->data = key; | |
393 | pwri->encryptedKey->length = keylen; | |
394 | } else { | |
395 | key = OPENSSL_malloc(pwri->encryptedKey->length); | |
e077455e | 396 | if (key == NULL) |
0f113f3e | 397 | goto err; |
0f113f3e MC |
398 | if (!kek_unwrap_key(key, &keylen, |
399 | pwri->encryptedKey->data, | |
846ec07d | 400 | pwri->encryptedKey->length, kekctx)) { |
9311d0c4 | 401 | ERR_raise(ERR_LIB_CMS, CMS_R_UNWRAP_FAILURE); |
0f113f3e MC |
402 | goto err; |
403 | } | |
404 | ||
4128136a | 405 | OPENSSL_clear_free(ec->key, ec->keylen); |
0f113f3e MC |
406 | ec->key = key; |
407 | ec->keylen = keylen; | |
408 | ||
409 | } | |
410 | ||
411 | r = 1; | |
412 | ||
413 | err: | |
c1669f41 | 414 | EVP_CIPHER_free(kekcipher); |
846ec07d | 415 | EVP_CIPHER_CTX_free(kekctx); |
0f113f3e | 416 | |
b548a1f1 | 417 | if (!r) |
0f113f3e MC |
418 | OPENSSL_free(key); |
419 | X509_ALGOR_free(kekalg); | |
420 | ||
421 | return r; | |
422 | ||
423 | } |