1183234Ssimon/* crypto/cms/cms_smime.c */
2280304Sjkim/*
3280304Sjkim * 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
14280304Sjkim *    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)
64280304Sjkim{
65280304Sjkim    unsigned char buf[4096];
66280304Sjkim    int r = 0, i;
67280304Sjkim    BIO *tmpout = NULL;
68183234Ssimon
69280304Sjkim    if (out == NULL)
70280304Sjkim        tmpout = BIO_new(BIO_s_null());
71280304Sjkim    else if (flags & CMS_TEXT) {
72280304Sjkim        tmpout = BIO_new(BIO_s_mem());
73280304Sjkim        BIO_set_mem_eof_return(tmpout, 0);
74280304Sjkim    } else
75280304Sjkim        tmpout = out;
76183234Ssimon
77280304Sjkim    if (!tmpout) {
78280304Sjkim        CMSerr(CMS_F_CMS_COPY_CONTENT, ERR_R_MALLOC_FAILURE);
79280304Sjkim        goto err;
80280304Sjkim    }
81183234Ssimon
82280304Sjkim    /* Read all content through chain to process digest, decrypt etc */
83280304Sjkim    for (;;) {
84280304Sjkim        i = BIO_read(in, buf, sizeof(buf));
85280304Sjkim        if (i <= 0) {
86280304Sjkim            if (BIO_method_type(in) == BIO_TYPE_CIPHER) {
87280304Sjkim                if (!BIO_get_cipher_status(in))
88280304Sjkim                    goto err;
89280304Sjkim            }
90280304Sjkim            if (i < 0)
91280304Sjkim                goto err;
92280304Sjkim            break;
93280304Sjkim        }
94183234Ssimon
95280304Sjkim        if (tmpout && (BIO_write(tmpout, buf, i) != i))
96280304Sjkim            goto err;
97280304Sjkim    }
98183234Ssimon
99280304Sjkim    if (flags & CMS_TEXT) {
100280304Sjkim        if (!SMIME_text(tmpout, out)) {
101280304Sjkim            CMSerr(CMS_F_CMS_COPY_CONTENT, CMS_R_SMIME_TEXT_ERROR);
102280304Sjkim            goto err;
103280304Sjkim        }
104280304Sjkim    }
105183234Ssimon
106280304Sjkim    r = 1;
107183234Ssimon
108280304Sjkim err:
109280304Sjkim    if (tmpout && (tmpout != out))
110280304Sjkim        BIO_free(tmpout);
111280304Sjkim    return r;
112183234Ssimon
113280304Sjkim}
114280304Sjkim
115183234Ssimonstatic int check_content(CMS_ContentInfo *cms)
116280304Sjkim{
117280304Sjkim    ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
118280304Sjkim    if (!pos || !*pos) {
119280304Sjkim        CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT);
120280304Sjkim        return 0;
121280304Sjkim    }
122280304Sjkim    return 1;
123280304Sjkim}
124183234Ssimon
125183234Ssimonstatic void do_free_upto(BIO *f, BIO *upto)
126280304Sjkim{
127280304Sjkim    if (upto) {
128280304Sjkim        BIO *tbio;
129280304Sjkim        do {
130280304Sjkim            tbio = BIO_pop(f);
131280304Sjkim            BIO_free(f);
132280304Sjkim            f = tbio;
133280304Sjkim        }
134284285Sjkim        while (f && f != upto);
135280304Sjkim    } else
136280304Sjkim        BIO_free_all(f);
137280304Sjkim}
138183234Ssimon
139183234Ssimonint CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
140280304Sjkim{
141280304Sjkim    BIO *cont;
142280304Sjkim    int r;
143280304Sjkim    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) {
144280304Sjkim        CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA);
145280304Sjkim        return 0;
146280304Sjkim    }
147280304Sjkim    cont = CMS_dataInit(cms, NULL);
148280304Sjkim    if (!cont)
149280304Sjkim        return 0;
150280304Sjkim    r = cms_copy_content(out, cont, flags);
151280304Sjkim    BIO_free_all(cont);
152280304Sjkim    return r;
153280304Sjkim}
154183234Ssimon
155183234SsimonCMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
156280304Sjkim{
157280304Sjkim    CMS_ContentInfo *cms;
158280304Sjkim    cms = cms_Data_create();
159280304Sjkim    if (!cms)
160280304Sjkim        return NULL;
161183234Ssimon
162280304Sjkim    if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
163280304Sjkim        return cms;
164183234Ssimon
165280304Sjkim    CMS_ContentInfo_free(cms);
166183234Ssimon
167280304Sjkim    return NULL;
168280304Sjkim}
169183234Ssimon
170183234Ssimonint CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
171280304Sjkim                      unsigned int flags)
172280304Sjkim{
173280304Sjkim    BIO *cont;
174280304Sjkim    int r;
175280304Sjkim    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) {
176280304Sjkim        CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA);
177280304Sjkim        return 0;
178280304Sjkim    }
179183234Ssimon
180280304Sjkim    if (!dcont && !check_content(cms))
181280304Sjkim        return 0;
182183234Ssimon
183280304Sjkim    cont = CMS_dataInit(cms, dcont);
184280304Sjkim    if (!cont)
185280304Sjkim        return 0;
186280304Sjkim    r = cms_copy_content(out, cont, flags);
187280304Sjkim    if (r)
188280304Sjkim        r = cms_DigestedData_do_final(cms, cont, 1);
189280304Sjkim    do_free_upto(cont, dcont);
190280304Sjkim    return r;
191280304Sjkim}
192183234Ssimon
193183234SsimonCMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
194280304Sjkim                                   unsigned int flags)
195280304Sjkim{
196280304Sjkim    CMS_ContentInfo *cms;
197280304Sjkim    if (!md)
198280304Sjkim        md = EVP_sha1();
199280304Sjkim    cms = cms_DigestedData_create(md);
200280304Sjkim    if (!cms)
201280304Sjkim        return NULL;
202183234Ssimon
203280304Sjkim    if (!(flags & CMS_DETACHED))
204280304Sjkim        CMS_set_detached(cms, 0);
205183234Ssimon
206280304Sjkim    if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
207280304Sjkim        return cms;
208183234Ssimon
209280304Sjkim    CMS_ContentInfo_free(cms);
210280304Sjkim    return NULL;
211280304Sjkim}
212183234Ssimon
213183234Ssimonint CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
214280304Sjkim                              const unsigned char *key, size_t keylen,
215280304Sjkim                              BIO *dcont, BIO *out, unsigned int flags)
216280304Sjkim{
217280304Sjkim    BIO *cont;
218280304Sjkim    int r;
219280304Sjkim    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) {
220280304Sjkim        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT,
221280304Sjkim               CMS_R_TYPE_NOT_ENCRYPTED_DATA);
222280304Sjkim        return 0;
223280304Sjkim    }
224183234Ssimon
225280304Sjkim    if (!dcont && !check_content(cms))
226280304Sjkim        return 0;
227183234Ssimon
228280304Sjkim    if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
229280304Sjkim        return 0;
230280304Sjkim    cont = CMS_dataInit(cms, dcont);
231280304Sjkim    if (!cont)
232280304Sjkim        return 0;
233280304Sjkim    r = cms_copy_content(out, cont, flags);
234280304Sjkim    do_free_upto(cont, dcont);
235280304Sjkim    return r;
236280304Sjkim}
237183234Ssimon
238183234SsimonCMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
239280304Sjkim                                           const unsigned char *key,
240280304Sjkim                                           size_t keylen, unsigned int flags)
241280304Sjkim{
242280304Sjkim    CMS_ContentInfo *cms;
243280304Sjkim    if (!cipher) {
244280304Sjkim        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER);
245280304Sjkim        return NULL;
246280304Sjkim    }
247280304Sjkim    cms = CMS_ContentInfo_new();
248280304Sjkim    if (!cms)
249280304Sjkim        return NULL;
250280304Sjkim    if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
251280304Sjkim        return NULL;
252183234Ssimon
253280304Sjkim    if (!(flags & CMS_DETACHED))
254280304Sjkim        CMS_set_detached(cms, 0);
255183234Ssimon
256280304Sjkim    if ((flags & (CMS_STREAM | CMS_PARTIAL))
257280304Sjkim        || CMS_final(cms, in, NULL, flags))
258280304Sjkim        return cms;
259183234Ssimon
260280304Sjkim    CMS_ContentInfo_free(cms);
261280304Sjkim    return NULL;
262280304Sjkim}
263183234Ssimon
264183234Ssimonstatic int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
265280304Sjkim                                      X509_STORE *store,
266280304Sjkim                                      STACK_OF(X509) *certs,
267280304Sjkim                                      STACK_OF(X509_CRL) *crls,
268280304Sjkim                                      unsigned int flags)
269280304Sjkim{
270280304Sjkim    X509_STORE_CTX ctx;
271280304Sjkim    X509 *signer;
272280304Sjkim    int i, j, r = 0;
273280304Sjkim    CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
274280304Sjkim    if (!X509_STORE_CTX_init(&ctx, store, signer, certs)) {
275280304Sjkim        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, CMS_R_STORE_INIT_ERROR);
276280304Sjkim        goto err;
277280304Sjkim    }
278280304Sjkim    X509_STORE_CTX_set_default(&ctx, "smime_sign");
279280304Sjkim    if (crls)
280280304Sjkim        X509_STORE_CTX_set0_crls(&ctx, crls);
281183234Ssimon
282280304Sjkim    i = X509_verify_cert(&ctx);
283280304Sjkim    if (i <= 0) {
284280304Sjkim        j = X509_STORE_CTX_get_error(&ctx);
285280304Sjkim        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
286280304Sjkim               CMS_R_CERTIFICATE_VERIFY_ERROR);
287280304Sjkim        ERR_add_error_data(2, "Verify error:",
288280304Sjkim                           X509_verify_cert_error_string(j));
289280304Sjkim        goto err;
290280304Sjkim    }
291280304Sjkim    r = 1;
292280304Sjkim err:
293280304Sjkim    X509_STORE_CTX_cleanup(&ctx);
294280304Sjkim    return r;
295183234Ssimon
296280304Sjkim}
297183234Ssimon
298183234Ssimonint CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
299280304Sjkim               X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags)
300280304Sjkim{
301280304Sjkim    CMS_SignerInfo *si;
302280304Sjkim    STACK_OF(CMS_SignerInfo) *sinfos;
303280304Sjkim    STACK_OF(X509) *cms_certs = NULL;
304280304Sjkim    STACK_OF(X509_CRL) *crls = NULL;
305280304Sjkim    X509 *signer;
306280304Sjkim    int i, scount = 0, ret = 0;
307280304Sjkim    BIO *cmsbio = NULL, *tmpin = NULL;
308183234Ssimon
309280304Sjkim    if (!dcont && !check_content(cms))
310280304Sjkim        return 0;
311183234Ssimon
312280304Sjkim    /* Attempt to find all signer certificates */
313183234Ssimon
314280304Sjkim    sinfos = CMS_get0_SignerInfos(cms);
315183234Ssimon
316280304Sjkim    if (sk_CMS_SignerInfo_num(sinfos) <= 0) {
317280304Sjkim        CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS);
318280304Sjkim        goto err;
319280304Sjkim    }
320183234Ssimon
321280304Sjkim    for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
322280304Sjkim        si = sk_CMS_SignerInfo_value(sinfos, i);
323280304Sjkim        CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
324280304Sjkim        if (signer)
325280304Sjkim            scount++;
326280304Sjkim    }
327183234Ssimon
328280304Sjkim    if (scount != sk_CMS_SignerInfo_num(sinfos))
329280304Sjkim        scount += CMS_set1_signers_certs(cms, certs, flags);
330183234Ssimon
331280304Sjkim    if (scount != sk_CMS_SignerInfo_num(sinfos)) {
332280304Sjkim        CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
333280304Sjkim        goto err;
334280304Sjkim    }
335183234Ssimon
336280304Sjkim    /* Attempt to verify all signers certs */
337183234Ssimon
338280304Sjkim    if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) {
339280304Sjkim        cms_certs = CMS_get1_certs(cms);
340280304Sjkim        if (!(flags & CMS_NOCRL))
341280304Sjkim            crls = CMS_get1_crls(cms);
342280304Sjkim        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
343280304Sjkim            si = sk_CMS_SignerInfo_value(sinfos, i);
344280304Sjkim            if (!cms_signerinfo_verify_cert(si, store,
345280304Sjkim                                            cms_certs, crls, flags))
346280304Sjkim                goto err;
347280304Sjkim        }
348280304Sjkim    }
349183234Ssimon
350280304Sjkim    /* Attempt to verify all SignerInfo signed attribute signatures */
351183234Ssimon
352280304Sjkim    if (!(flags & CMS_NO_ATTR_VERIFY)) {
353280304Sjkim        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
354280304Sjkim            si = sk_CMS_SignerInfo_value(sinfos, i);
355280304Sjkim            if (CMS_signed_get_attr_count(si) < 0)
356280304Sjkim                continue;
357280304Sjkim            if (CMS_SignerInfo_verify(si) <= 0)
358280304Sjkim                goto err;
359280304Sjkim        }
360280304Sjkim    }
361183234Ssimon
362280304Sjkim    /*
363280304Sjkim     * Performance optimization: if the content is a memory BIO then store
364280304Sjkim     * its contents in a temporary read only memory BIO. This avoids
365280304Sjkim     * potentially large numbers of slow copies of data which will occur when
366280304Sjkim     * reading from a read write memory BIO when signatures are calculated.
367280304Sjkim     */
368183234Ssimon
369280304Sjkim    if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) {
370280304Sjkim        char *ptr;
371280304Sjkim        long len;
372280304Sjkim        len = BIO_get_mem_data(dcont, &ptr);
373280304Sjkim        tmpin = BIO_new_mem_buf(ptr, len);
374280304Sjkim        if (tmpin == NULL) {
375280304Sjkim            CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE);
376280304Sjkim            return 0;
377280304Sjkim        }
378280304Sjkim    } else
379280304Sjkim        tmpin = dcont;
380183234Ssimon
381280304Sjkim    cmsbio = CMS_dataInit(cms, tmpin);
382280304Sjkim    if (!cmsbio)
383280304Sjkim        goto err;
384183234Ssimon
385280304Sjkim    if (!cms_copy_content(out, cmsbio, flags))
386280304Sjkim        goto err;
387183234Ssimon
388280304Sjkim    if (!(flags & CMS_NO_CONTENT_VERIFY)) {
389280304Sjkim        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
390280304Sjkim            si = sk_CMS_SignerInfo_value(sinfos, i);
391280304Sjkim            if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) {
392280304Sjkim                CMSerr(CMS_F_CMS_VERIFY, CMS_R_CONTENT_VERIFY_ERROR);
393280304Sjkim                goto err;
394280304Sjkim            }
395280304Sjkim        }
396280304Sjkim    }
397183234Ssimon
398280304Sjkim    ret = 1;
399183234Ssimon
400280304Sjkim err:
401183234Ssimon
402280304Sjkim    if (dcont && (tmpin == dcont))
403280304Sjkim        do_free_upto(cmsbio, dcont);
404280304Sjkim    else
405280304Sjkim        BIO_free_all(cmsbio);
406183234Ssimon
407280304Sjkim    if (cms_certs)
408280304Sjkim        sk_X509_pop_free(cms_certs, X509_free);
409280304Sjkim    if (crls)
410280304Sjkim        sk_X509_CRL_pop_free(crls, X509_CRL_free);
411183234Ssimon
412280304Sjkim    return ret;
413280304Sjkim}
414280304Sjkim
415183234Ssimonint CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
416280304Sjkim                       STACK_OF(X509) *certs,
417280304Sjkim                       X509_STORE *store, unsigned int flags)
418280304Sjkim{
419280304Sjkim    int r;
420280304Sjkim    flags &= ~(CMS_DETACHED | CMS_TEXT);
421280304Sjkim    r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
422280304Sjkim    if (r <= 0)
423280304Sjkim        return r;
424280304Sjkim    return cms_Receipt_verify(rcms, ocms);
425280304Sjkim}
426183234Ssimon
427280304SjkimCMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey,
428280304Sjkim                          STACK_OF(X509) *certs, BIO *data,
429280304Sjkim                          unsigned int flags)
430280304Sjkim{
431280304Sjkim    CMS_ContentInfo *cms;
432280304Sjkim    int i;
433183234Ssimon
434280304Sjkim    cms = CMS_ContentInfo_new();
435280304Sjkim    if (!cms || !CMS_SignedData_init(cms))
436280304Sjkim        goto merr;
437183234Ssimon
438280304Sjkim    if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) {
439280304Sjkim        CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR);
440280304Sjkim        goto err;
441280304Sjkim    }
442183234Ssimon
443280304Sjkim    for (i = 0; i < sk_X509_num(certs); i++) {
444280304Sjkim        X509 *x = sk_X509_value(certs, i);
445280304Sjkim        if (!CMS_add1_cert(cms, x))
446280304Sjkim            goto merr;
447280304Sjkim    }
448183234Ssimon
449280304Sjkim    if (!(flags & CMS_DETACHED))
450280304Sjkim        CMS_set_detached(cms, 0);
451183234Ssimon
452280304Sjkim    if ((flags & (CMS_STREAM | CMS_PARTIAL))
453280304Sjkim        || CMS_final(cms, data, NULL, flags))
454280304Sjkim        return cms;
455280304Sjkim    else
456280304Sjkim        goto err;
457183234Ssimon
458280304Sjkim merr:
459280304Sjkim    CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE);
460183234Ssimon
461280304Sjkim err:
462280304Sjkim    if (cms)
463280304Sjkim        CMS_ContentInfo_free(cms);
464280304Sjkim    return NULL;
465280304Sjkim}
466183234Ssimon
467183234SsimonCMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
468280304Sjkim                                  X509 *signcert, EVP_PKEY *pkey,
469280304Sjkim                                  STACK_OF(X509) *certs, unsigned int flags)
470280304Sjkim{
471280304Sjkim    CMS_SignerInfo *rct_si;
472280304Sjkim    CMS_ContentInfo *cms = NULL;
473280304Sjkim    ASN1_OCTET_STRING **pos, *os;
474280304Sjkim    BIO *rct_cont = NULL;
475280304Sjkim    int r = 0;
476183234Ssimon
477280304Sjkim    flags &= ~(CMS_STREAM | CMS_TEXT);
478280304Sjkim    /* Not really detached but avoids content being allocated */
479280304Sjkim    flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED;
480280304Sjkim    if (!pkey || !signcert) {
481280304Sjkim        CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT);
482280304Sjkim        return NULL;
483280304Sjkim    }
484183234Ssimon
485280304Sjkim    /* Initialize signed data */
486183234Ssimon
487280304Sjkim    cms = CMS_sign(NULL, NULL, certs, NULL, flags);
488280304Sjkim    if (!cms)
489280304Sjkim        goto err;
490183234Ssimon
491280304Sjkim    /* Set inner content type to signed receipt */
492280304Sjkim    if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt)))
493280304Sjkim        goto err;
494183234Ssimon
495280304Sjkim    rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
496280304Sjkim    if (!rct_si) {
497280304Sjkim        CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR);
498280304Sjkim        goto err;
499280304Sjkim    }
500183234Ssimon
501280304Sjkim    os = cms_encode_Receipt(si);
502183234Ssimon
503280304Sjkim    if (!os)
504280304Sjkim        goto err;
505183234Ssimon
506280304Sjkim    /* Set content to digest */
507280304Sjkim    rct_cont = BIO_new_mem_buf(os->data, os->length);
508280304Sjkim    if (!rct_cont)
509280304Sjkim        goto err;
510183234Ssimon
511280304Sjkim    /* Add msgSigDigest attribute */
512183234Ssimon
513280304Sjkim    if (!cms_msgSigDigest_add1(rct_si, si))
514280304Sjkim        goto err;
515183234Ssimon
516280304Sjkim    /* Finalize structure */
517280304Sjkim    if (!CMS_final(cms, rct_cont, NULL, flags))
518280304Sjkim        goto err;
519183234Ssimon
520280304Sjkim    /* Set embedded content */
521280304Sjkim    pos = CMS_get0_content(cms);
522280304Sjkim    *pos = os;
523183234Ssimon
524280304Sjkim    r = 1;
525183234Ssimon
526280304Sjkim err:
527280304Sjkim    if (rct_cont)
528280304Sjkim        BIO_free(rct_cont);
529280304Sjkim    if (r)
530280304Sjkim        return cms;
531280304Sjkim    CMS_ContentInfo_free(cms);
532280304Sjkim    return NULL;
533183234Ssimon
534280304Sjkim}
535183234Ssimon
536183234SsimonCMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
537280304Sjkim                             const EVP_CIPHER *cipher, unsigned int flags)
538280304Sjkim{
539280304Sjkim    CMS_ContentInfo *cms;
540280304Sjkim    int i;
541280304Sjkim    X509 *recip;
542280304Sjkim    cms = CMS_EnvelopedData_create(cipher);
543280304Sjkim    if (!cms)
544280304Sjkim        goto merr;
545280304Sjkim    for (i = 0; i < sk_X509_num(certs); i++) {
546280304Sjkim        recip = sk_X509_value(certs, i);
547280304Sjkim        if (!CMS_add1_recipient_cert(cms, recip, flags)) {
548280304Sjkim            CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
549280304Sjkim            goto err;
550280304Sjkim        }
551280304Sjkim    }
552183234Ssimon
553280304Sjkim    if (!(flags & CMS_DETACHED))
554280304Sjkim        CMS_set_detached(cms, 0);
555183234Ssimon
556280304Sjkim    if ((flags & (CMS_STREAM | CMS_PARTIAL))
557280304Sjkim        || CMS_final(cms, data, NULL, flags))
558280304Sjkim        return cms;
559280304Sjkim    else
560280304Sjkim        goto err;
561183234Ssimon
562280304Sjkim merr:
563280304Sjkim    CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
564280304Sjkim err:
565280304Sjkim    if (cms)
566280304Sjkim        CMS_ContentInfo_free(cms);
567280304Sjkim    return NULL;
568280304Sjkim}
569183234Ssimon
570183234Ssimonint CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
571280304Sjkim{
572280304Sjkim    STACK_OF(CMS_RecipientInfo) *ris;
573280304Sjkim    CMS_RecipientInfo *ri;
574280304Sjkim    int i, r;
575280304Sjkim    int debug = 0, ri_match = 0;
576280304Sjkim    ris = CMS_get0_RecipientInfos(cms);
577280304Sjkim    if (ris)
578280304Sjkim        debug = cms->d.envelopedData->encryptedContentInfo->debug;
579280304Sjkim    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
580280304Sjkim        ri = sk_CMS_RecipientInfo_value(ris, i);
581280304Sjkim        if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
582280304Sjkim            continue;
583280304Sjkim        ri_match = 1;
584280304Sjkim        /*
585280304Sjkim         * If we have a cert try matching RecipientInfo otherwise try them
586280304Sjkim         * all.
587280304Sjkim         */
588280304Sjkim        if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) {
589280304Sjkim            CMS_RecipientInfo_set0_pkey(ri, pk);
590280304Sjkim            r = CMS_RecipientInfo_decrypt(cms, ri);
591280304Sjkim            CMS_RecipientInfo_set0_pkey(ri, NULL);
592280304Sjkim            if (cert) {
593280304Sjkim                /*
594280304Sjkim                 * If not debugging clear any error and return success to
595280304Sjkim                 * avoid leaking of information useful to MMA
596280304Sjkim                 */
597280304Sjkim                if (!debug) {
598280304Sjkim                    ERR_clear_error();
599280304Sjkim                    return 1;
600280304Sjkim                }
601280304Sjkim                if (r > 0)
602280304Sjkim                    return 1;
603280304Sjkim                CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR);
604280304Sjkim                return 0;
605280304Sjkim            }
606280304Sjkim            /*
607280304Sjkim             * If no cert and not debugging don't leave loop after first
608280304Sjkim             * successful decrypt. Always attempt to decrypt all recipients
609280304Sjkim             * to avoid leaking timing of a successful decrypt.
610280304Sjkim             */
611280304Sjkim            else if (r > 0 && debug)
612280304Sjkim                return 1;
613280304Sjkim        }
614280304Sjkim    }
615280304Sjkim    /* If no cert and not debugging always return success */
616280304Sjkim    if (ri_match && !cert && !debug) {
617280304Sjkim        ERR_clear_error();
618280304Sjkim        return 1;
619280304Sjkim    }
620183234Ssimon
621280304Sjkim    CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
622280304Sjkim    return 0;
623183234Ssimon
624280304Sjkim}
625183234Ssimon
626280304Sjkimint CMS_decrypt_set1_key(CMS_ContentInfo *cms,
627280304Sjkim                         unsigned char *key, size_t keylen,
628280304Sjkim                         unsigned char *id, size_t idlen)
629280304Sjkim{
630280304Sjkim    STACK_OF(CMS_RecipientInfo) *ris;
631280304Sjkim    CMS_RecipientInfo *ri;
632280304Sjkim    int i, r;
633280304Sjkim    ris = CMS_get0_RecipientInfos(cms);
634280304Sjkim    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
635280304Sjkim        ri = sk_CMS_RecipientInfo_value(ris, i);
636280304Sjkim        if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK)
637280304Sjkim            continue;
638183234Ssimon
639280304Sjkim        /*
640280304Sjkim         * If we have an id try matching RecipientInfo otherwise try them
641280304Sjkim         * all.
642280304Sjkim         */
643280304Sjkim        if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) {
644280304Sjkim            CMS_RecipientInfo_set0_key(ri, key, keylen);
645280304Sjkim            r = CMS_RecipientInfo_decrypt(cms, ri);
646280304Sjkim            CMS_RecipientInfo_set0_key(ri, NULL, 0);
647280304Sjkim            if (r > 0)
648280304Sjkim                return 1;
649280304Sjkim            if (id) {
650280304Sjkim                CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_DECRYPT_ERROR);
651280304Sjkim                return 0;
652280304Sjkim            }
653280304Sjkim            ERR_clear_error();
654280304Sjkim        }
655280304Sjkim    }
656183234Ssimon
657280304Sjkim    CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT);
658280304Sjkim    return 0;
659183234Ssimon
660280304Sjkim}
661238405Sjkim
662280304Sjkimint CMS_decrypt_set1_password(CMS_ContentInfo *cms,
663280304Sjkim                              unsigned char *pass, ossl_ssize_t passlen)
664280304Sjkim{
665280304Sjkim    STACK_OF(CMS_RecipientInfo) *ris;
666280304Sjkim    CMS_RecipientInfo *ri;
667280304Sjkim    int i, r;
668280304Sjkim    ris = CMS_get0_RecipientInfos(cms);
669280304Sjkim    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
670280304Sjkim        ri = sk_CMS_RecipientInfo_value(ris, i);
671280304Sjkim        if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS)
672280304Sjkim            continue;
673280304Sjkim        CMS_RecipientInfo_set0_password(ri, pass, passlen);
674280304Sjkim        r = CMS_RecipientInfo_decrypt(cms, ri);
675280304Sjkim        CMS_RecipientInfo_set0_password(ri, NULL, 0);
676280304Sjkim        if (r > 0)
677280304Sjkim            return 1;
678280304Sjkim    }
679238405Sjkim
680280304Sjkim    CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT);
681280304Sjkim    return 0;
682238405Sjkim
683280304Sjkim}
684280304Sjkim
685183234Ssimonint CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
686280304Sjkim                BIO *dcont, BIO *out, unsigned int flags)
687280304Sjkim{
688280304Sjkim    int r;
689280304Sjkim    BIO *cont;
690280304Sjkim    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) {
691280304Sjkim        CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
692280304Sjkim        return 0;
693280304Sjkim    }
694280304Sjkim    if (!dcont && !check_content(cms))
695280304Sjkim        return 0;
696280304Sjkim    if (flags & CMS_DEBUG_DECRYPT)
697280304Sjkim        cms->d.envelopedData->encryptedContentInfo->debug = 1;
698280304Sjkim    else
699280304Sjkim        cms->d.envelopedData->encryptedContentInfo->debug = 0;
700280304Sjkim    if (!pk && !cert && !dcont && !out)
701280304Sjkim        return 1;
702280304Sjkim    if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
703280304Sjkim        return 0;
704280304Sjkim    cont = CMS_dataInit(cms, dcont);
705280304Sjkim    if (!cont)
706280304Sjkim        return 0;
707280304Sjkim    r = cms_copy_content(out, cont, flags);
708280304Sjkim    do_free_upto(cont, dcont);
709280304Sjkim    return r;
710280304Sjkim}
711183234Ssimon
712183234Ssimonint CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
713280304Sjkim{
714280304Sjkim    BIO *cmsbio;
715280304Sjkim    int ret = 0;
716280304Sjkim    if (!(cmsbio = CMS_dataInit(cms, dcont))) {
717291721Sjkim        CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_LIB);
718280304Sjkim        return 0;
719280304Sjkim    }
720183234Ssimon
721280304Sjkim    SMIME_crlf_copy(data, cmsbio, flags);
722183234Ssimon
723280304Sjkim    (void)BIO_flush(cmsbio);
724183234Ssimon
725280304Sjkim    if (!CMS_dataFinal(cms, cmsbio)) {
726280304Sjkim        CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_DATAFINAL_ERROR);
727280304Sjkim        goto err;
728280304Sjkim    }
729183234Ssimon
730280304Sjkim    ret = 1;
731183234Ssimon
732280304Sjkim err:
733280304Sjkim    do_free_upto(cmsbio, dcont);
734183234Ssimon
735280304Sjkim    return ret;
736183234Ssimon
737280304Sjkim}
738183234Ssimon
739183234Ssimon#ifdef ZLIB
740183234Ssimon
741183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
742280304Sjkim                   unsigned int flags)
743280304Sjkim{
744280304Sjkim    BIO *cont;
745280304Sjkim    int r;
746280304Sjkim    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) {
747280304Sjkim        CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_TYPE_NOT_COMPRESSED_DATA);
748280304Sjkim        return 0;
749280304Sjkim    }
750183234Ssimon
751280304Sjkim    if (!dcont && !check_content(cms))
752280304Sjkim        return 0;
753183234Ssimon
754280304Sjkim    cont = CMS_dataInit(cms, dcont);
755280304Sjkim    if (!cont)
756280304Sjkim        return 0;
757280304Sjkim    r = cms_copy_content(out, cont, flags);
758280304Sjkim    do_free_upto(cont, dcont);
759280304Sjkim    return r;
760280304Sjkim}
761183234Ssimon
762183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
763280304Sjkim{
764280304Sjkim    CMS_ContentInfo *cms;
765280304Sjkim    if (comp_nid <= 0)
766280304Sjkim        comp_nid = NID_zlib_compression;
767280304Sjkim    cms = cms_CompressedData_create(comp_nid);
768280304Sjkim    if (!cms)
769280304Sjkim        return NULL;
770183234Ssimon
771280304Sjkim    if (!(flags & CMS_DETACHED))
772280304Sjkim        CMS_set_detached(cms, 0);
773183234Ssimon
774280304Sjkim    if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
775280304Sjkim        return cms;
776183234Ssimon
777280304Sjkim    CMS_ContentInfo_free(cms);
778280304Sjkim    return NULL;
779280304Sjkim}
780183234Ssimon
781183234Ssimon#else
782183234Ssimon
783183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
784280304Sjkim                   unsigned int flags)
785280304Sjkim{
786280304Sjkim    CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
787280304Sjkim    return 0;
788280304Sjkim}
789183234Ssimon
790183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
791280304Sjkim{
792280304Sjkim    CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
793280304Sjkim    return NULL;
794280304Sjkim}
795183234Ssimon
796183234Ssimon#endif
797