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