]>
Commit | Line | Data |
---|---|---|
94b2c29f | 1 | /* crypto/cms/cms_env.c */ |
40720ce3 MC |
2 | /* |
3 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | |
94b2c29f DSH |
4 | * project. |
5 | */ | |
6 | /* ==================================================================== | |
7 | * Copyright (c) 2008 The OpenSSL Project. All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * 1. Redistributions of source code must retain the above copyright | |
40720ce3 | 14 | * notice, this list of conditions and the following disclaimer. |
94b2c29f DSH |
15 | * |
16 | * 2. Redistributions in binary form must reproduce the above copyright | |
17 | * notice, this list of conditions and the following disclaimer in | |
18 | * the documentation and/or other materials provided with the | |
19 | * distribution. | |
20 | * | |
21 | * 3. All advertising materials mentioning features or use of this | |
22 | * software must display the following acknowledgment: | |
23 | * "This product includes software developed by the OpenSSL Project | |
24 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
25 | * | |
26 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
27 | * endorse or promote products derived from this software without | |
28 | * prior written permission. For written permission, please contact | |
29 | * licensing@OpenSSL.org. | |
30 | * | |
31 | * 5. Products derived from this software may not be called "OpenSSL" | |
32 | * nor may "OpenSSL" appear in their names without prior written | |
33 | * permission of the OpenSSL Project. | |
34 | * | |
35 | * 6. Redistributions of any form whatsoever must retain the following | |
36 | * acknowledgment: | |
37 | * "This product includes software developed by the OpenSSL Project | |
38 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
39 | * | |
40 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
41 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
42 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
43 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
44 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
45 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
47 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
49 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
51 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
52 | * ==================================================================== | |
53 | */ | |
54 | ||
55 | #include "cryptlib.h" | |
56 | #include <openssl/asn1t.h> | |
57 | #include <openssl/pem.h> | |
58 | #include <openssl/x509v3.h> | |
59 | #include <openssl/err.h> | |
60 | #include <openssl/cms.h> | |
61 | #include <openssl/rand.h> | |
62 | #include <openssl/aes.h> | |
63 | #include "cms_lcl.h" | |
64 | ||
65 | /* CMS EnvelopedData Utilities */ | |
66 | ||
67 | DECLARE_ASN1_ITEM(CMS_EnvelopedData) | |
68 | DECLARE_ASN1_ITEM(CMS_RecipientInfo) | |
69 | DECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo) | |
70 | DECLARE_ASN1_ITEM(CMS_KEKRecipientInfo) | |
71 | DECLARE_ASN1_ITEM(CMS_OtherKeyAttribute) | |
72 | ||
73 | DECLARE_STACK_OF(CMS_RecipientInfo) | |
74 | ||
75 | static CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms) | |
40720ce3 MC |
76 | { |
77 | if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) { | |
78 | CMSerr(CMS_F_CMS_GET0_ENVELOPED, | |
79 | CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA); | |
80 | return NULL; | |
81 | } | |
82 | return cms->d.envelopedData; | |
83 | } | |
94b2c29f DSH |
84 | |
85 | static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms) | |
40720ce3 MC |
86 | { |
87 | if (cms->d.other == NULL) { | |
88 | cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData); | |
89 | if (!cms->d.envelopedData) { | |
90 | CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT, ERR_R_MALLOC_FAILURE); | |
91 | return NULL; | |
92 | } | |
93 | cms->d.envelopedData->version = 0; | |
94 | cms->d.envelopedData->encryptedContentInfo->contentType = | |
95 | OBJ_nid2obj(NID_pkcs7_data); | |
96 | ASN1_OBJECT_free(cms->contentType); | |
97 | cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped); | |
98 | return cms->d.envelopedData; | |
99 | } | |
100 | return cms_get0_enveloped(cms); | |
101 | } | |
94b2c29f DSH |
102 | |
103 | STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms) | |
40720ce3 MC |
104 | { |
105 | CMS_EnvelopedData *env; | |
106 | env = cms_get0_enveloped(cms); | |
107 | if (!env) | |
108 | return NULL; | |
109 | return env->recipientInfos; | |
110 | } | |
94b2c29f DSH |
111 | |
112 | int CMS_RecipientInfo_type(CMS_RecipientInfo *ri) | |
40720ce3 MC |
113 | { |
114 | return ri->type; | |
115 | } | |
94b2c29f DSH |
116 | |
117 | CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher) | |
40720ce3 MC |
118 | { |
119 | CMS_ContentInfo *cms; | |
120 | CMS_EnvelopedData *env; | |
121 | cms = CMS_ContentInfo_new(); | |
122 | if (!cms) | |
123 | goto merr; | |
124 | env = cms_enveloped_data_init(cms); | |
125 | if (!env) | |
126 | goto merr; | |
127 | if (!cms_EncryptedContent_init(env->encryptedContentInfo, | |
128 | cipher, NULL, 0)) | |
129 | goto merr; | |
130 | return cms; | |
131 | merr: | |
132 | if (cms) | |
133 | CMS_ContentInfo_free(cms); | |
134 | CMSerr(CMS_F_CMS_ENVELOPEDDATA_CREATE, ERR_R_MALLOC_FAILURE); | |
135 | return NULL; | |
136 | } | |
94b2c29f DSH |
137 | |
138 | /* Key Transport Recipient Info (KTRI) routines */ | |
139 | ||
40720ce3 MC |
140 | /* |
141 | * Add a recipient certificate. For now only handle key transport. If we ever | |
142 | * handle key agreement will need updating. | |
94b2c29f DSH |
143 | */ |
144 | ||
145 | CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, | |
40720ce3 MC |
146 | X509 *recip, unsigned int flags) |
147 | { | |
148 | CMS_RecipientInfo *ri = NULL; | |
149 | CMS_KeyTransRecipientInfo *ktri; | |
150 | CMS_EnvelopedData *env; | |
151 | EVP_PKEY *pk = NULL; | |
152 | int type; | |
153 | env = cms_get0_enveloped(cms); | |
154 | if (!env) | |
155 | goto err; | |
156 | ||
157 | /* Initialize recipient info */ | |
158 | ri = M_ASN1_new_of(CMS_RecipientInfo); | |
159 | if (!ri) | |
160 | goto merr; | |
161 | ||
162 | /* Initialize and add key transport recipient info */ | |
163 | ||
164 | ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo); | |
165 | if (!ri->d.ktri) | |
166 | goto merr; | |
167 | ri->type = CMS_RECIPINFO_TRANS; | |
168 | ||
169 | ktri = ri->d.ktri; | |
170 | ||
171 | X509_check_purpose(recip, -1, -1); | |
172 | pk = X509_get_pubkey(recip); | |
173 | if (!pk) { | |
174 | CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_ERROR_GETTING_PUBLIC_KEY); | |
175 | goto err; | |
176 | } | |
177 | CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509); | |
178 | ktri->pkey = pk; | |
179 | ktri->recip = recip; | |
180 | ||
181 | if (flags & CMS_USE_KEYID) { | |
182 | ktri->version = 2; | |
183 | if (env->version < 2) | |
184 | env->version = 2; | |
185 | type = CMS_RECIPINFO_KEYIDENTIFIER; | |
186 | } else { | |
187 | ktri->version = 0; | |
188 | type = CMS_RECIPINFO_ISSUER_SERIAL; | |
189 | } | |
190 | ||
191 | /* | |
192 | * Not a typo: RecipientIdentifier and SignerIdentifier are the same | |
193 | * structure. | |
194 | */ | |
195 | ||
196 | if (!cms_set1_SignerIdentifier(ktri->rid, recip, type)) | |
197 | goto err; | |
198 | ||
199 | /* | |
200 | * Since we have no EVP_PKEY_ASN1_METHOD in OpenSSL 0.9.8, hard code | |
201 | * algorithm parameters. | |
202 | */ | |
203 | ||
204 | if (pk->type == EVP_PKEY_RSA) { | |
205 | X509_ALGOR_set0(ktri->keyEncryptionAlgorithm, | |
206 | OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0); | |
207 | } else { | |
208 | CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, | |
209 | CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); | |
210 | goto err; | |
211 | } | |
212 | ||
213 | if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) | |
214 | goto merr; | |
215 | ||
216 | return ri; | |
217 | ||
218 | merr: | |
219 | CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE); | |
220 | err: | |
221 | if (ri) | |
222 | M_ASN1_free_of(ri, CMS_RecipientInfo); | |
223 | return NULL; | |
224 | ||
225 | } | |
94b2c29f DSH |
226 | |
227 | int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, | |
40720ce3 MC |
228 | EVP_PKEY **pk, X509 **recip, |
229 | X509_ALGOR **palg) | |
230 | { | |
231 | CMS_KeyTransRecipientInfo *ktri; | |
232 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
233 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS, | |
234 | CMS_R_NOT_KEY_TRANSPORT); | |
235 | return 0; | |
236 | } | |
237 | ||
238 | ktri = ri->d.ktri; | |
239 | ||
240 | if (pk) | |
241 | *pk = ktri->pkey; | |
242 | if (recip) | |
243 | *recip = ktri->recip; | |
244 | if (palg) | |
245 | *palg = ktri->keyEncryptionAlgorithm; | |
246 | return 1; | |
247 | } | |
94b2c29f DSH |
248 | |
249 | int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri, | |
40720ce3 MC |
250 | ASN1_OCTET_STRING **keyid, |
251 | X509_NAME **issuer, | |
252 | ASN1_INTEGER **sno) | |
253 | { | |
254 | CMS_KeyTransRecipientInfo *ktri; | |
255 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
256 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID, | |
257 | CMS_R_NOT_KEY_TRANSPORT); | |
258 | return 0; | |
259 | } | |
260 | ktri = ri->d.ktri; | |
261 | ||
262 | return cms_SignerIdentifier_get0_signer_id(ktri->rid, keyid, issuer, sno); | |
263 | } | |
94b2c29f DSH |
264 | |
265 | int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert) | |
40720ce3 MC |
266 | { |
267 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
268 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP, | |
269 | CMS_R_NOT_KEY_TRANSPORT); | |
270 | return -2; | |
271 | } | |
272 | return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert); | |
273 | } | |
94b2c29f DSH |
274 | |
275 | int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey) | |
40720ce3 MC |
276 | { |
277 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
278 | CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY, CMS_R_NOT_KEY_TRANSPORT); | |
279 | return 0; | |
280 | } | |
281 | ri->d.ktri->pkey = pkey; | |
282 | return 1; | |
283 | } | |
94b2c29f DSH |
284 | |
285 | /* Encrypt content key in key transport recipient info */ | |
286 | ||
287 | static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms, | |
40720ce3 MC |
288 | CMS_RecipientInfo *ri) |
289 | { | |
290 | CMS_KeyTransRecipientInfo *ktri; | |
291 | CMS_EncryptedContentInfo *ec; | |
292 | unsigned char *ek = NULL; | |
293 | int eklen; | |
94b2c29f | 294 | |
40720ce3 | 295 | int ret = 0; |
94b2c29f | 296 | |
40720ce3 MC |
297 | if (ri->type != CMS_RECIPINFO_TRANS) { |
298 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_NOT_KEY_TRANSPORT); | |
299 | return 0; | |
300 | } | |
301 | ktri = ri->d.ktri; | |
302 | ec = cms->d.envelopedData->encryptedContentInfo; | |
94b2c29f | 303 | |
40720ce3 | 304 | eklen = EVP_PKEY_size(ktri->pkey); |
94b2c29f | 305 | |
40720ce3 | 306 | ek = OPENSSL_malloc(eklen); |
94b2c29f | 307 | |
40720ce3 MC |
308 | if (ek == NULL) { |
309 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, ERR_R_MALLOC_FAILURE); | |
310 | goto err; | |
311 | } | |
94b2c29f | 312 | |
40720ce3 | 313 | eklen = EVP_PKEY_encrypt(ek, ec->key, ec->keylen, ktri->pkey); |
94b2c29f | 314 | |
40720ce3 MC |
315 | if (eklen <= 0) |
316 | goto err; | |
94b2c29f | 317 | |
40720ce3 MC |
318 | ASN1_STRING_set0(ktri->encryptedKey, ek, eklen); |
319 | ek = NULL; | |
94b2c29f | 320 | |
40720ce3 | 321 | ret = 1; |
94b2c29f | 322 | |
40720ce3 MC |
323 | err: |
324 | if (ek) | |
325 | OPENSSL_free(ek); | |
326 | return ret; | |
94b2c29f | 327 | |
40720ce3 | 328 | } |
94b2c29f DSH |
329 | |
330 | /* Decrypt content key from KTRI */ | |
331 | ||
332 | static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, | |
40720ce3 MC |
333 | CMS_RecipientInfo *ri) |
334 | { | |
335 | CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; | |
336 | unsigned char *ek = NULL; | |
337 | int eklen; | |
338 | int ret = 0; | |
339 | CMS_EncryptedContentInfo *ec; | |
340 | ec = cms->d.envelopedData->encryptedContentInfo; | |
341 | ||
342 | if (ktri->pkey == NULL) { | |
343 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_NO_PRIVATE_KEY); | |
344 | return 0; | |
345 | } | |
346 | ||
347 | eklen = EVP_PKEY_size(ktri->pkey); | |
348 | ||
349 | ek = OPENSSL_malloc(eklen); | |
350 | ||
351 | if (ek == NULL) { | |
352 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, ERR_R_MALLOC_FAILURE); | |
353 | goto err; | |
354 | } | |
355 | ||
356 | eklen = EVP_PKEY_decrypt(ek, | |
357 | ktri->encryptedKey->data, | |
358 | ktri->encryptedKey->length, ktri->pkey); | |
359 | if (eklen <= 0) { | |
360 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB); | |
361 | goto err; | |
362 | } | |
363 | ||
364 | ret = 1; | |
365 | ||
366 | if (ec->key) { | |
367 | OPENSSL_cleanse(ec->key, ec->keylen); | |
368 | OPENSSL_free(ec->key); | |
369 | } | |
370 | ||
371 | ec->key = ek; | |
372 | ec->keylen = eklen; | |
373 | ||
374 | err: | |
375 | if (!ret && ek) | |
376 | OPENSSL_free(ek); | |
377 | ||
378 | return ret; | |
379 | } | |
94b2c29f DSH |
380 | |
381 | /* Key Encrypted Key (KEK) RecipientInfo routines */ | |
382 | ||
40720ce3 MC |
383 | int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, |
384 | const unsigned char *id, size_t idlen) | |
385 | { | |
386 | ASN1_OCTET_STRING tmp_os; | |
387 | CMS_KEKRecipientInfo *kekri; | |
388 | if (ri->type != CMS_RECIPINFO_KEK) { | |
389 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP, CMS_R_NOT_KEK); | |
390 | return -2; | |
391 | } | |
392 | kekri = ri->d.kekri; | |
393 | tmp_os.type = V_ASN1_OCTET_STRING; | |
394 | tmp_os.flags = 0; | |
395 | tmp_os.data = (unsigned char *)id; | |
396 | tmp_os.length = (int)idlen; | |
397 | return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier); | |
398 | } | |
94b2c29f DSH |
399 | |
400 | /* For now hard code AES key wrap info */ | |
401 | ||
402 | static size_t aes_wrap_keylen(int nid) | |
40720ce3 MC |
403 | { |
404 | switch (nid) { | |
405 | case NID_id_aes128_wrap: | |
406 | return 16; | |
94b2c29f | 407 | |
40720ce3 MC |
408 | case NID_id_aes192_wrap: |
409 | return 24; | |
94b2c29f | 410 | |
40720ce3 MC |
411 | case NID_id_aes256_wrap: |
412 | return 32; | |
94b2c29f | 413 | |
40720ce3 MC |
414 | default: |
415 | return 0; | |
416 | } | |
417 | } | |
94b2c29f DSH |
418 | |
419 | CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, | |
40720ce3 MC |
420 | unsigned char *key, size_t keylen, |
421 | unsigned char *id, size_t idlen, | |
422 | ASN1_GENERALIZEDTIME *date, | |
423 | ASN1_OBJECT *otherTypeId, | |
424 | ASN1_TYPE *otherType) | |
425 | { | |
426 | CMS_RecipientInfo *ri = NULL; | |
427 | CMS_EnvelopedData *env; | |
428 | CMS_KEKRecipientInfo *kekri; | |
429 | env = cms_get0_enveloped(cms); | |
430 | if (!env) | |
431 | goto err; | |
94b2c29f | 432 | |
40720ce3 MC |
433 | if (nid == NID_undef) { |
434 | switch (keylen) { | |
435 | case 16: | |
436 | nid = NID_id_aes128_wrap; | |
437 | break; | |
94b2c29f | 438 | |
40720ce3 MC |
439 | case 24: |
440 | nid = NID_id_aes192_wrap; | |
441 | break; | |
442 | ||
443 | case 32: | |
444 | nid = NID_id_aes256_wrap; | |
445 | break; | |
446 | ||
447 | default: | |
448 | CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH); | |
449 | goto err; | |
450 | } | |
451 | ||
452 | } else { | |
453 | ||
454 | size_t exp_keylen = aes_wrap_keylen(nid); | |
455 | ||
456 | if (!exp_keylen) { | |
457 | CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, | |
458 | CMS_R_UNSUPPORTED_KEK_ALGORITHM); | |
459 | goto err; | |
460 | } | |
461 | ||
462 | if (keylen != exp_keylen) { | |
463 | CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH); | |
464 | goto err; | |
465 | } | |
466 | ||
467 | } | |
468 | ||
469 | /* Initialize recipient info */ | |
470 | ri = M_ASN1_new_of(CMS_RecipientInfo); | |
471 | if (!ri) | |
472 | goto merr; | |
473 | ||
474 | ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo); | |
475 | if (!ri->d.kekri) | |
476 | goto merr; | |
477 | ri->type = CMS_RECIPINFO_KEK; | |
478 | ||
479 | kekri = ri->d.kekri; | |
480 | ||
481 | if (otherTypeId) { | |
482 | kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute); | |
483 | if (kekri->kekid->other == NULL) | |
484 | goto merr; | |
485 | } | |
486 | ||
487 | if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) | |
488 | goto merr; | |
489 | ||
490 | /* After this point no calls can fail */ | |
491 | ||
492 | kekri->version = 4; | |
493 | ||
494 | kekri->key = key; | |
495 | kekri->keylen = keylen; | |
496 | ||
497 | ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen); | |
498 | ||
499 | kekri->kekid->date = date; | |
500 | ||
501 | if (kekri->kekid->other) { | |
502 | kekri->kekid->other->keyAttrId = otherTypeId; | |
503 | kekri->kekid->other->keyAttr = otherType; | |
504 | } | |
505 | ||
506 | X509_ALGOR_set0(kekri->keyEncryptionAlgorithm, | |
507 | OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL); | |
508 | ||
509 | return ri; | |
510 | ||
511 | merr: | |
512 | CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE); | |
513 | err: | |
514 | if (ri) | |
515 | M_ASN1_free_of(ri, CMS_RecipientInfo); | |
516 | return NULL; | |
94b2c29f | 517 | |
40720ce3 MC |
518 | } |
519 | ||
520 | int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri, | |
521 | X509_ALGOR **palg, | |
522 | ASN1_OCTET_STRING **pid, | |
523 | ASN1_GENERALIZEDTIME **pdate, | |
524 | ASN1_OBJECT **potherid, | |
525 | ASN1_TYPE **pothertype) | |
526 | { | |
527 | CMS_KEKIdentifier *rkid; | |
528 | if (ri->type != CMS_RECIPINFO_KEK) { | |
529 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK); | |
530 | return 0; | |
531 | } | |
532 | rkid = ri->d.kekri->kekid; | |
533 | if (palg) | |
534 | *palg = ri->d.kekri->keyEncryptionAlgorithm; | |
535 | if (pid) | |
536 | *pid = rkid->keyIdentifier; | |
537 | if (pdate) | |
538 | *pdate = rkid->date; | |
539 | if (potherid) { | |
540 | if (rkid->other) | |
541 | *potherid = rkid->other->keyAttrId; | |
542 | else | |
543 | *potherid = NULL; | |
544 | } | |
545 | if (pothertype) { | |
546 | if (rkid->other) | |
547 | *pothertype = rkid->other->keyAttr; | |
548 | else | |
549 | *pothertype = NULL; | |
550 | } | |
551 | return 1; | |
552 | } | |
553 | ||
554 | int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri, | |
555 | unsigned char *key, size_t keylen) | |
556 | { | |
557 | CMS_KEKRecipientInfo *kekri; | |
558 | if (ri->type != CMS_RECIPINFO_KEK) { | |
559 | CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK); | |
560 | return 0; | |
561 | } | |
562 | ||
563 | kekri = ri->d.kekri; | |
564 | kekri->key = key; | |
565 | kekri->keylen = keylen; | |
566 | return 1; | |
567 | } | |
94b2c29f DSH |
568 | |
569 | /* Encrypt content key in KEK recipient info */ | |
570 | ||
571 | static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms, | |
40720ce3 MC |
572 | CMS_RecipientInfo *ri) |
573 | { | |
574 | CMS_EncryptedContentInfo *ec; | |
575 | CMS_KEKRecipientInfo *kekri; | |
576 | AES_KEY actx; | |
577 | unsigned char *wkey = NULL; | |
578 | int wkeylen; | |
579 | int r = 0; | |
94b2c29f | 580 | |
40720ce3 | 581 | ec = cms->d.envelopedData->encryptedContentInfo; |
94b2c29f | 582 | |
40720ce3 | 583 | kekri = ri->d.kekri; |
94b2c29f | 584 | |
40720ce3 MC |
585 | if (!kekri->key) { |
586 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY); | |
587 | return 0; | |
588 | } | |
94b2c29f | 589 | |
40720ce3 MC |
590 | if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx)) { |
591 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, | |
592 | CMS_R_ERROR_SETTING_KEY); | |
593 | goto err; | |
594 | } | |
94b2c29f | 595 | |
40720ce3 | 596 | wkey = OPENSSL_malloc(ec->keylen + 8); |
94b2c29f | 597 | |
40720ce3 MC |
598 | if (!wkey) { |
599 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, ERR_R_MALLOC_FAILURE); | |
600 | goto err; | |
601 | } | |
94b2c29f | 602 | |
40720ce3 | 603 | wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen); |
94b2c29f | 604 | |
40720ce3 MC |
605 | if (wkeylen <= 0) { |
606 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR); | |
607 | goto err; | |
608 | } | |
94b2c29f | 609 | |
40720ce3 | 610 | ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen); |
94b2c29f | 611 | |
40720ce3 | 612 | r = 1; |
94b2c29f | 613 | |
40720ce3 | 614 | err: |
94b2c29f | 615 | |
40720ce3 MC |
616 | if (!r && wkey) |
617 | OPENSSL_free(wkey); | |
618 | OPENSSL_cleanse(&actx, sizeof(actx)); | |
94b2c29f | 619 | |
40720ce3 | 620 | return r; |
94b2c29f | 621 | |
40720ce3 | 622 | } |
94b2c29f DSH |
623 | |
624 | /* Decrypt content key in KEK recipient info */ | |
625 | ||
626 | static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, | |
40720ce3 MC |
627 | CMS_RecipientInfo *ri) |
628 | { | |
629 | CMS_EncryptedContentInfo *ec; | |
630 | CMS_KEKRecipientInfo *kekri; | |
631 | AES_KEY actx; | |
632 | unsigned char *ukey = NULL; | |
633 | int ukeylen; | |
634 | int r = 0, wrap_nid; | |
635 | ||
636 | ec = cms->d.envelopedData->encryptedContentInfo; | |
637 | ||
638 | kekri = ri->d.kekri; | |
639 | ||
640 | if (!kekri->key) { | |
641 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY); | |
642 | return 0; | |
643 | } | |
644 | ||
645 | wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm); | |
646 | if (aes_wrap_keylen(wrap_nid) != kekri->keylen) { | |
647 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, | |
648 | CMS_R_INVALID_KEY_LENGTH); | |
649 | return 0; | |
650 | } | |
651 | ||
652 | /* If encrypted key length is invalid don't bother */ | |
653 | ||
654 | if (kekri->encryptedKey->length < 16) { | |
655 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, | |
656 | CMS_R_INVALID_ENCRYPTED_KEY_LENGTH); | |
657 | goto err; | |
658 | } | |
659 | ||
660 | if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx)) { | |
661 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, | |
662 | CMS_R_ERROR_SETTING_KEY); | |
663 | goto err; | |
664 | } | |
665 | ||
666 | ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8); | |
667 | ||
668 | if (!ukey) { | |
669 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, ERR_R_MALLOC_FAILURE); | |
670 | goto err; | |
671 | } | |
672 | ||
673 | ukeylen = AES_unwrap_key(&actx, NULL, ukey, | |
674 | kekri->encryptedKey->data, | |
675 | kekri->encryptedKey->length); | |
676 | ||
677 | if (ukeylen <= 0) { | |
678 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_UNWRAP_ERROR); | |
679 | goto err; | |
680 | } | |
681 | ||
682 | ec->key = ukey; | |
683 | ec->keylen = ukeylen; | |
684 | ||
685 | r = 1; | |
686 | ||
687 | err: | |
688 | ||
689 | if (!r && ukey) | |
690 | OPENSSL_free(ukey); | |
691 | OPENSSL_cleanse(&actx, sizeof(actx)); | |
692 | ||
693 | return r; | |
694 | ||
695 | } | |
94b2c29f DSH |
696 | |
697 | int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) | |
40720ce3 MC |
698 | { |
699 | switch (ri->type) { | |
700 | case CMS_RECIPINFO_TRANS: | |
701 | return cms_RecipientInfo_ktri_decrypt(cms, ri); | |
702 | ||
703 | case CMS_RECIPINFO_KEK: | |
704 | return cms_RecipientInfo_kekri_decrypt(cms, ri); | |
705 | ||
706 | default: | |
707 | CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, | |
708 | CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE); | |
709 | return 0; | |
710 | } | |
711 | } | |
94b2c29f DSH |
712 | |
713 | BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) | |
40720ce3 MC |
714 | { |
715 | CMS_EncryptedContentInfo *ec; | |
716 | STACK_OF(CMS_RecipientInfo) *rinfos; | |
717 | CMS_RecipientInfo *ri; | |
718 | int i, r, ok = 0; | |
719 | BIO *ret; | |
720 | ||
721 | /* Get BIO first to set up key */ | |
722 | ||
723 | ec = cms->d.envelopedData->encryptedContentInfo; | |
724 | ret = cms_EncryptedContent_init_bio(ec); | |
725 | ||
726 | /* If error or no cipher end of processing */ | |
727 | ||
728 | if (!ret || !ec->cipher) | |
729 | return ret; | |
730 | ||
731 | /* Now encrypt content key according to each RecipientInfo type */ | |
732 | ||
733 | rinfos = cms->d.envelopedData->recipientInfos; | |
734 | ||
735 | for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) { | |
736 | ri = sk_CMS_RecipientInfo_value(rinfos, i); | |
737 | ||
738 | switch (ri->type) { | |
739 | case CMS_RECIPINFO_TRANS: | |
740 | r = cms_RecipientInfo_ktri_encrypt(cms, ri); | |
741 | break; | |
742 | ||
743 | case CMS_RECIPINFO_KEK: | |
744 | r = cms_RecipientInfo_kekri_encrypt(cms, ri); | |
745 | break; | |
746 | ||
747 | default: | |
748 | CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, | |
749 | CMS_R_UNSUPPORTED_RECIPIENT_TYPE); | |
750 | goto err; | |
751 | } | |
752 | ||
753 | if (r <= 0) { | |
754 | CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, | |
755 | CMS_R_ERROR_SETTING_RECIPIENTINFO); | |
756 | goto err; | |
757 | } | |
758 | } | |
759 | ||
760 | ok = 1; | |
761 | ||
762 | err: | |
763 | ec->cipher = NULL; | |
764 | if (ec->key) { | |
765 | OPENSSL_cleanse(ec->key, ec->keylen); | |
766 | OPENSSL_free(ec->key); | |
767 | ec->key = NULL; | |
768 | ec->keylen = 0; | |
769 | } | |
770 | if (ok) | |
771 | return ret; | |
772 | BIO_free(ret); | |
773 | return NULL; | |
774 | ||
775 | } |