1 | /* |
2 | * Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
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 |
8 | */ |
9 | |
10 | #include "internal/cryptlib.h" |
11 | #include <openssl/asn1t.h> |
12 | #include <openssl/x509.h> |
13 | #include <openssl/x509v3.h> |
14 | #include <openssl/err.h> |
15 | #include <openssl/cms.h> |
16 | #include "cms_local.h" |
17 | #include "crypto/asn1.h" |
18 | |
19 | static BIO *cms_get_text_bio(BIO *out, unsigned int flags) |
20 | { |
21 | BIO *rbio; |
22 | if (out == NULL) |
23 | rbio = BIO_new(BIO_s_null()); |
24 | else if (flags & CMS_TEXT) { |
25 | rbio = BIO_new(BIO_s_mem()); |
26 | BIO_set_mem_eof_return(rbio, 0); |
27 | } else |
28 | rbio = out; |
29 | return rbio; |
30 | } |
31 | |
32 | static int cms_copy_content(BIO *out, BIO *in, unsigned int flags) |
33 | { |
34 | unsigned char buf[4096]; |
35 | int r = 0, i; |
36 | BIO *tmpout; |
37 | |
38 | tmpout = cms_get_text_bio(out, flags); |
39 | |
40 | if (tmpout == NULL) { |
41 | CMSerr(CMS_F_CMS_COPY_CONTENT, ERR_R_MALLOC_FAILURE); |
42 | goto err; |
43 | } |
44 | |
45 | /* Read all content through chain to process digest, decrypt etc */ |
46 | for (;;) { |
47 | i = BIO_read(in, buf, sizeof(buf)); |
48 | if (i <= 0) { |
49 | if (BIO_method_type(in) == BIO_TYPE_CIPHER) { |
50 | if (!BIO_get_cipher_status(in)) |
51 | goto err; |
52 | } |
53 | if (i < 0) |
54 | goto err; |
55 | break; |
56 | } |
57 | |
58 | if (tmpout && (BIO_write(tmpout, buf, i) != i)) |
59 | goto err; |
60 | } |
61 | |
62 | if (flags & CMS_TEXT) { |
63 | if (!SMIME_text(tmpout, out)) { |
64 | CMSerr(CMS_F_CMS_COPY_CONTENT, CMS_R_SMIME_TEXT_ERROR); |
65 | goto err; |
66 | } |
67 | } |
68 | |
69 | r = 1; |
70 | |
71 | err: |
72 | if (tmpout != out) |
73 | BIO_free(tmpout); |
74 | return r; |
75 | |
76 | } |
77 | |
78 | static int check_content(CMS_ContentInfo *cms) |
79 | { |
80 | ASN1_OCTET_STRING **pos = CMS_get0_content(cms); |
81 | |
82 | if (pos == NULL || *pos == NULL) { |
83 | CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT); |
84 | return 0; |
85 | } |
86 | return 1; |
87 | } |
88 | |
89 | static void do_free_upto(BIO *f, BIO *upto) |
90 | { |
91 | if (upto != NULL) { |
92 | BIO *tbio; |
93 | do { |
94 | tbio = BIO_pop(f); |
95 | BIO_free(f); |
96 | f = tbio; |
97 | } while (f != NULL && f != upto); |
98 | } else |
99 | BIO_free_all(f); |
100 | } |
101 | |
102 | int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags) |
103 | { |
104 | BIO *cont; |
105 | int r; |
106 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) { |
107 | CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA); |
108 | return 0; |
109 | } |
110 | cont = CMS_dataInit(cms, NULL); |
111 | if (!cont) |
112 | return 0; |
113 | r = cms_copy_content(out, cont, flags); |
114 | BIO_free_all(cont); |
115 | return r; |
116 | } |
117 | |
118 | CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags) |
119 | { |
120 | CMS_ContentInfo *cms; |
121 | cms = cms_Data_create(); |
122 | if (!cms) |
123 | return NULL; |
124 | |
125 | if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) |
126 | return cms; |
127 | |
128 | CMS_ContentInfo_free(cms); |
129 | |
130 | return NULL; |
131 | } |
132 | |
133 | int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, |
134 | unsigned int flags) |
135 | { |
136 | BIO *cont; |
137 | int r; |
138 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) { |
139 | CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA); |
140 | return 0; |
141 | } |
142 | |
143 | if (!dcont && !check_content(cms)) |
144 | return 0; |
145 | |
146 | cont = CMS_dataInit(cms, dcont); |
147 | if (!cont) |
148 | return 0; |
149 | r = cms_copy_content(out, cont, flags); |
150 | if (r) |
151 | r = cms_DigestedData_do_final(cms, cont, 1); |
152 | do_free_upto(cont, dcont); |
153 | return r; |
154 | } |
155 | |
156 | CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, |
157 | unsigned int flags) |
158 | { |
159 | CMS_ContentInfo *cms; |
160 | if (!md) |
161 | md = EVP_sha1(); |
162 | cms = cms_DigestedData_create(md); |
163 | if (!cms) |
164 | return NULL; |
165 | |
166 | if (!(flags & CMS_DETACHED)) |
167 | CMS_set_detached(cms, 0); |
168 | |
169 | if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) |
170 | return cms; |
171 | |
172 | CMS_ContentInfo_free(cms); |
173 | return NULL; |
174 | } |
175 | |
176 | int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, |
177 | const unsigned char *key, size_t keylen, |
178 | BIO *dcont, BIO *out, unsigned int flags) |
179 | { |
180 | BIO *cont; |
181 | int r; |
182 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) { |
183 | CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT, |
184 | CMS_R_TYPE_NOT_ENCRYPTED_DATA); |
185 | return 0; |
186 | } |
187 | |
188 | if (!dcont && !check_content(cms)) |
189 | return 0; |
190 | |
191 | if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0) |
192 | return 0; |
193 | cont = CMS_dataInit(cms, dcont); |
194 | if (!cont) |
195 | return 0; |
196 | r = cms_copy_content(out, cont, flags); |
197 | do_free_upto(cont, dcont); |
198 | return r; |
199 | } |
200 | |
201 | CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, |
202 | const unsigned char *key, |
203 | size_t keylen, unsigned int flags) |
204 | { |
205 | CMS_ContentInfo *cms; |
206 | if (!cipher) { |
207 | CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER); |
208 | return NULL; |
209 | } |
210 | cms = CMS_ContentInfo_new(); |
211 | if (cms == NULL) |
212 | return NULL; |
213 | if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) |
214 | return NULL; |
215 | |
216 | if (!(flags & CMS_DETACHED)) |
217 | CMS_set_detached(cms, 0); |
218 | |
219 | if ((flags & (CMS_STREAM | CMS_PARTIAL)) |
220 | || CMS_final(cms, in, NULL, flags)) |
221 | return cms; |
222 | |
223 | CMS_ContentInfo_free(cms); |
224 | return NULL; |
225 | } |
226 | |
227 | static int cms_signerinfo_verify_cert(CMS_SignerInfo *si, |
228 | X509_STORE *store, |
229 | STACK_OF(X509) *certs, |
230 | STACK_OF(X509_CRL) *crls) |
231 | { |
232 | X509_STORE_CTX *ctx = X509_STORE_CTX_new(); |
233 | X509 *signer; |
234 | int i, j, r = 0; |
235 | |
236 | if (ctx == NULL) { |
237 | CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, ERR_R_MALLOC_FAILURE); |
238 | goto err; |
239 | } |
240 | CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); |
241 | if (!X509_STORE_CTX_init(ctx, store, signer, certs)) { |
242 | CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, CMS_R_STORE_INIT_ERROR); |
243 | goto err; |
244 | } |
245 | X509_STORE_CTX_set_default(ctx, "smime_sign" ); |
246 | if (crls) |
247 | X509_STORE_CTX_set0_crls(ctx, crls); |
248 | |
249 | i = X509_verify_cert(ctx); |
250 | if (i <= 0) { |
251 | j = X509_STORE_CTX_get_error(ctx); |
252 | CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, |
253 | CMS_R_CERTIFICATE_VERIFY_ERROR); |
254 | ERR_add_error_data(2, "Verify error:" , |
255 | X509_verify_cert_error_string(j)); |
256 | goto err; |
257 | } |
258 | r = 1; |
259 | err: |
260 | X509_STORE_CTX_free(ctx); |
261 | return r; |
262 | |
263 | } |
264 | |
265 | int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, |
266 | X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags) |
267 | { |
268 | CMS_SignerInfo *si; |
269 | STACK_OF(CMS_SignerInfo) *sinfos; |
270 | STACK_OF(X509) *cms_certs = NULL; |
271 | STACK_OF(X509_CRL) *crls = NULL; |
272 | X509 *signer; |
273 | int i, scount = 0, ret = 0; |
274 | BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL; |
275 | |
276 | if (!dcont && !check_content(cms)) |
277 | return 0; |
278 | if (dcont && !(flags & CMS_BINARY)) { |
279 | const ASN1_OBJECT *coid = CMS_get0_eContentType(cms); |
280 | if (OBJ_obj2nid(coid) == NID_id_ct_asciiTextWithCRLF) |
281 | flags |= CMS_ASCIICRLF; |
282 | } |
283 | |
284 | /* Attempt to find all signer certificates */ |
285 | |
286 | sinfos = CMS_get0_SignerInfos(cms); |
287 | |
288 | if (sk_CMS_SignerInfo_num(sinfos) <= 0) { |
289 | CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS); |
290 | goto err; |
291 | } |
292 | |
293 | for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { |
294 | si = sk_CMS_SignerInfo_value(sinfos, i); |
295 | CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); |
296 | if (signer) |
297 | scount++; |
298 | } |
299 | |
300 | if (scount != sk_CMS_SignerInfo_num(sinfos)) |
301 | scount += CMS_set1_signers_certs(cms, certs, flags); |
302 | |
303 | if (scount != sk_CMS_SignerInfo_num(sinfos)) { |
304 | CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND); |
305 | goto err; |
306 | } |
307 | |
308 | /* Attempt to verify all signers certs */ |
309 | |
310 | if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) { |
311 | cms_certs = CMS_get1_certs(cms); |
312 | if (!(flags & CMS_NOCRL)) |
313 | crls = CMS_get1_crls(cms); |
314 | for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { |
315 | si = sk_CMS_SignerInfo_value(sinfos, i); |
316 | if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls)) |
317 | goto err; |
318 | } |
319 | } |
320 | |
321 | /* Attempt to verify all SignerInfo signed attribute signatures */ |
322 | |
323 | if (!(flags & CMS_NO_ATTR_VERIFY)) { |
324 | for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { |
325 | si = sk_CMS_SignerInfo_value(sinfos, i); |
326 | if (CMS_signed_get_attr_count(si) < 0) |
327 | continue; |
328 | if (CMS_SignerInfo_verify(si) <= 0) |
329 | goto err; |
330 | } |
331 | } |
332 | |
333 | /* |
334 | * Performance optimization: if the content is a memory BIO then store |
335 | * its contents in a temporary read only memory BIO. This avoids |
336 | * potentially large numbers of slow copies of data which will occur when |
337 | * reading from a read write memory BIO when signatures are calculated. |
338 | */ |
339 | |
340 | if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) { |
341 | char *ptr; |
342 | long len; |
343 | len = BIO_get_mem_data(dcont, &ptr); |
344 | tmpin = BIO_new_mem_buf(ptr, len); |
345 | if (tmpin == NULL) { |
346 | CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE); |
347 | goto err2; |
348 | } |
349 | } else |
350 | tmpin = dcont; |
351 | /* |
352 | * If not binary mode and detached generate digests by *writing* through |
353 | * the BIO. That makes it possible to canonicalise the input. |
354 | */ |
355 | if (!(flags & SMIME_BINARY) && dcont) { |
356 | /* |
357 | * Create output BIO so we can either handle text or to ensure |
358 | * included content doesn't override detached content. |
359 | */ |
360 | tmpout = cms_get_text_bio(out, flags); |
361 | if (!tmpout) { |
362 | CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE); |
363 | goto err; |
364 | } |
365 | cmsbio = CMS_dataInit(cms, tmpout); |
366 | if (!cmsbio) |
367 | goto err; |
368 | /* |
369 | * Don't use SMIME_TEXT for verify: it adds headers and we want to |
370 | * remove them. |
371 | */ |
372 | SMIME_crlf_copy(dcont, cmsbio, flags & ~SMIME_TEXT); |
373 | |
374 | if (flags & CMS_TEXT) { |
375 | if (!SMIME_text(tmpout, out)) { |
376 | CMSerr(CMS_F_CMS_VERIFY, CMS_R_SMIME_TEXT_ERROR); |
377 | goto err; |
378 | } |
379 | } |
380 | } else { |
381 | cmsbio = CMS_dataInit(cms, tmpin); |
382 | if (!cmsbio) |
383 | goto err; |
384 | |
385 | if (!cms_copy_content(out, cmsbio, flags)) |
386 | goto err; |
387 | |
388 | } |
389 | if (!(flags & CMS_NO_CONTENT_VERIFY)) { |
390 | for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { |
391 | si = sk_CMS_SignerInfo_value(sinfos, i); |
392 | if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) { |
393 | CMSerr(CMS_F_CMS_VERIFY, CMS_R_CONTENT_VERIFY_ERROR); |
394 | goto err; |
395 | } |
396 | } |
397 | } |
398 | |
399 | ret = 1; |
400 | |
401 | err: |
402 | if (!(flags & SMIME_BINARY) && dcont) { |
403 | do_free_upto(cmsbio, tmpout); |
404 | if (tmpin != dcont) |
405 | BIO_free(tmpin); |
406 | } else { |
407 | if (dcont && (tmpin == dcont)) |
408 | do_free_upto(cmsbio, dcont); |
409 | else |
410 | BIO_free_all(cmsbio); |
411 | } |
412 | |
413 | if (out != tmpout) |
414 | BIO_free_all(tmpout); |
415 | |
416 | err2: |
417 | sk_X509_pop_free(cms_certs, X509_free); |
418 | sk_X509_CRL_pop_free(crls, X509_CRL_free); |
419 | |
420 | return ret; |
421 | } |
422 | |
423 | int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, |
424 | STACK_OF(X509) *certs, |
425 | X509_STORE *store, unsigned int flags) |
426 | { |
427 | int r; |
428 | flags &= ~(CMS_DETACHED | CMS_TEXT); |
429 | r = CMS_verify(rcms, certs, store, NULL, NULL, flags); |
430 | if (r <= 0) |
431 | return r; |
432 | return cms_Receipt_verify(rcms, ocms); |
433 | } |
434 | |
435 | CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, |
436 | STACK_OF(X509) *certs, BIO *data, |
437 | unsigned int flags) |
438 | { |
439 | CMS_ContentInfo *cms; |
440 | int i; |
441 | |
442 | cms = CMS_ContentInfo_new(); |
443 | if (cms == NULL || !CMS_SignedData_init(cms)) |
444 | goto merr; |
445 | if (flags & CMS_ASCIICRLF |
446 | && !CMS_set1_eContentType(cms, |
447 | OBJ_nid2obj(NID_id_ct_asciiTextWithCRLF))) |
448 | goto err; |
449 | |
450 | if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) { |
451 | CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR); |
452 | goto err; |
453 | } |
454 | |
455 | for (i = 0; i < sk_X509_num(certs); i++) { |
456 | X509 *x = sk_X509_value(certs, i); |
457 | if (!CMS_add1_cert(cms, x)) |
458 | goto merr; |
459 | } |
460 | |
461 | if (!(flags & CMS_DETACHED)) |
462 | CMS_set_detached(cms, 0); |
463 | |
464 | if ((flags & (CMS_STREAM | CMS_PARTIAL)) |
465 | || CMS_final(cms, data, NULL, flags)) |
466 | return cms; |
467 | else |
468 | goto err; |
469 | |
470 | merr: |
471 | CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE); |
472 | |
473 | err: |
474 | CMS_ContentInfo_free(cms); |
475 | return NULL; |
476 | } |
477 | |
478 | CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, |
479 | X509 *signcert, EVP_PKEY *pkey, |
480 | STACK_OF(X509) *certs, unsigned int flags) |
481 | { |
482 | CMS_SignerInfo *rct_si; |
483 | CMS_ContentInfo *cms = NULL; |
484 | ASN1_OCTET_STRING **pos, *os; |
485 | BIO *rct_cont = NULL; |
486 | int r = 0; |
487 | |
488 | flags &= ~(CMS_STREAM | CMS_TEXT); |
489 | /* Not really detached but avoids content being allocated */ |
490 | flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED; |
491 | if (pkey == NULL || signcert == NULL) { |
492 | CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT); |
493 | return NULL; |
494 | } |
495 | |
496 | /* Initialize signed data */ |
497 | |
498 | cms = CMS_sign(NULL, NULL, certs, NULL, flags); |
499 | if (!cms) |
500 | goto err; |
501 | |
502 | /* Set inner content type to signed receipt */ |
503 | if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt))) |
504 | goto err; |
505 | |
506 | rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags); |
507 | if (!rct_si) { |
508 | CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR); |
509 | goto err; |
510 | } |
511 | |
512 | os = cms_encode_Receipt(si); |
513 | |
514 | if (!os) |
515 | goto err; |
516 | |
517 | /* Set content to digest */ |
518 | rct_cont = BIO_new_mem_buf(os->data, os->length); |
519 | if (!rct_cont) |
520 | goto err; |
521 | |
522 | /* Add msgSigDigest attribute */ |
523 | |
524 | if (!cms_msgSigDigest_add1(rct_si, si)) |
525 | goto err; |
526 | |
527 | /* Finalize structure */ |
528 | if (!CMS_final(cms, rct_cont, NULL, flags)) |
529 | goto err; |
530 | |
531 | /* Set embedded content */ |
532 | pos = CMS_get0_content(cms); |
533 | *pos = os; |
534 | |
535 | r = 1; |
536 | |
537 | err: |
538 | BIO_free(rct_cont); |
539 | if (r) |
540 | return cms; |
541 | CMS_ContentInfo_free(cms); |
542 | return NULL; |
543 | |
544 | } |
545 | |
546 | CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, |
547 | const EVP_CIPHER *cipher, unsigned int flags) |
548 | { |
549 | CMS_ContentInfo *cms; |
550 | int i; |
551 | X509 *recip; |
552 | cms = CMS_EnvelopedData_create(cipher); |
553 | if (!cms) |
554 | goto merr; |
555 | for (i = 0; i < sk_X509_num(certs); i++) { |
556 | recip = sk_X509_value(certs, i); |
557 | if (!CMS_add1_recipient_cert(cms, recip, flags)) { |
558 | CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR); |
559 | goto err; |
560 | } |
561 | } |
562 | |
563 | if (!(flags & CMS_DETACHED)) |
564 | CMS_set_detached(cms, 0); |
565 | |
566 | if ((flags & (CMS_STREAM | CMS_PARTIAL)) |
567 | || CMS_final(cms, data, NULL, flags)) |
568 | return cms; |
569 | else |
570 | goto err; |
571 | |
572 | merr: |
573 | CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE); |
574 | err: |
575 | CMS_ContentInfo_free(cms); |
576 | return NULL; |
577 | } |
578 | |
579 | static int cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, |
580 | EVP_PKEY *pk, X509 *cert) |
581 | { |
582 | int i; |
583 | STACK_OF(CMS_RecipientEncryptedKey) *reks; |
584 | CMS_RecipientEncryptedKey *rek; |
585 | reks = CMS_RecipientInfo_kari_get0_reks(ri); |
586 | for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) { |
587 | int rv; |
588 | rek = sk_CMS_RecipientEncryptedKey_value(reks, i); |
589 | if (cert != NULL && CMS_RecipientEncryptedKey_cert_cmp(rek, cert)) |
590 | continue; |
591 | CMS_RecipientInfo_kari_set0_pkey(ri, pk); |
592 | rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek); |
593 | CMS_RecipientInfo_kari_set0_pkey(ri, NULL); |
594 | if (rv > 0) |
595 | return 1; |
596 | return cert == NULL ? 0 : -1; |
597 | } |
598 | return 0; |
599 | } |
600 | |
601 | int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) |
602 | { |
603 | STACK_OF(CMS_RecipientInfo) *ris; |
604 | CMS_RecipientInfo *ri; |
605 | int i, r, ri_type; |
606 | int debug = 0, match_ri = 0; |
607 | ris = CMS_get0_RecipientInfos(cms); |
608 | if (ris) |
609 | debug = cms->d.envelopedData->encryptedContentInfo->debug; |
610 | ri_type = cms_pkey_get_ri_type(pk); |
611 | if (ri_type == CMS_RECIPINFO_NONE) { |
612 | CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, |
613 | CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); |
614 | return 0; |
615 | } |
616 | |
617 | for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { |
618 | ri = sk_CMS_RecipientInfo_value(ris, i); |
619 | if (CMS_RecipientInfo_type(ri) != ri_type) |
620 | continue; |
621 | match_ri = 1; |
622 | if (ri_type == CMS_RECIPINFO_AGREE) { |
623 | r = cms_kari_set1_pkey(cms, ri, pk, cert); |
624 | if (r > 0) |
625 | return 1; |
626 | if (r < 0) |
627 | return 0; |
628 | } |
629 | /* |
630 | * If we have a cert try matching RecipientInfo otherwise try them |
631 | * all. |
632 | */ |
633 | else if (!cert || !CMS_RecipientInfo_ktri_cert_cmp(ri, cert)) { |
634 | EVP_PKEY_up_ref(pk); |
635 | CMS_RecipientInfo_set0_pkey(ri, pk); |
636 | r = CMS_RecipientInfo_decrypt(cms, ri); |
637 | CMS_RecipientInfo_set0_pkey(ri, NULL); |
638 | if (cert) { |
639 | /* |
640 | * If not debugging clear any error and return success to |
641 | * avoid leaking of information useful to MMA |
642 | */ |
643 | if (!debug) { |
644 | ERR_clear_error(); |
645 | return 1; |
646 | } |
647 | if (r > 0) |
648 | return 1; |
649 | CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR); |
650 | return 0; |
651 | } |
652 | /* |
653 | * If no cert and not debugging don't leave loop after first |
654 | * successful decrypt. Always attempt to decrypt all recipients |
655 | * to avoid leaking timing of a successful decrypt. |
656 | */ |
657 | else if (r > 0 && debug) |
658 | return 1; |
659 | } |
660 | } |
661 | /* If no cert, key transport and not debugging always return success */ |
662 | if (cert == NULL && ri_type == CMS_RECIPINFO_TRANS && match_ri && !debug) { |
663 | ERR_clear_error(); |
664 | return 1; |
665 | } |
666 | |
667 | CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT); |
668 | return 0; |
669 | |
670 | } |
671 | |
672 | int CMS_decrypt_set1_key(CMS_ContentInfo *cms, |
673 | unsigned char *key, size_t keylen, |
674 | const unsigned char *id, size_t idlen) |
675 | { |
676 | STACK_OF(CMS_RecipientInfo) *ris; |
677 | CMS_RecipientInfo *ri; |
678 | int i, r; |
679 | ris = CMS_get0_RecipientInfos(cms); |
680 | for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { |
681 | ri = sk_CMS_RecipientInfo_value(ris, i); |
682 | if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK) |
683 | continue; |
684 | |
685 | /* |
686 | * If we have an id try matching RecipientInfo otherwise try them |
687 | * all. |
688 | */ |
689 | if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) { |
690 | CMS_RecipientInfo_set0_key(ri, key, keylen); |
691 | r = CMS_RecipientInfo_decrypt(cms, ri); |
692 | CMS_RecipientInfo_set0_key(ri, NULL, 0); |
693 | if (r > 0) |
694 | return 1; |
695 | if (id) { |
696 | CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_DECRYPT_ERROR); |
697 | return 0; |
698 | } |
699 | ERR_clear_error(); |
700 | } |
701 | } |
702 | |
703 | CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT); |
704 | return 0; |
705 | |
706 | } |
707 | |
708 | int CMS_decrypt_set1_password(CMS_ContentInfo *cms, |
709 | unsigned char *pass, ossl_ssize_t passlen) |
710 | { |
711 | STACK_OF(CMS_RecipientInfo) *ris; |
712 | CMS_RecipientInfo *ri; |
713 | int i, r; |
714 | ris = CMS_get0_RecipientInfos(cms); |
715 | for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { |
716 | ri = sk_CMS_RecipientInfo_value(ris, i); |
717 | if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS) |
718 | continue; |
719 | CMS_RecipientInfo_set0_password(ri, pass, passlen); |
720 | r = CMS_RecipientInfo_decrypt(cms, ri); |
721 | CMS_RecipientInfo_set0_password(ri, NULL, 0); |
722 | if (r > 0) |
723 | return 1; |
724 | } |
725 | |
726 | CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT); |
727 | return 0; |
728 | |
729 | } |
730 | |
731 | int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, |
732 | BIO *dcont, BIO *out, unsigned int flags) |
733 | { |
734 | int r; |
735 | BIO *cont; |
736 | |
737 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) { |
738 | CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA); |
739 | return 0; |
740 | } |
741 | if (!dcont && !check_content(cms)) |
742 | return 0; |
743 | if (flags & CMS_DEBUG_DECRYPT) |
744 | cms->d.envelopedData->encryptedContentInfo->debug = 1; |
745 | else |
746 | cms->d.envelopedData->encryptedContentInfo->debug = 0; |
747 | if (!cert) |
748 | cms->d.envelopedData->encryptedContentInfo->havenocert = 1; |
749 | else |
750 | cms->d.envelopedData->encryptedContentInfo->havenocert = 0; |
751 | if (pk == NULL && cert == NULL && dcont == NULL && out == NULL) |
752 | return 1; |
753 | if (pk != NULL && !CMS_decrypt_set1_pkey(cms, pk, cert)) |
754 | return 0; |
755 | cont = CMS_dataInit(cms, dcont); |
756 | if (cont == NULL) |
757 | return 0; |
758 | r = cms_copy_content(out, cont, flags); |
759 | do_free_upto(cont, dcont); |
760 | return r; |
761 | } |
762 | |
763 | int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags) |
764 | { |
765 | BIO *cmsbio; |
766 | int ret = 0; |
767 | |
768 | if ((cmsbio = CMS_dataInit(cms, dcont)) == NULL) { |
769 | CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_LIB); |
770 | return 0; |
771 | } |
772 | |
773 | SMIME_crlf_copy(data, cmsbio, flags); |
774 | |
775 | (void)BIO_flush(cmsbio); |
776 | |
777 | if (!CMS_dataFinal(cms, cmsbio)) { |
778 | CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_DATAFINAL_ERROR); |
779 | goto err; |
780 | } |
781 | |
782 | ret = 1; |
783 | |
784 | err: |
785 | do_free_upto(cmsbio, dcont); |
786 | |
787 | return ret; |
788 | |
789 | } |
790 | |
791 | #ifdef ZLIB |
792 | |
793 | int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, |
794 | unsigned int flags) |
795 | { |
796 | BIO *cont; |
797 | int r; |
798 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) { |
799 | CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_TYPE_NOT_COMPRESSED_DATA); |
800 | return 0; |
801 | } |
802 | |
803 | if (!dcont && !check_content(cms)) |
804 | return 0; |
805 | |
806 | cont = CMS_dataInit(cms, dcont); |
807 | if (!cont) |
808 | return 0; |
809 | r = cms_copy_content(out, cont, flags); |
810 | do_free_upto(cont, dcont); |
811 | return r; |
812 | } |
813 | |
814 | CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) |
815 | { |
816 | CMS_ContentInfo *cms; |
817 | if (comp_nid <= 0) |
818 | comp_nid = NID_zlib_compression; |
819 | cms = cms_CompressedData_create(comp_nid); |
820 | if (!cms) |
821 | return NULL; |
822 | |
823 | if (!(flags & CMS_DETACHED)) |
824 | CMS_set_detached(cms, 0); |
825 | |
826 | if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) |
827 | return cms; |
828 | |
829 | CMS_ContentInfo_free(cms); |
830 | return NULL; |
831 | } |
832 | |
833 | #else |
834 | |
835 | int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, |
836 | unsigned int flags) |
837 | { |
838 | CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); |
839 | return 0; |
840 | } |
841 | |
842 | CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) |
843 | { |
844 | CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); |
845 | return NULL; |
846 | } |
847 | |
848 | #endif |
849 | |