1183234Ssimon/* crypto/cms/cms_lib.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 <openssl/asn1t.h>
56183234Ssimon#include <openssl/x509.h>
57183234Ssimon#include <openssl/err.h>
58183234Ssimon#include <openssl/pem.h>
59183234Ssimon#include <openssl/bio.h>
60183234Ssimon#include <openssl/asn1.h>
61183234Ssimon#include "cms.h"
62183234Ssimon#include "cms_lcl.h"
63183234Ssimon
64238405SjkimIMPLEMENT_ASN1_FUNCTIONS(CMS_ContentInfo)
65238405SjkimIMPLEMENT_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
66183234Ssimon
67183234SsimonDECLARE_ASN1_ITEM(CMS_CertificateChoices)
68183234SsimonDECLARE_ASN1_ITEM(CMS_RevocationInfoChoice)
69183234SsimonDECLARE_STACK_OF(CMS_CertificateChoices)
70183234SsimonDECLARE_STACK_OF(CMS_RevocationInfoChoice)
71183234Ssimon
72183234Ssimonconst ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms)
73280304Sjkim{
74280304Sjkim    return cms->contentType;
75280304Sjkim}
76183234Ssimon
77183234SsimonCMS_ContentInfo *cms_Data_create(void)
78280304Sjkim{
79280304Sjkim    CMS_ContentInfo *cms;
80280304Sjkim    cms = CMS_ContentInfo_new();
81280304Sjkim    if (cms) {
82280304Sjkim        cms->contentType = OBJ_nid2obj(NID_pkcs7_data);
83280304Sjkim        /* Never detached */
84280304Sjkim        CMS_set_detached(cms, 0);
85280304Sjkim    }
86280304Sjkim    return cms;
87280304Sjkim}
88183234Ssimon
89183234SsimonBIO *cms_content_bio(CMS_ContentInfo *cms)
90280304Sjkim{
91280304Sjkim    ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
92280304Sjkim    if (!pos)
93280304Sjkim        return NULL;
94280304Sjkim    /* If content detached data goes nowhere: create NULL BIO */
95280304Sjkim    if (!*pos)
96280304Sjkim        return BIO_new(BIO_s_null());
97280304Sjkim    /*
98280304Sjkim     * If content not detached and created return memory BIO
99280304Sjkim     */
100280304Sjkim    if (!*pos || ((*pos)->flags == ASN1_STRING_FLAG_CONT))
101280304Sjkim        return BIO_new(BIO_s_mem());
102280304Sjkim    /* Else content was read in: return read only BIO for it */
103280304Sjkim    return BIO_new_mem_buf((*pos)->data, (*pos)->length);
104280304Sjkim}
105183234Ssimon
106183234SsimonBIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont)
107280304Sjkim{
108280304Sjkim    BIO *cmsbio, *cont;
109280304Sjkim    if (icont)
110280304Sjkim        cont = icont;
111280304Sjkim    else
112280304Sjkim        cont = cms_content_bio(cms);
113280304Sjkim    if (!cont) {
114280304Sjkim        CMSerr(CMS_F_CMS_DATAINIT, CMS_R_NO_CONTENT);
115280304Sjkim        return NULL;
116280304Sjkim    }
117280304Sjkim    switch (OBJ_obj2nid(cms->contentType)) {
118183234Ssimon
119280304Sjkim    case NID_pkcs7_data:
120280304Sjkim        return cont;
121183234Ssimon
122280304Sjkim    case NID_pkcs7_signed:
123280304Sjkim        cmsbio = cms_SignedData_init_bio(cms);
124280304Sjkim        break;
125183234Ssimon
126280304Sjkim    case NID_pkcs7_digest:
127280304Sjkim        cmsbio = cms_DigestedData_init_bio(cms);
128280304Sjkim        break;
129183234Ssimon#ifdef ZLIB
130280304Sjkim    case NID_id_smime_ct_compressedData:
131280304Sjkim        cmsbio = cms_CompressedData_init_bio(cms);
132280304Sjkim        break;
133183234Ssimon#endif
134183234Ssimon
135280304Sjkim    case NID_pkcs7_encrypted:
136280304Sjkim        cmsbio = cms_EncryptedData_init_bio(cms);
137280304Sjkim        break;
138183234Ssimon
139280304Sjkim    case NID_pkcs7_enveloped:
140280304Sjkim        cmsbio = cms_EnvelopedData_init_bio(cms);
141280304Sjkim        break;
142183234Ssimon
143280304Sjkim    default:
144280304Sjkim        CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE);
145280304Sjkim        return NULL;
146280304Sjkim    }
147183234Ssimon
148280304Sjkim    if (cmsbio)
149280304Sjkim        return BIO_push(cmsbio, cont);
150183234Ssimon
151280304Sjkim    if (!icont)
152280304Sjkim        BIO_free(cont);
153280304Sjkim    return NULL;
154183234Ssimon
155280304Sjkim}
156183234Ssimon
157183234Ssimonint CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
158280304Sjkim{
159280304Sjkim    ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
160280304Sjkim    if (!pos)
161280304Sjkim        return 0;
162280304Sjkim    /* If ebmedded content find memory BIO and set content */
163280304Sjkim    if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT)) {
164280304Sjkim        BIO *mbio;
165280304Sjkim        unsigned char *cont;
166280304Sjkim        long contlen;
167280304Sjkim        mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM);
168280304Sjkim        if (!mbio) {
169280304Sjkim            CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_CONTENT_NOT_FOUND);
170280304Sjkim            return 0;
171280304Sjkim        }
172280304Sjkim        contlen = BIO_get_mem_data(mbio, &cont);
173280304Sjkim        /* Set bio as read only so its content can't be clobbered */
174280304Sjkim        BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY);
175280304Sjkim        BIO_set_mem_eof_return(mbio, 0);
176280304Sjkim        ASN1_STRING_set0(*pos, cont, contlen);
177280304Sjkim        (*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
178280304Sjkim    }
179183234Ssimon
180280304Sjkim    switch (OBJ_obj2nid(cms->contentType)) {
181183234Ssimon
182280304Sjkim    case NID_pkcs7_data:
183280304Sjkim    case NID_pkcs7_enveloped:
184280304Sjkim    case NID_pkcs7_encrypted:
185280304Sjkim    case NID_id_smime_ct_compressedData:
186280304Sjkim        /* Nothing to do */
187280304Sjkim        return 1;
188183234Ssimon
189280304Sjkim    case NID_pkcs7_signed:
190280304Sjkim        return cms_SignedData_final(cms, cmsbio);
191183234Ssimon
192280304Sjkim    case NID_pkcs7_digest:
193280304Sjkim        return cms_DigestedData_do_final(cms, cmsbio, 0);
194183234Ssimon
195280304Sjkim    default:
196280304Sjkim        CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_UNSUPPORTED_TYPE);
197280304Sjkim        return 0;
198280304Sjkim    }
199280304Sjkim}
200183234Ssimon
201280304Sjkim/*
202280304Sjkim * Return an OCTET STRING pointer to content. This allows it to be accessed
203280304Sjkim * or set later.
204183234Ssimon */
205183234Ssimon
206183234SsimonASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms)
207280304Sjkim{
208280304Sjkim    switch (OBJ_obj2nid(cms->contentType)) {
209183234Ssimon
210280304Sjkim    case NID_pkcs7_data:
211280304Sjkim        return &cms->d.data;
212183234Ssimon
213280304Sjkim    case NID_pkcs7_signed:
214280304Sjkim        return &cms->d.signedData->encapContentInfo->eContent;
215183234Ssimon
216280304Sjkim    case NID_pkcs7_enveloped:
217280304Sjkim        return &cms->d.envelopedData->encryptedContentInfo->encryptedContent;
218183234Ssimon
219280304Sjkim    case NID_pkcs7_digest:
220280304Sjkim        return &cms->d.digestedData->encapContentInfo->eContent;
221183234Ssimon
222280304Sjkim    case NID_pkcs7_encrypted:
223280304Sjkim        return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
224183234Ssimon
225280304Sjkim    case NID_id_smime_ct_authData:
226280304Sjkim        return &cms->d.authenticatedData->encapContentInfo->eContent;
227183234Ssimon
228280304Sjkim    case NID_id_smime_ct_compressedData:
229280304Sjkim        return &cms->d.compressedData->encapContentInfo->eContent;
230183234Ssimon
231280304Sjkim    default:
232280304Sjkim        if (cms->d.other->type == V_ASN1_OCTET_STRING)
233280304Sjkim            return &cms->d.other->value.octet_string;
234280304Sjkim        CMSerr(CMS_F_CMS_GET0_CONTENT, CMS_R_UNSUPPORTED_CONTENT_TYPE);
235280304Sjkim        return NULL;
236183234Ssimon
237280304Sjkim    }
238280304Sjkim}
239183234Ssimon
240280304Sjkim/*
241280304Sjkim * Return an ASN1_OBJECT pointer to content type. This allows it to be
242280304Sjkim * accessed or set later.
243183234Ssimon */
244183234Ssimon
245183234Ssimonstatic ASN1_OBJECT **cms_get0_econtent_type(CMS_ContentInfo *cms)
246280304Sjkim{
247280304Sjkim    switch (OBJ_obj2nid(cms->contentType)) {
248183234Ssimon
249280304Sjkim    case NID_pkcs7_signed:
250280304Sjkim        return &cms->d.signedData->encapContentInfo->eContentType;
251183234Ssimon
252280304Sjkim    case NID_pkcs7_enveloped:
253280304Sjkim        return &cms->d.envelopedData->encryptedContentInfo->contentType;
254183234Ssimon
255280304Sjkim    case NID_pkcs7_digest:
256280304Sjkim        return &cms->d.digestedData->encapContentInfo->eContentType;
257183234Ssimon
258280304Sjkim    case NID_pkcs7_encrypted:
259280304Sjkim        return &cms->d.encryptedData->encryptedContentInfo->contentType;
260183234Ssimon
261280304Sjkim    case NID_id_smime_ct_authData:
262280304Sjkim        return &cms->d.authenticatedData->encapContentInfo->eContentType;
263183234Ssimon
264280304Sjkim    case NID_id_smime_ct_compressedData:
265280304Sjkim        return &cms->d.compressedData->encapContentInfo->eContentType;
266183234Ssimon
267280304Sjkim    default:
268280304Sjkim        CMSerr(CMS_F_CMS_GET0_ECONTENT_TYPE, CMS_R_UNSUPPORTED_CONTENT_TYPE);
269280304Sjkim        return NULL;
270183234Ssimon
271280304Sjkim    }
272280304Sjkim}
273183234Ssimon
274183234Ssimonconst ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms)
275280304Sjkim{
276280304Sjkim    ASN1_OBJECT **petype;
277280304Sjkim    petype = cms_get0_econtent_type(cms);
278280304Sjkim    if (petype)
279280304Sjkim        return *petype;
280280304Sjkim    return NULL;
281280304Sjkim}
282183234Ssimon
283183234Ssimonint CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid)
284280304Sjkim{
285280304Sjkim    ASN1_OBJECT **petype, *etype;
286280304Sjkim    petype = cms_get0_econtent_type(cms);
287280304Sjkim    if (!petype)
288280304Sjkim        return 0;
289280304Sjkim    if (!oid)
290280304Sjkim        return 1;
291280304Sjkim    etype = OBJ_dup(oid);
292280304Sjkim    if (!etype)
293280304Sjkim        return 0;
294280304Sjkim    ASN1_OBJECT_free(*petype);
295280304Sjkim    *petype = etype;
296280304Sjkim    return 1;
297280304Sjkim}
298183234Ssimon
299183234Ssimonint CMS_is_detached(CMS_ContentInfo *cms)
300280304Sjkim{
301280304Sjkim    ASN1_OCTET_STRING **pos;
302280304Sjkim    pos = CMS_get0_content(cms);
303280304Sjkim    if (!pos)
304280304Sjkim        return -1;
305280304Sjkim    if (*pos)
306280304Sjkim        return 0;
307280304Sjkim    return 1;
308280304Sjkim}
309183234Ssimon
310183234Ssimonint CMS_set_detached(CMS_ContentInfo *cms, int detached)
311280304Sjkim{
312280304Sjkim    ASN1_OCTET_STRING **pos;
313280304Sjkim    pos = CMS_get0_content(cms);
314280304Sjkim    if (!pos)
315280304Sjkim        return 0;
316280304Sjkim    if (detached) {
317280304Sjkim        if (*pos) {
318280304Sjkim            ASN1_OCTET_STRING_free(*pos);
319280304Sjkim            *pos = NULL;
320280304Sjkim        }
321280304Sjkim        return 1;
322280304Sjkim    }
323280304Sjkim    if (!*pos)
324280304Sjkim        *pos = ASN1_OCTET_STRING_new();
325280304Sjkim    if (*pos) {
326280304Sjkim        /*
327280304Sjkim         * NB: special flag to show content is created and not read in.
328280304Sjkim         */
329280304Sjkim        (*pos)->flags |= ASN1_STRING_FLAG_CONT;
330280304Sjkim        return 1;
331280304Sjkim    }
332280304Sjkim    CMSerr(CMS_F_CMS_SET_DETACHED, ERR_R_MALLOC_FAILURE);
333280304Sjkim    return 0;
334280304Sjkim}
335183234Ssimon
336183234Ssimon/* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */
337183234Ssimon
338183234Ssimonvoid cms_DigestAlgorithm_set(X509_ALGOR *alg, const EVP_MD *md)
339280304Sjkim{
340280304Sjkim    int param_type;
341183234Ssimon
342280304Sjkim    if (md->flags & EVP_MD_FLAG_DIGALGID_ABSENT)
343280304Sjkim        param_type = V_ASN1_UNDEF;
344280304Sjkim    else
345280304Sjkim        param_type = V_ASN1_NULL;
346183234Ssimon
347280304Sjkim    X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL);
348183234Ssimon
349280304Sjkim}
350183234Ssimon
351183234Ssimon/* Create a digest BIO from an X509_ALGOR structure */
352183234Ssimon
353183234SsimonBIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
354280304Sjkim{
355280304Sjkim    BIO *mdbio = NULL;
356280304Sjkim    ASN1_OBJECT *digestoid;
357280304Sjkim    const EVP_MD *digest;
358280304Sjkim    X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
359280304Sjkim    digest = EVP_get_digestbyobj(digestoid);
360280304Sjkim    if (!digest) {
361280304Sjkim        CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
362280304Sjkim               CMS_R_UNKNOWN_DIGEST_ALGORIHM);
363280304Sjkim        goto err;
364280304Sjkim    }
365280304Sjkim    mdbio = BIO_new(BIO_f_md());
366280304Sjkim    if (!mdbio || !BIO_set_md(mdbio, digest)) {
367280304Sjkim        CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO, CMS_R_MD_BIO_INIT_ERROR);
368280304Sjkim        goto err;
369280304Sjkim    }
370280304Sjkim    return mdbio;
371280304Sjkim err:
372280304Sjkim    if (mdbio)
373280304Sjkim        BIO_free(mdbio);
374280304Sjkim    return NULL;
375280304Sjkim}
376183234Ssimon
377183234Ssimon/* Locate a message digest content from a BIO chain based on SignerInfo */
378183234Ssimon
379183234Ssimonint cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
380280304Sjkim                                 X509_ALGOR *mdalg)
381280304Sjkim{
382280304Sjkim    int nid;
383280304Sjkim    ASN1_OBJECT *mdoid;
384280304Sjkim    X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
385280304Sjkim    nid = OBJ_obj2nid(mdoid);
386280304Sjkim    /* Look for digest type to match signature */
387280304Sjkim    for (;;) {
388280304Sjkim        EVP_MD_CTX *mtmp;
389280304Sjkim        chain = BIO_find_type(chain, BIO_TYPE_MD);
390280304Sjkim        if (chain == NULL) {
391280304Sjkim            CMSerr(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX,
392280304Sjkim                   CMS_R_NO_MATCHING_DIGEST);
393280304Sjkim            return 0;
394280304Sjkim        }
395280304Sjkim        BIO_get_md_ctx(chain, &mtmp);
396280304Sjkim        if (EVP_MD_CTX_type(mtmp) == nid
397280304Sjkim            /*
398280304Sjkim             * Workaround for broken implementations that use signature
399280304Sjkim             * algorithm OID instead of digest.
400280304Sjkim             */
401280304Sjkim            || EVP_MD_pkey_type(EVP_MD_CTX_md(mtmp)) == nid)
402280304Sjkim            return EVP_MD_CTX_copy_ex(mctx, mtmp);
403280304Sjkim        chain = BIO_next(chain);
404280304Sjkim    }
405280304Sjkim}
406183234Ssimon
407280304Sjkimstatic STACK_OF(CMS_CertificateChoices)
408280304Sjkim**cms_get0_certificate_choices(CMS_ContentInfo *cms)
409280304Sjkim{
410280304Sjkim    switch (OBJ_obj2nid(cms->contentType)) {
411183234Ssimon
412280304Sjkim    case NID_pkcs7_signed:
413280304Sjkim        return &cms->d.signedData->certificates;
414183234Ssimon
415280304Sjkim    case NID_pkcs7_enveloped:
416280304Sjkim        return &cms->d.envelopedData->originatorInfo->certificates;
417183234Ssimon
418280304Sjkim    default:
419280304Sjkim        CMSerr(CMS_F_CMS_GET0_CERTIFICATE_CHOICES,
420280304Sjkim               CMS_R_UNSUPPORTED_CONTENT_TYPE);
421280304Sjkim        return NULL;
422183234Ssimon
423280304Sjkim    }
424280304Sjkim}
425183234Ssimon
426183234SsimonCMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms)
427280304Sjkim{
428280304Sjkim    STACK_OF(CMS_CertificateChoices) **pcerts;
429280304Sjkim    CMS_CertificateChoices *cch;
430280304Sjkim    pcerts = cms_get0_certificate_choices(cms);
431280304Sjkim    if (!pcerts)
432280304Sjkim        return NULL;
433280304Sjkim    if (!*pcerts)
434280304Sjkim        *pcerts = sk_CMS_CertificateChoices_new_null();
435280304Sjkim    if (!*pcerts)
436280304Sjkim        return NULL;
437280304Sjkim    cch = M_ASN1_new_of(CMS_CertificateChoices);
438280304Sjkim    if (!cch)
439280304Sjkim        return NULL;
440280304Sjkim    if (!sk_CMS_CertificateChoices_push(*pcerts, cch)) {
441280304Sjkim        M_ASN1_free_of(cch, CMS_CertificateChoices);
442280304Sjkim        return NULL;
443280304Sjkim    }
444280304Sjkim    return cch;
445280304Sjkim}
446183234Ssimon
447183234Ssimonint CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
448280304Sjkim{
449280304Sjkim    CMS_CertificateChoices *cch;
450280304Sjkim    STACK_OF(CMS_CertificateChoices) **pcerts;
451280304Sjkim    int i;
452280304Sjkim    pcerts = cms_get0_certificate_choices(cms);
453280304Sjkim    if (!pcerts)
454280304Sjkim        return 0;
455280304Sjkim    for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
456280304Sjkim        cch = sk_CMS_CertificateChoices_value(*pcerts, i);
457280304Sjkim        if (cch->type == CMS_CERTCHOICE_CERT) {
458280304Sjkim            if (!X509_cmp(cch->d.certificate, cert)) {
459280304Sjkim                CMSerr(CMS_F_CMS_ADD0_CERT,
460280304Sjkim                       CMS_R_CERTIFICATE_ALREADY_PRESENT);
461280304Sjkim                return 0;
462280304Sjkim            }
463280304Sjkim        }
464280304Sjkim    }
465280304Sjkim    cch = CMS_add0_CertificateChoices(cms);
466280304Sjkim    if (!cch)
467280304Sjkim        return 0;
468280304Sjkim    cch->type = CMS_CERTCHOICE_CERT;
469280304Sjkim    cch->d.certificate = cert;
470280304Sjkim    return 1;
471280304Sjkim}
472183234Ssimon
473183234Ssimonint CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
474280304Sjkim{
475280304Sjkim    int r;
476280304Sjkim    r = CMS_add0_cert(cms, cert);
477280304Sjkim    if (r > 0)
478280304Sjkim        CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
479280304Sjkim    return r;
480280304Sjkim}
481183234Ssimon
482280304Sjkimstatic STACK_OF(CMS_RevocationInfoChoice)
483280304Sjkim**cms_get0_revocation_choices(CMS_ContentInfo *cms)
484280304Sjkim{
485280304Sjkim    switch (OBJ_obj2nid(cms->contentType)) {
486183234Ssimon
487280304Sjkim    case NID_pkcs7_signed:
488280304Sjkim        return &cms->d.signedData->crls;
489183234Ssimon
490280304Sjkim    case NID_pkcs7_enveloped:
491280304Sjkim        return &cms->d.envelopedData->originatorInfo->crls;
492183234Ssimon
493280304Sjkim    default:
494280304Sjkim        CMSerr(CMS_F_CMS_GET0_REVOCATION_CHOICES,
495280304Sjkim               CMS_R_UNSUPPORTED_CONTENT_TYPE);
496280304Sjkim        return NULL;
497183234Ssimon
498280304Sjkim    }
499280304Sjkim}
500183234Ssimon
501183234SsimonCMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)
502280304Sjkim{
503280304Sjkim    STACK_OF(CMS_RevocationInfoChoice) **pcrls;
504280304Sjkim    CMS_RevocationInfoChoice *rch;
505280304Sjkim    pcrls = cms_get0_revocation_choices(cms);
506280304Sjkim    if (!pcrls)
507280304Sjkim        return NULL;
508280304Sjkim    if (!*pcrls)
509280304Sjkim        *pcrls = sk_CMS_RevocationInfoChoice_new_null();
510280304Sjkim    if (!*pcrls)
511280304Sjkim        return NULL;
512280304Sjkim    rch = M_ASN1_new_of(CMS_RevocationInfoChoice);
513280304Sjkim    if (!rch)
514280304Sjkim        return NULL;
515280304Sjkim    if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch)) {
516280304Sjkim        M_ASN1_free_of(rch, CMS_RevocationInfoChoice);
517280304Sjkim        return NULL;
518280304Sjkim    }
519280304Sjkim    return rch;
520280304Sjkim}
521183234Ssimon
522183234Ssimonint CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
523280304Sjkim{
524280304Sjkim    CMS_RevocationInfoChoice *rch;
525280304Sjkim    rch = CMS_add0_RevocationInfoChoice(cms);
526280304Sjkim    if (!rch)
527280304Sjkim        return 0;
528280304Sjkim    rch->type = CMS_REVCHOICE_CRL;
529280304Sjkim    rch->d.crl = crl;
530280304Sjkim    return 1;
531280304Sjkim}
532183234Ssimon
533238405Sjkimint CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl)
534280304Sjkim{
535280304Sjkim    int r;
536280304Sjkim    r = CMS_add0_crl(cms, crl);
537280304Sjkim    if (r > 0)
538280304Sjkim        CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
539280304Sjkim    return r;
540280304Sjkim}
541238405Sjkim
542183234SsimonSTACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms)
543280304Sjkim{
544280304Sjkim    STACK_OF(X509) *certs = NULL;
545280304Sjkim    CMS_CertificateChoices *cch;
546280304Sjkim    STACK_OF(CMS_CertificateChoices) **pcerts;
547280304Sjkim    int i;
548280304Sjkim    pcerts = cms_get0_certificate_choices(cms);
549280304Sjkim    if (!pcerts)
550280304Sjkim        return NULL;
551280304Sjkim    for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
552280304Sjkim        cch = sk_CMS_CertificateChoices_value(*pcerts, i);
553280304Sjkim        if (cch->type == 0) {
554280304Sjkim            if (!certs) {
555280304Sjkim                certs = sk_X509_new_null();
556280304Sjkim                if (!certs)
557280304Sjkim                    return NULL;
558280304Sjkim            }
559280304Sjkim            if (!sk_X509_push(certs, cch->d.certificate)) {
560280304Sjkim                sk_X509_pop_free(certs, X509_free);
561280304Sjkim                return NULL;
562280304Sjkim            }
563280304Sjkim            CRYPTO_add(&cch->d.certificate->references, 1, CRYPTO_LOCK_X509);
564280304Sjkim        }
565280304Sjkim    }
566280304Sjkim    return certs;
567183234Ssimon
568280304Sjkim}
569183234Ssimon
570183234SsimonSTACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms)
571280304Sjkim{
572280304Sjkim    STACK_OF(X509_CRL) *crls = NULL;
573280304Sjkim    STACK_OF(CMS_RevocationInfoChoice) **pcrls;
574280304Sjkim    CMS_RevocationInfoChoice *rch;
575280304Sjkim    int i;
576280304Sjkim    pcrls = cms_get0_revocation_choices(cms);
577280304Sjkim    if (!pcrls)
578280304Sjkim        return NULL;
579280304Sjkim    for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++) {
580280304Sjkim        rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
581280304Sjkim        if (rch->type == 0) {
582280304Sjkim            if (!crls) {
583280304Sjkim                crls = sk_X509_CRL_new_null();
584280304Sjkim                if (!crls)
585280304Sjkim                    return NULL;
586280304Sjkim            }
587280304Sjkim            if (!sk_X509_CRL_push(crls, rch->d.crl)) {
588280304Sjkim                sk_X509_CRL_pop_free(crls, X509_CRL_free);
589280304Sjkim                return NULL;
590280304Sjkim            }
591280304Sjkim            CRYPTO_add(&rch->d.crl->references, 1, CRYPTO_LOCK_X509_CRL);
592280304Sjkim        }
593280304Sjkim    }
594280304Sjkim    return crls;
595280304Sjkim}
596