1183234Ssimon/* crypto/cms/cms_smime.c */
2296465Sdelphij/*
3296465Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4183234Ssimon * project.
5183234Ssimon */
6183234Ssimon/* ====================================================================
7183234Ssimon * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
8183234Ssimon *
9183234Ssimon * Redistribution and use in source and binary forms, with or without
10183234Ssimon * modification, are permitted provided that the following conditions
11183234Ssimon * are met:
12183234Ssimon *
13183234Ssimon * 1. Redistributions of source code must retain the above copyright
14296465Sdelphij *    notice, this list of conditions and the following disclaimer.
15183234Ssimon *
16183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright
17183234Ssimon *    notice, this list of conditions and the following disclaimer in
18183234Ssimon *    the documentation and/or other materials provided with the
19183234Ssimon *    distribution.
20183234Ssimon *
21183234Ssimon * 3. All advertising materials mentioning features or use of this
22183234Ssimon *    software must display the following acknowledgment:
23183234Ssimon *    "This product includes software developed by the OpenSSL Project
24183234Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25183234Ssimon *
26183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27183234Ssimon *    endorse or promote products derived from this software without
28183234Ssimon *    prior written permission. For written permission, please contact
29183234Ssimon *    licensing@OpenSSL.org.
30183234Ssimon *
31183234Ssimon * 5. Products derived from this software may not be called "OpenSSL"
32183234Ssimon *    nor may "OpenSSL" appear in their names without prior written
33183234Ssimon *    permission of the OpenSSL Project.
34183234Ssimon *
35183234Ssimon * 6. Redistributions of any form whatsoever must retain the following
36183234Ssimon *    acknowledgment:
37183234Ssimon *    "This product includes software developed by the OpenSSL Project
38183234Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39183234Ssimon *
40183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43183234Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
52183234Ssimon * ====================================================================
53183234Ssimon */
54183234Ssimon
55183234Ssimon#include "cryptlib.h"
56183234Ssimon#include <openssl/asn1t.h>
57183234Ssimon#include <openssl/x509.h>
58183234Ssimon#include <openssl/x509v3.h>
59183234Ssimon#include <openssl/err.h>
60183234Ssimon#include <openssl/cms.h>
61183234Ssimon#include "cms_lcl.h"
62183234Ssimon
63183234Ssimonstatic int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
64296465Sdelphij{
65296465Sdelphij    unsigned char buf[4096];
66296465Sdelphij    int r = 0, i;
67296465Sdelphij    BIO *tmpout = NULL;
68183234Ssimon
69296465Sdelphij    if (out == NULL)
70296465Sdelphij        tmpout = BIO_new(BIO_s_null());
71296465Sdelphij    else if (flags & CMS_TEXT) {
72296465Sdelphij        tmpout = BIO_new(BIO_s_mem());
73296465Sdelphij        BIO_set_mem_eof_return(tmpout, 0);
74296465Sdelphij    } else
75296465Sdelphij        tmpout = out;
76183234Ssimon
77296465Sdelphij    if (!tmpout) {
78296465Sdelphij        CMSerr(CMS_F_CMS_COPY_CONTENT, ERR_R_MALLOC_FAILURE);
79296465Sdelphij        goto err;
80296465Sdelphij    }
81183234Ssimon
82296465Sdelphij    /* Read all content through chain to process digest, decrypt etc */
83296465Sdelphij    for (;;) {
84296465Sdelphij        i = BIO_read(in, buf, sizeof(buf));
85296465Sdelphij        if (i <= 0) {
86296465Sdelphij            if (BIO_method_type(in) == BIO_TYPE_CIPHER) {
87296465Sdelphij                if (!BIO_get_cipher_status(in))
88296465Sdelphij                    goto err;
89296465Sdelphij            }
90296465Sdelphij            if (i < 0)
91296465Sdelphij                goto err;
92296465Sdelphij            break;
93296465Sdelphij        }
94183234Ssimon
95296465Sdelphij        if (tmpout && (BIO_write(tmpout, buf, i) != i))
96296465Sdelphij            goto err;
97296465Sdelphij    }
98183234Ssimon
99296465Sdelphij    if (flags & CMS_TEXT) {
100296465Sdelphij        if (!SMIME_text(tmpout, out)) {
101296465Sdelphij            CMSerr(CMS_F_CMS_COPY_CONTENT, CMS_R_SMIME_TEXT_ERROR);
102296465Sdelphij            goto err;
103296465Sdelphij        }
104296465Sdelphij    }
105183234Ssimon
106296465Sdelphij    r = 1;
107183234Ssimon
108296465Sdelphij err:
109296465Sdelphij    if (tmpout && (tmpout != out))
110296465Sdelphij        BIO_free(tmpout);
111296465Sdelphij    return r;
112183234Ssimon
113296465Sdelphij}
114296465Sdelphij
115183234Ssimonstatic int check_content(CMS_ContentInfo *cms)
116296465Sdelphij{
117296465Sdelphij    ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
118296465Sdelphij    if (!pos || !*pos) {
119296465Sdelphij        CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT);
120296465Sdelphij        return 0;
121296465Sdelphij    }
122296465Sdelphij    return 1;
123296465Sdelphij}
124183234Ssimon
125183234Ssimonstatic void do_free_upto(BIO *f, BIO *upto)
126296465Sdelphij{
127296465Sdelphij    if (upto) {
128296465Sdelphij        BIO *tbio;
129296465Sdelphij        do {
130296465Sdelphij            tbio = BIO_pop(f);
131296465Sdelphij            BIO_free(f);
132296465Sdelphij            f = tbio;
133296465Sdelphij        }
134296465Sdelphij        while (f && f != upto);
135296465Sdelphij    } else
136296465Sdelphij        BIO_free_all(f);
137296465Sdelphij}
138183234Ssimon
139183234Ssimonint CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
140296465Sdelphij{
141296465Sdelphij    BIO *cont;
142296465Sdelphij    int r;
143296465Sdelphij    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) {
144296465Sdelphij        CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA);
145296465Sdelphij        return 0;
146296465Sdelphij    }
147296465Sdelphij    cont = CMS_dataInit(cms, NULL);
148296465Sdelphij    if (!cont)
149296465Sdelphij        return 0;
150296465Sdelphij    r = cms_copy_content(out, cont, flags);
151296465Sdelphij    BIO_free_all(cont);
152296465Sdelphij    return r;
153296465Sdelphij}
154183234Ssimon
155183234SsimonCMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
156296465Sdelphij{
157296465Sdelphij    CMS_ContentInfo *cms;
158296465Sdelphij    cms = cms_Data_create();
159296465Sdelphij    if (!cms)
160296465Sdelphij        return NULL;
161183234Ssimon
162296465Sdelphij    if (CMS_final(cms, in, NULL, flags))
163296465Sdelphij        return cms;
164183234Ssimon
165296465Sdelphij    CMS_ContentInfo_free(cms);
166183234Ssimon
167296465Sdelphij    return NULL;
168296465Sdelphij}
169183234Ssimon
170183234Ssimonint CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
171296465Sdelphij                      unsigned int flags)
172296465Sdelphij{
173296465Sdelphij    BIO *cont;
174296465Sdelphij    int r;
175296465Sdelphij    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) {
176296465Sdelphij        CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA);
177296465Sdelphij        return 0;
178296465Sdelphij    }
179183234Ssimon
180296465Sdelphij    if (!dcont && !check_content(cms))
181296465Sdelphij        return 0;
182183234Ssimon
183296465Sdelphij    cont = CMS_dataInit(cms, dcont);
184296465Sdelphij    if (!cont)
185296465Sdelphij        return 0;
186296465Sdelphij    r = cms_copy_content(out, cont, flags);
187296465Sdelphij    if (r)
188296465Sdelphij        r = cms_DigestedData_do_final(cms, cont, 1);
189296465Sdelphij    do_free_upto(cont, dcont);
190296465Sdelphij    return r;
191296465Sdelphij}
192183234Ssimon
193183234SsimonCMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
194296465Sdelphij                                   unsigned int flags)
195296465Sdelphij{
196296465Sdelphij    CMS_ContentInfo *cms;
197296465Sdelphij    if (!md)
198296465Sdelphij        md = EVP_sha1();
199296465Sdelphij    cms = cms_DigestedData_create(md);
200296465Sdelphij    if (!cms)
201296465Sdelphij        return NULL;
202183234Ssimon
203296465Sdelphij    if (!(flags & CMS_DETACHED)) {
204296465Sdelphij        flags &= ~CMS_STREAM;
205296465Sdelphij        CMS_set_detached(cms, 0);
206296465Sdelphij    }
207183234Ssimon
208296465Sdelphij    if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
209296465Sdelphij        return cms;
210183234Ssimon
211296465Sdelphij    CMS_ContentInfo_free(cms);
212296465Sdelphij    return NULL;
213296465Sdelphij}
214183234Ssimon
215183234Ssimonint CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
216296465Sdelphij                              const unsigned char *key, size_t keylen,
217296465Sdelphij                              BIO *dcont, BIO *out, unsigned int flags)
218296465Sdelphij{
219296465Sdelphij    BIO *cont;
220296465Sdelphij    int r;
221296465Sdelphij    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) {
222296465Sdelphij        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT,
223296465Sdelphij               CMS_R_TYPE_NOT_ENCRYPTED_DATA);
224296465Sdelphij        return 0;
225296465Sdelphij    }
226183234Ssimon
227296465Sdelphij    if (!dcont && !check_content(cms))
228296465Sdelphij        return 0;
229183234Ssimon
230296465Sdelphij    if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
231296465Sdelphij        return 0;
232296465Sdelphij    cont = CMS_dataInit(cms, dcont);
233296465Sdelphij    if (!cont)
234296465Sdelphij        return 0;
235296465Sdelphij    r = cms_copy_content(out, cont, flags);
236296465Sdelphij    do_free_upto(cont, dcont);
237296465Sdelphij    return r;
238296465Sdelphij}
239183234Ssimon
240183234SsimonCMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
241296465Sdelphij                                           const unsigned char *key,
242296465Sdelphij                                           size_t keylen, unsigned int flags)
243296465Sdelphij{
244296465Sdelphij    CMS_ContentInfo *cms;
245296465Sdelphij    if (!cipher) {
246296465Sdelphij        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER);
247296465Sdelphij        return NULL;
248296465Sdelphij    }
249296465Sdelphij    cms = CMS_ContentInfo_new();
250296465Sdelphij    if (!cms)
251296465Sdelphij        return NULL;
252296465Sdelphij    if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
253296465Sdelphij        return NULL;
254183234Ssimon
255296465Sdelphij    if (!(flags & CMS_DETACHED)) {
256296465Sdelphij        flags &= ~CMS_STREAM;
257296465Sdelphij        CMS_set_detached(cms, 0);
258296465Sdelphij    }
259183234Ssimon
260296465Sdelphij    if ((flags & (CMS_STREAM | CMS_PARTIAL))
261296465Sdelphij        || CMS_final(cms, in, NULL, flags))
262296465Sdelphij        return cms;
263183234Ssimon
264296465Sdelphij    CMS_ContentInfo_free(cms);
265296465Sdelphij    return NULL;
266296465Sdelphij}
267183234Ssimon
268183234Ssimonstatic int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
269296465Sdelphij                                      X509_STORE *store,
270296465Sdelphij                                      STACK_OF(X509) *certs,
271296465Sdelphij                                      STACK_OF(X509_CRL) *crls,
272296465Sdelphij                                      unsigned int flags)
273296465Sdelphij{
274296465Sdelphij    X509_STORE_CTX ctx;
275296465Sdelphij    X509 *signer;
276296465Sdelphij    int i, j, r = 0;
277296465Sdelphij    CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
278296465Sdelphij    if (!X509_STORE_CTX_init(&ctx, store, signer, certs)) {
279296465Sdelphij        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, CMS_R_STORE_INIT_ERROR);
280296465Sdelphij        goto err;
281296465Sdelphij    }
282296465Sdelphij    X509_STORE_CTX_set_default(&ctx, "smime_sign");
283296465Sdelphij    if (crls)
284296465Sdelphij        X509_STORE_CTX_set0_crls(&ctx, crls);
285183234Ssimon
286296465Sdelphij    i = X509_verify_cert(&ctx);
287296465Sdelphij    if (i <= 0) {
288296465Sdelphij        j = X509_STORE_CTX_get_error(&ctx);
289296465Sdelphij        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
290296465Sdelphij               CMS_R_CERTIFICATE_VERIFY_ERROR);
291296465Sdelphij        ERR_add_error_data(2, "Verify error:",
292296465Sdelphij                           X509_verify_cert_error_string(j));
293296465Sdelphij        goto err;
294296465Sdelphij    }
295296465Sdelphij    r = 1;
296296465Sdelphij err:
297296465Sdelphij    X509_STORE_CTX_cleanup(&ctx);
298296465Sdelphij    return r;
299183234Ssimon
300296465Sdelphij}
301183234Ssimon
302183234Ssimonint CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
303296465Sdelphij               X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags)
304296465Sdelphij{
305296465Sdelphij    CMS_SignerInfo *si;
306296465Sdelphij    STACK_OF(CMS_SignerInfo) *sinfos;
307296465Sdelphij    STACK_OF(X509) *cms_certs = NULL;
308296465Sdelphij    STACK_OF(X509_CRL) *crls = NULL;
309296465Sdelphij    X509 *signer;
310296465Sdelphij    int i, scount = 0, ret = 0;
311296465Sdelphij    BIO *cmsbio = NULL, *tmpin = NULL;
312183234Ssimon
313296465Sdelphij    if (!dcont && !check_content(cms))
314296465Sdelphij        return 0;
315183234Ssimon
316296465Sdelphij    /* Attempt to find all signer certificates */
317183234Ssimon
318296465Sdelphij    sinfos = CMS_get0_SignerInfos(cms);
319183234Ssimon
320296465Sdelphij    if (sk_CMS_SignerInfo_num(sinfos) <= 0) {
321296465Sdelphij        CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS);
322296465Sdelphij        goto err;
323296465Sdelphij    }
324183234Ssimon
325296465Sdelphij    for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
326296465Sdelphij        si = sk_CMS_SignerInfo_value(sinfos, i);
327296465Sdelphij        CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
328296465Sdelphij        if (signer)
329296465Sdelphij            scount++;
330296465Sdelphij    }
331183234Ssimon
332296465Sdelphij    if (scount != sk_CMS_SignerInfo_num(sinfos))
333296465Sdelphij        scount += CMS_set1_signers_certs(cms, certs, flags);
334183234Ssimon
335296465Sdelphij    if (scount != sk_CMS_SignerInfo_num(sinfos)) {
336296465Sdelphij        CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
337296465Sdelphij        goto err;
338296465Sdelphij    }
339183234Ssimon
340296465Sdelphij    /* Attempt to verify all signers certs */
341183234Ssimon
342296465Sdelphij    if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) {
343296465Sdelphij        cms_certs = CMS_get1_certs(cms);
344296465Sdelphij        if (!(flags & CMS_NOCRL))
345296465Sdelphij            crls = CMS_get1_crls(cms);
346296465Sdelphij        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
347296465Sdelphij            si = sk_CMS_SignerInfo_value(sinfos, i);
348296465Sdelphij            if (!cms_signerinfo_verify_cert(si, store,
349296465Sdelphij                                            cms_certs, crls, flags))
350296465Sdelphij                goto err;
351296465Sdelphij        }
352296465Sdelphij    }
353183234Ssimon
354296465Sdelphij    /* Attempt to verify all SignerInfo signed attribute signatures */
355183234Ssimon
356296465Sdelphij    if (!(flags & CMS_NO_ATTR_VERIFY)) {
357296465Sdelphij        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
358296465Sdelphij            si = sk_CMS_SignerInfo_value(sinfos, i);
359296465Sdelphij            if (CMS_signed_get_attr_count(si) < 0)
360296465Sdelphij                continue;
361296465Sdelphij            if (CMS_SignerInfo_verify(si) <= 0)
362296465Sdelphij                goto err;
363296465Sdelphij        }
364296465Sdelphij    }
365183234Ssimon
366296465Sdelphij    /*
367296465Sdelphij     * Performance optimization: if the content is a memory BIO then store
368296465Sdelphij     * its contents in a temporary read only memory BIO. This avoids
369296465Sdelphij     * potentially large numbers of slow copies of data which will occur when
370296465Sdelphij     * reading from a read write memory BIO when signatures are calculated.
371296465Sdelphij     */
372183234Ssimon
373296465Sdelphij    if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) {
374296465Sdelphij        char *ptr;
375296465Sdelphij        long len;
376296465Sdelphij        len = BIO_get_mem_data(dcont, &ptr);
377296465Sdelphij        tmpin = BIO_new_mem_buf(ptr, len);
378296465Sdelphij        if (tmpin == NULL) {
379296465Sdelphij            CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE);
380296465Sdelphij            return 0;
381296465Sdelphij        }
382296465Sdelphij    } else
383296465Sdelphij        tmpin = dcont;
384183234Ssimon
385296465Sdelphij    cmsbio = CMS_dataInit(cms, tmpin);
386296465Sdelphij    if (!cmsbio)
387296465Sdelphij        goto err;
388183234Ssimon
389296465Sdelphij    if (!cms_copy_content(out, cmsbio, flags))
390296465Sdelphij        goto err;
391183234Ssimon
392296465Sdelphij    if (!(flags & CMS_NO_CONTENT_VERIFY)) {
393296465Sdelphij        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
394296465Sdelphij            si = sk_CMS_SignerInfo_value(sinfos, i);
395296465Sdelphij            if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) {
396296465Sdelphij                CMSerr(CMS_F_CMS_VERIFY, CMS_R_CONTENT_VERIFY_ERROR);
397296465Sdelphij                goto err;
398296465Sdelphij            }
399296465Sdelphij        }
400296465Sdelphij    }
401183234Ssimon
402296465Sdelphij    ret = 1;
403183234Ssimon
404296465Sdelphij err:
405183234Ssimon
406296465Sdelphij    if (dcont && (tmpin == dcont))
407296465Sdelphij        do_free_upto(cmsbio, dcont);
408296465Sdelphij    else
409296465Sdelphij        BIO_free_all(cmsbio);
410183234Ssimon
411296465Sdelphij    if (cms_certs)
412296465Sdelphij        sk_X509_pop_free(cms_certs, X509_free);
413296465Sdelphij    if (crls)
414296465Sdelphij        sk_X509_CRL_pop_free(crls, X509_CRL_free);
415183234Ssimon
416296465Sdelphij    return ret;
417296465Sdelphij}
418296465Sdelphij
419183234Ssimonint CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
420296465Sdelphij                       STACK_OF(X509) *certs,
421296465Sdelphij                       X509_STORE *store, unsigned int flags)
422296465Sdelphij{
423296465Sdelphij    int r;
424296465Sdelphij    r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
425296465Sdelphij    if (r <= 0)
426296465Sdelphij        return r;
427296465Sdelphij    return cms_Receipt_verify(rcms, ocms);
428296465Sdelphij}
429183234Ssimon
430296465SdelphijCMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey,
431296465Sdelphij                          STACK_OF(X509) *certs, BIO *data,
432296465Sdelphij                          unsigned int flags)
433296465Sdelphij{
434296465Sdelphij    CMS_ContentInfo *cms;
435296465Sdelphij    int i;
436183234Ssimon
437296465Sdelphij    cms = CMS_ContentInfo_new();
438296465Sdelphij    if (!cms || !CMS_SignedData_init(cms))
439296465Sdelphij        goto merr;
440183234Ssimon
441296465Sdelphij    if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) {
442296465Sdelphij        CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR);
443296465Sdelphij        goto err;
444296465Sdelphij    }
445183234Ssimon
446296465Sdelphij    for (i = 0; i < sk_X509_num(certs); i++) {
447296465Sdelphij        X509 *x = sk_X509_value(certs, i);
448296465Sdelphij        if (!CMS_add1_cert(cms, x))
449296465Sdelphij            goto merr;
450296465Sdelphij    }
451183234Ssimon
452296465Sdelphij    if (!(flags & CMS_DETACHED)) {
453296465Sdelphij        flags &= ~CMS_STREAM;
454296465Sdelphij        CMS_set_detached(cms, 0);
455296465Sdelphij    }
456183234Ssimon
457296465Sdelphij    if ((flags & (CMS_STREAM | CMS_PARTIAL))
458296465Sdelphij        || CMS_final(cms, data, NULL, flags))
459296465Sdelphij        return cms;
460296465Sdelphij    else
461296465Sdelphij        goto err;
462183234Ssimon
463296465Sdelphij merr:
464296465Sdelphij    CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE);
465183234Ssimon
466296465Sdelphij err:
467296465Sdelphij    if (cms)
468296465Sdelphij        CMS_ContentInfo_free(cms);
469296465Sdelphij    return NULL;
470296465Sdelphij}
471183234Ssimon
472183234SsimonCMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
473296465Sdelphij                                  X509 *signcert, EVP_PKEY *pkey,
474296465Sdelphij                                  STACK_OF(X509) *certs, unsigned int flags)
475296465Sdelphij{
476296465Sdelphij    CMS_SignerInfo *rct_si;
477296465Sdelphij    CMS_ContentInfo *cms = NULL;
478296465Sdelphij    ASN1_OCTET_STRING **pos, *os;
479296465Sdelphij    BIO *rct_cont = NULL;
480296465Sdelphij    int r = 0;
481183234Ssimon
482296465Sdelphij    flags &= ~CMS_STREAM;
483296465Sdelphij    /* Not really detached but avoids content being allocated */
484296465Sdelphij    flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED;
485296465Sdelphij    if (!pkey || !signcert) {
486296465Sdelphij        CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT);
487296465Sdelphij        return NULL;
488296465Sdelphij    }
489183234Ssimon
490296465Sdelphij    /* Initialize signed data */
491183234Ssimon
492296465Sdelphij    cms = CMS_sign(NULL, NULL, certs, NULL, flags);
493296465Sdelphij    if (!cms)
494296465Sdelphij        goto err;
495183234Ssimon
496296465Sdelphij    /* Set inner content type to signed receipt */
497296465Sdelphij    if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt)))
498296465Sdelphij        goto err;
499183234Ssimon
500296465Sdelphij    rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
501296465Sdelphij    if (!rct_si) {
502296465Sdelphij        CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR);
503296465Sdelphij        goto err;
504296465Sdelphij    }
505183234Ssimon
506296465Sdelphij    os = cms_encode_Receipt(si);
507183234Ssimon
508296465Sdelphij    if (!os)
509296465Sdelphij        goto err;
510183234Ssimon
511296465Sdelphij    /* Set content to digest */
512296465Sdelphij    rct_cont = BIO_new_mem_buf(os->data, os->length);
513296465Sdelphij    if (!rct_cont)
514296465Sdelphij        goto err;
515183234Ssimon
516296465Sdelphij    /* Add msgSigDigest attribute */
517183234Ssimon
518296465Sdelphij    if (!cms_msgSigDigest_add1(rct_si, si))
519296465Sdelphij        goto err;
520183234Ssimon
521296465Sdelphij    /* Finalize structure */
522296465Sdelphij    if (!CMS_final(cms, rct_cont, NULL, flags))
523296465Sdelphij        goto err;
524183234Ssimon
525296465Sdelphij    /* Set embedded content */
526296465Sdelphij    pos = CMS_get0_content(cms);
527296465Sdelphij    *pos = os;
528183234Ssimon
529296465Sdelphij    r = 1;
530183234Ssimon
531296465Sdelphij err:
532296465Sdelphij    if (rct_cont)
533296465Sdelphij        BIO_free(rct_cont);
534296465Sdelphij    if (r)
535296465Sdelphij        return cms;
536296465Sdelphij    CMS_ContentInfo_free(cms);
537296465Sdelphij    return NULL;
538183234Ssimon
539296465Sdelphij}
540183234Ssimon
541183234SsimonCMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
542296465Sdelphij                             const EVP_CIPHER *cipher, unsigned int flags)
543296465Sdelphij{
544296465Sdelphij    CMS_ContentInfo *cms;
545296465Sdelphij    int i;
546296465Sdelphij    X509 *recip;
547296465Sdelphij    cms = CMS_EnvelopedData_create(cipher);
548296465Sdelphij    if (!cms)
549296465Sdelphij        goto merr;
550296465Sdelphij    for (i = 0; i < sk_X509_num(certs); i++) {
551296465Sdelphij        recip = sk_X509_value(certs, i);
552296465Sdelphij        if (!CMS_add1_recipient_cert(cms, recip, flags)) {
553296465Sdelphij            CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
554296465Sdelphij            goto err;
555296465Sdelphij        }
556296465Sdelphij    }
557183234Ssimon
558296465Sdelphij    if (!(flags & CMS_DETACHED)) {
559296465Sdelphij        flags &= ~CMS_STREAM;
560296465Sdelphij        CMS_set_detached(cms, 0);
561296465Sdelphij    }
562183234Ssimon
563296465Sdelphij    if ((flags & (CMS_STREAM | CMS_PARTIAL))
564296465Sdelphij        || CMS_final(cms, data, NULL, flags))
565296465Sdelphij        return cms;
566296465Sdelphij    else
567296465Sdelphij        goto err;
568183234Ssimon
569296465Sdelphij merr:
570296465Sdelphij    CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
571296465Sdelphij err:
572296465Sdelphij    if (cms)
573296465Sdelphij        CMS_ContentInfo_free(cms);
574296465Sdelphij    return NULL;
575296465Sdelphij}
576183234Ssimon
577183234Ssimonint CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
578296465Sdelphij{
579296465Sdelphij    STACK_OF(CMS_RecipientInfo) *ris;
580296465Sdelphij    CMS_RecipientInfo *ri;
581296465Sdelphij    int i, r;
582296465Sdelphij    int debug = 0, ri_match = 0;
583296465Sdelphij    ris = CMS_get0_RecipientInfos(cms);
584296465Sdelphij    if (ris)
585296465Sdelphij        debug = cms->d.envelopedData->encryptedContentInfo->debug;
586296465Sdelphij    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
587296465Sdelphij        ri = sk_CMS_RecipientInfo_value(ris, i);
588296465Sdelphij        if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
589296465Sdelphij            continue;
590296465Sdelphij        ri_match = 1;
591296465Sdelphij        /*
592296465Sdelphij         * If we have a cert try matching RecipientInfo otherwise try them
593296465Sdelphij         * all.
594296465Sdelphij         */
595296465Sdelphij        if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) {
596296465Sdelphij            CMS_RecipientInfo_set0_pkey(ri, pk);
597296465Sdelphij            r = CMS_RecipientInfo_decrypt(cms, ri);
598296465Sdelphij            CMS_RecipientInfo_set0_pkey(ri, NULL);
599296465Sdelphij            if (cert) {
600296465Sdelphij                /*
601296465Sdelphij                 * If not debugging clear any error and return success to
602296465Sdelphij                 * avoid leaking of information useful to MMA
603296465Sdelphij                 */
604296465Sdelphij                if (!debug) {
605296465Sdelphij                    ERR_clear_error();
606296465Sdelphij                    return 1;
607296465Sdelphij                }
608296465Sdelphij                if (r > 0)
609296465Sdelphij                    return 1;
610296465Sdelphij                CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR);
611296465Sdelphij                return 0;
612296465Sdelphij            }
613296465Sdelphij            /*
614296465Sdelphij             * If no cert and not debugging don't leave loop after first
615296465Sdelphij             * successful decrypt. Always attempt to decrypt all recipients
616296465Sdelphij             * to avoid leaking timing of a successful decrypt.
617296465Sdelphij             */
618296465Sdelphij            else if (r > 0 && debug)
619296465Sdelphij                return 1;
620296465Sdelphij        }
621296465Sdelphij    }
622296465Sdelphij    /* If no cert and not debugging always return success */
623296465Sdelphij    if (ri_match && !cert && !debug) {
624296465Sdelphij        ERR_clear_error();
625296465Sdelphij        return 1;
626296465Sdelphij    }
627183234Ssimon
628296465Sdelphij    CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
629296465Sdelphij    return 0;
630183234Ssimon
631296465Sdelphij}
632183234Ssimon
633296465Sdelphijint CMS_decrypt_set1_key(CMS_ContentInfo *cms,
634296465Sdelphij                         unsigned char *key, size_t keylen,
635296465Sdelphij                         unsigned char *id, size_t idlen)
636296465Sdelphij{
637296465Sdelphij    STACK_OF(CMS_RecipientInfo) *ris;
638296465Sdelphij    CMS_RecipientInfo *ri;
639296465Sdelphij    int i, r;
640296465Sdelphij    ris = CMS_get0_RecipientInfos(cms);
641296465Sdelphij    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
642296465Sdelphij        ri = sk_CMS_RecipientInfo_value(ris, i);
643296465Sdelphij        if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK)
644296465Sdelphij            continue;
645183234Ssimon
646296465Sdelphij        /*
647296465Sdelphij         * If we have an id try matching RecipientInfo otherwise try them
648296465Sdelphij         * all.
649296465Sdelphij         */
650296465Sdelphij        if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) {
651296465Sdelphij            CMS_RecipientInfo_set0_key(ri, key, keylen);
652296465Sdelphij            r = CMS_RecipientInfo_decrypt(cms, ri);
653296465Sdelphij            CMS_RecipientInfo_set0_key(ri, NULL, 0);
654296465Sdelphij            if (r > 0)
655296465Sdelphij                return 1;
656296465Sdelphij            if (id) {
657296465Sdelphij                CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_DECRYPT_ERROR);
658296465Sdelphij                return 0;
659296465Sdelphij            }
660296465Sdelphij            ERR_clear_error();
661296465Sdelphij        }
662296465Sdelphij    }
663183234Ssimon
664296465Sdelphij    CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT);
665296465Sdelphij    return 0;
666183234Ssimon
667296465Sdelphij}
668296465Sdelphij
669183234Ssimonint CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
670296465Sdelphij                BIO *dcont, BIO *out, unsigned int flags)
671296465Sdelphij{
672296465Sdelphij    int r;
673296465Sdelphij    BIO *cont;
674296465Sdelphij    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) {
675296465Sdelphij        CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
676296465Sdelphij        return 0;
677296465Sdelphij    }
678296465Sdelphij    if (!dcont && !check_content(cms))
679296465Sdelphij        return 0;
680296465Sdelphij    if (flags & CMS_DEBUG_DECRYPT)
681296465Sdelphij        cms->d.envelopedData->encryptedContentInfo->debug = 1;
682296465Sdelphij    else
683296465Sdelphij        cms->d.envelopedData->encryptedContentInfo->debug = 0;
684296465Sdelphij    if (!pk && !cert && !dcont && !out)
685296465Sdelphij        return 1;
686296465Sdelphij    if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
687296465Sdelphij        return 0;
688296465Sdelphij    cont = CMS_dataInit(cms, dcont);
689296465Sdelphij    if (!cont)
690296465Sdelphij        return 0;
691296465Sdelphij    r = cms_copy_content(out, cont, flags);
692296465Sdelphij    do_free_upto(cont, dcont);
693296465Sdelphij    return r;
694296465Sdelphij}
695183234Ssimon
696183234Ssimonint CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
697296465Sdelphij{
698296465Sdelphij    BIO *cmsbio;
699296465Sdelphij    int ret = 0;
700296465Sdelphij    if (!(cmsbio = CMS_dataInit(cms, dcont))) {
701296465Sdelphij        CMSerr(CMS_F_CMS_FINAL, ERR_R_MALLOC_FAILURE);
702296465Sdelphij        return 0;
703296465Sdelphij    }
704183234Ssimon
705296465Sdelphij    SMIME_crlf_copy(data, cmsbio, flags);
706183234Ssimon
707296465Sdelphij    (void)BIO_flush(cmsbio);
708183234Ssimon
709296465Sdelphij    if (!CMS_dataFinal(cms, cmsbio)) {
710296465Sdelphij        CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_DATAFINAL_ERROR);
711296465Sdelphij        goto err;
712296465Sdelphij    }
713183234Ssimon
714296465Sdelphij    ret = 1;
715183234Ssimon
716296465Sdelphij err:
717296465Sdelphij    do_free_upto(cmsbio, dcont);
718183234Ssimon
719296465Sdelphij    return ret;
720183234Ssimon
721296465Sdelphij}
722183234Ssimon
723183234Ssimon#ifdef ZLIB
724183234Ssimon
725183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
726296465Sdelphij                   unsigned int flags)
727296465Sdelphij{
728296465Sdelphij    BIO *cont;
729296465Sdelphij    int r;
730296465Sdelphij    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) {
731296465Sdelphij        CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_TYPE_NOT_COMPRESSED_DATA);
732296465Sdelphij        return 0;
733296465Sdelphij    }
734183234Ssimon
735296465Sdelphij    if (!dcont && !check_content(cms))
736296465Sdelphij        return 0;
737183234Ssimon
738296465Sdelphij    cont = CMS_dataInit(cms, dcont);
739296465Sdelphij    if (!cont)
740296465Sdelphij        return 0;
741296465Sdelphij    r = cms_copy_content(out, cont, flags);
742296465Sdelphij    do_free_upto(cont, dcont);
743296465Sdelphij    return r;
744296465Sdelphij}
745183234Ssimon
746183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
747296465Sdelphij{
748296465Sdelphij    CMS_ContentInfo *cms;
749296465Sdelphij    if (comp_nid <= 0)
750296465Sdelphij        comp_nid = NID_zlib_compression;
751296465Sdelphij    cms = cms_CompressedData_create(comp_nid);
752296465Sdelphij    if (!cms)
753296465Sdelphij        return NULL;
754183234Ssimon
755296465Sdelphij    if (!(flags & CMS_DETACHED)) {
756296465Sdelphij        flags &= ~CMS_STREAM;
757296465Sdelphij        CMS_set_detached(cms, 0);
758296465Sdelphij    }
759183234Ssimon
760296465Sdelphij    if (CMS_final(cms, in, NULL, flags))
761296465Sdelphij        return cms;
762183234Ssimon
763296465Sdelphij    CMS_ContentInfo_free(cms);
764296465Sdelphij    return NULL;
765296465Sdelphij}
766183234Ssimon
767183234Ssimon#else
768183234Ssimon
769183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
770296465Sdelphij                   unsigned int flags)
771296465Sdelphij{
772296465Sdelphij    CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
773296465Sdelphij    return 0;
774296465Sdelphij}
775183234Ssimon
776183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
777296465Sdelphij{
778296465Sdelphij    CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
779296465Sdelphij    return NULL;
780296465Sdelphij}
781183234Ssimon
782183234Ssimon#endif
783