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