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