1183234Ssimon/* crypto/cms/cms_lib.c */
2183234Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3183234Ssimon * project.
4183234Ssimon */
5183234Ssimon/* ====================================================================
6183234Ssimon * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
7183234Ssimon *
8183234Ssimon * Redistribution and use in source and binary forms, with or without
9183234Ssimon * modification, are permitted provided that the following conditions
10183234Ssimon * are met:
11183234Ssimon *
12183234Ssimon * 1. Redistributions of source code must retain the above copyright
13183234Ssimon *    notice, this list of conditions and the following disclaimer.
14183234Ssimon *
15183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright
16183234Ssimon *    notice, this list of conditions and the following disclaimer in
17183234Ssimon *    the documentation and/or other materials provided with the
18183234Ssimon *    distribution.
19183234Ssimon *
20183234Ssimon * 3. All advertising materials mentioning features or use of this
21183234Ssimon *    software must display the following acknowledgment:
22183234Ssimon *    "This product includes software developed by the OpenSSL Project
23183234Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24183234Ssimon *
25183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26183234Ssimon *    endorse or promote products derived from this software without
27183234Ssimon *    prior written permission. For written permission, please contact
28183234Ssimon *    licensing@OpenSSL.org.
29183234Ssimon *
30183234Ssimon * 5. Products derived from this software may not be called "OpenSSL"
31183234Ssimon *    nor may "OpenSSL" appear in their names without prior written
32183234Ssimon *    permission of the OpenSSL Project.
33183234Ssimon *
34183234Ssimon * 6. Redistributions of any form whatsoever must retain the following
35183234Ssimon *    acknowledgment:
36183234Ssimon *    "This product includes software developed by the OpenSSL Project
37183234Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38183234Ssimon *
39183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42183234Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
51183234Ssimon * ====================================================================
52183234Ssimon */
53183234Ssimon
54183234Ssimon#include <openssl/asn1t.h>
55183234Ssimon#include <openssl/x509.h>
56183234Ssimon#include <openssl/err.h>
57183234Ssimon#include <openssl/pem.h>
58183234Ssimon#include <openssl/bio.h>
59183234Ssimon#include <openssl/asn1.h>
60183234Ssimon#include "cms.h"
61183234Ssimon#include "cms_lcl.h"
62183234Ssimon
63238405SjkimIMPLEMENT_ASN1_FUNCTIONS(CMS_ContentInfo)
64238405SjkimIMPLEMENT_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
65183234Ssimon
66183234SsimonDECLARE_ASN1_ITEM(CMS_CertificateChoices)
67183234SsimonDECLARE_ASN1_ITEM(CMS_RevocationInfoChoice)
68183234SsimonDECLARE_STACK_OF(CMS_CertificateChoices)
69183234SsimonDECLARE_STACK_OF(CMS_RevocationInfoChoice)
70183234Ssimon
71183234Ssimonconst ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms)
72183234Ssimon	{
73183234Ssimon	return cms->contentType;
74183234Ssimon	}
75183234Ssimon
76183234SsimonCMS_ContentInfo *cms_Data_create(void)
77183234Ssimon	{
78183234Ssimon	CMS_ContentInfo *cms;
79183234Ssimon	cms = CMS_ContentInfo_new();
80183234Ssimon	if (cms)
81183234Ssimon		{
82183234Ssimon		cms->contentType = OBJ_nid2obj(NID_pkcs7_data);
83183234Ssimon		/* Never detached */
84183234Ssimon		CMS_set_detached(cms, 0);
85183234Ssimon		}
86183234Ssimon	return cms;
87183234Ssimon	}
88183234Ssimon
89183234SsimonBIO *cms_content_bio(CMS_ContentInfo *cms)
90183234Ssimon	{
91183234Ssimon	ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
92183234Ssimon	if (!pos)
93183234Ssimon		return NULL;
94183234Ssimon	/* If content detached data goes nowhere: create NULL BIO */
95183234Ssimon	if (!*pos)
96183234Ssimon		return BIO_new(BIO_s_null());
97183234Ssimon	/* If content not detached and created return memory BIO
98183234Ssimon	 */
99183234Ssimon	if (!*pos || ((*pos)->flags == ASN1_STRING_FLAG_CONT))
100183234Ssimon		return BIO_new(BIO_s_mem());
101183234Ssimon	/* Else content was read in: return read only BIO for it */
102183234Ssimon	return BIO_new_mem_buf((*pos)->data, (*pos)->length);
103183234Ssimon	}
104183234Ssimon
105183234SsimonBIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont)
106183234Ssimon	{
107183234Ssimon	BIO *cmsbio, *cont;
108183234Ssimon	if (icont)
109183234Ssimon		cont = icont;
110183234Ssimon	else
111183234Ssimon		cont = cms_content_bio(cms);
112183234Ssimon	if (!cont)
113183234Ssimon		{
114183234Ssimon		CMSerr(CMS_F_CMS_DATAINIT, CMS_R_NO_CONTENT);
115183234Ssimon		return NULL;
116183234Ssimon		}
117183234Ssimon	switch (OBJ_obj2nid(cms->contentType))
118183234Ssimon		{
119183234Ssimon
120183234Ssimon		case NID_pkcs7_data:
121183234Ssimon		return cont;
122183234Ssimon
123183234Ssimon		case NID_pkcs7_signed:
124183234Ssimon		cmsbio = cms_SignedData_init_bio(cms);
125183234Ssimon		break;
126183234Ssimon
127183234Ssimon		case NID_pkcs7_digest:
128183234Ssimon		cmsbio = cms_DigestedData_init_bio(cms);
129183234Ssimon		break;
130183234Ssimon#ifdef ZLIB
131183234Ssimon		case NID_id_smime_ct_compressedData:
132183234Ssimon		cmsbio = cms_CompressedData_init_bio(cms);
133183234Ssimon		break;
134183234Ssimon#endif
135183234Ssimon
136183234Ssimon		case NID_pkcs7_encrypted:
137183234Ssimon		cmsbio = cms_EncryptedData_init_bio(cms);
138183234Ssimon		break;
139183234Ssimon
140183234Ssimon		case NID_pkcs7_enveloped:
141183234Ssimon		cmsbio = cms_EnvelopedData_init_bio(cms);
142183234Ssimon		break;
143183234Ssimon
144183234Ssimon		default:
145183234Ssimon		CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE);
146183234Ssimon		return NULL;
147183234Ssimon		}
148183234Ssimon
149183234Ssimon	if (cmsbio)
150183234Ssimon		return BIO_push(cmsbio, cont);
151183234Ssimon
152183234Ssimon	if (!icont)
153183234Ssimon		BIO_free(cont);
154183234Ssimon	return NULL;
155183234Ssimon
156183234Ssimon	}
157183234Ssimon
158183234Ssimonint CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
159183234Ssimon	{
160183234Ssimon	ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
161183234Ssimon	if (!pos)
162183234Ssimon		return 0;
163183234Ssimon	/* If ebmedded content find memory BIO and set content */
164183234Ssimon	if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT))
165183234Ssimon		{
166183234Ssimon		BIO *mbio;
167183234Ssimon		unsigned char *cont;
168183234Ssimon		long contlen;
169183234Ssimon		mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM);
170183234Ssimon		if (!mbio)
171183234Ssimon			{
172183234Ssimon			CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_CONTENT_NOT_FOUND);
173183234Ssimon			return 0;
174183234Ssimon			}
175183234Ssimon		contlen = BIO_get_mem_data(mbio, &cont);
176183234Ssimon		/* Set bio as read only so its content can't be clobbered */
177183234Ssimon		BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY);
178183234Ssimon		BIO_set_mem_eof_return(mbio, 0);
179183234Ssimon		ASN1_STRING_set0(*pos, cont, contlen);
180183234Ssimon		(*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
181183234Ssimon		}
182183234Ssimon
183183234Ssimon	switch (OBJ_obj2nid(cms->contentType))
184183234Ssimon		{
185183234Ssimon
186183234Ssimon		case NID_pkcs7_data:
187183234Ssimon		case NID_pkcs7_enveloped:
188183234Ssimon		case NID_pkcs7_encrypted:
189183234Ssimon		case NID_id_smime_ct_compressedData:
190183234Ssimon		/* Nothing to do */
191183234Ssimon		return 1;
192183234Ssimon
193183234Ssimon		case NID_pkcs7_signed:
194183234Ssimon		return cms_SignedData_final(cms, cmsbio);
195183234Ssimon
196183234Ssimon		case NID_pkcs7_digest:
197183234Ssimon		return cms_DigestedData_do_final(cms, cmsbio, 0);
198183234Ssimon
199183234Ssimon		default:
200183234Ssimon		CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_UNSUPPORTED_TYPE);
201183234Ssimon		return 0;
202183234Ssimon		}
203183234Ssimon	}
204183234Ssimon
205183234Ssimon/* Return an OCTET STRING pointer to content. This allows it to
206183234Ssimon * be accessed or set later.
207183234Ssimon */
208183234Ssimon
209183234SsimonASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms)
210183234Ssimon	{
211183234Ssimon	switch (OBJ_obj2nid(cms->contentType))
212183234Ssimon		{
213183234Ssimon
214183234Ssimon		case NID_pkcs7_data:
215183234Ssimon		return &cms->d.data;
216183234Ssimon
217183234Ssimon		case NID_pkcs7_signed:
218183234Ssimon		return &cms->d.signedData->encapContentInfo->eContent;
219183234Ssimon
220183234Ssimon		case NID_pkcs7_enveloped:
221183234Ssimon		return &cms->d.envelopedData->encryptedContentInfo->encryptedContent;
222183234Ssimon
223183234Ssimon		case NID_pkcs7_digest:
224183234Ssimon		return &cms->d.digestedData->encapContentInfo->eContent;
225183234Ssimon
226183234Ssimon		case NID_pkcs7_encrypted:
227183234Ssimon		return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
228183234Ssimon
229183234Ssimon		case NID_id_smime_ct_authData:
230183234Ssimon		return &cms->d.authenticatedData->encapContentInfo->eContent;
231183234Ssimon
232183234Ssimon		case NID_id_smime_ct_compressedData:
233183234Ssimon		return &cms->d.compressedData->encapContentInfo->eContent;
234183234Ssimon
235183234Ssimon		default:
236183234Ssimon		if (cms->d.other->type == V_ASN1_OCTET_STRING)
237183234Ssimon			return &cms->d.other->value.octet_string;
238183234Ssimon		CMSerr(CMS_F_CMS_GET0_CONTENT, CMS_R_UNSUPPORTED_CONTENT_TYPE);
239183234Ssimon		return NULL;
240183234Ssimon
241183234Ssimon		}
242183234Ssimon	}
243183234Ssimon
244183234Ssimon/* Return an ASN1_OBJECT pointer to content type. This allows it to
245183234Ssimon * be accessed or set later.
246183234Ssimon */
247183234Ssimon
248183234Ssimonstatic ASN1_OBJECT **cms_get0_econtent_type(CMS_ContentInfo *cms)
249183234Ssimon	{
250183234Ssimon	switch (OBJ_obj2nid(cms->contentType))
251183234Ssimon		{
252183234Ssimon
253183234Ssimon		case NID_pkcs7_signed:
254183234Ssimon		return &cms->d.signedData->encapContentInfo->eContentType;
255183234Ssimon
256183234Ssimon		case NID_pkcs7_enveloped:
257183234Ssimon		return &cms->d.envelopedData->encryptedContentInfo->contentType;
258183234Ssimon
259183234Ssimon		case NID_pkcs7_digest:
260183234Ssimon		return &cms->d.digestedData->encapContentInfo->eContentType;
261183234Ssimon
262183234Ssimon		case NID_pkcs7_encrypted:
263183234Ssimon		return &cms->d.encryptedData->encryptedContentInfo->contentType;
264183234Ssimon
265183234Ssimon		case NID_id_smime_ct_authData:
266183234Ssimon		return &cms->d.authenticatedData->encapContentInfo->eContentType;
267183234Ssimon
268183234Ssimon		case NID_id_smime_ct_compressedData:
269183234Ssimon		return &cms->d.compressedData->encapContentInfo->eContentType;
270183234Ssimon
271183234Ssimon		default:
272183234Ssimon		CMSerr(CMS_F_CMS_GET0_ECONTENT_TYPE,
273183234Ssimon					CMS_R_UNSUPPORTED_CONTENT_TYPE);
274183234Ssimon		return NULL;
275183234Ssimon
276183234Ssimon		}
277183234Ssimon	}
278183234Ssimon
279183234Ssimonconst ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms)
280183234Ssimon	{
281183234Ssimon	ASN1_OBJECT **petype;
282183234Ssimon	petype = cms_get0_econtent_type(cms);
283183234Ssimon	if (petype)
284183234Ssimon		return *petype;
285183234Ssimon	return NULL;
286183234Ssimon	}
287183234Ssimon
288183234Ssimonint CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid)
289183234Ssimon	{
290183234Ssimon	ASN1_OBJECT **petype, *etype;
291183234Ssimon	petype = cms_get0_econtent_type(cms);
292183234Ssimon	if (!petype)
293183234Ssimon		return 0;
294183234Ssimon	if (!oid)
295183234Ssimon		return 1;
296183234Ssimon	etype = OBJ_dup(oid);
297183234Ssimon	if (!etype)
298183234Ssimon		return 0;
299183234Ssimon	ASN1_OBJECT_free(*petype);
300183234Ssimon	*petype = etype;
301183234Ssimon	return 1;
302183234Ssimon	}
303183234Ssimon
304183234Ssimonint CMS_is_detached(CMS_ContentInfo *cms)
305183234Ssimon	{
306183234Ssimon	ASN1_OCTET_STRING **pos;
307183234Ssimon	pos = CMS_get0_content(cms);
308183234Ssimon	if (!pos)
309183234Ssimon		return -1;
310183234Ssimon	if (*pos)
311183234Ssimon		return 0;
312183234Ssimon	return 1;
313183234Ssimon	}
314183234Ssimon
315183234Ssimonint CMS_set_detached(CMS_ContentInfo *cms, int detached)
316183234Ssimon	{
317183234Ssimon	ASN1_OCTET_STRING **pos;
318183234Ssimon	pos = CMS_get0_content(cms);
319183234Ssimon	if (!pos)
320183234Ssimon		return 0;
321183234Ssimon	if (detached)
322183234Ssimon		{
323183234Ssimon		if (*pos)
324183234Ssimon			{
325183234Ssimon			ASN1_OCTET_STRING_free(*pos);
326183234Ssimon			*pos = NULL;
327183234Ssimon			}
328183234Ssimon		return 1;
329183234Ssimon		}
330183234Ssimon	if (!*pos)
331183234Ssimon		*pos = ASN1_OCTET_STRING_new();
332183234Ssimon	if (*pos)
333183234Ssimon		{
334183234Ssimon		/* NB: special flag to show content is created and not
335183234Ssimon		 * read in.
336183234Ssimon		 */
337183234Ssimon		(*pos)->flags |= ASN1_STRING_FLAG_CONT;
338183234Ssimon		return 1;
339183234Ssimon		}
340183234Ssimon	CMSerr(CMS_F_CMS_SET_DETACHED, ERR_R_MALLOC_FAILURE);
341183234Ssimon	return 0;
342183234Ssimon	}
343183234Ssimon
344183234Ssimon/* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */
345183234Ssimon
346183234Ssimonvoid cms_DigestAlgorithm_set(X509_ALGOR *alg, const EVP_MD *md)
347183234Ssimon	{
348183234Ssimon	int param_type;
349183234Ssimon
350238405Sjkim	if (md->flags & EVP_MD_FLAG_DIGALGID_ABSENT)
351183234Ssimon		param_type = V_ASN1_UNDEF;
352238405Sjkim	else
353183234Ssimon		param_type = V_ASN1_NULL;
354183234Ssimon
355183234Ssimon	X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL);
356183234Ssimon
357183234Ssimon	}
358183234Ssimon
359183234Ssimon/* Create a digest BIO from an X509_ALGOR structure */
360183234Ssimon
361183234SsimonBIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
362183234Ssimon	{
363183234Ssimon	BIO *mdbio = NULL;
364183234Ssimon	ASN1_OBJECT *digestoid;
365183234Ssimon	const EVP_MD *digest;
366183234Ssimon	X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
367183234Ssimon	digest = EVP_get_digestbyobj(digestoid);
368183234Ssimon	if (!digest)
369183234Ssimon		{
370183234Ssimon		CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
371183234Ssimon				CMS_R_UNKNOWN_DIGEST_ALGORIHM);
372183234Ssimon		goto err;
373183234Ssimon		}
374183234Ssimon	mdbio = BIO_new(BIO_f_md());
375183234Ssimon	if (!mdbio || !BIO_set_md(mdbio, digest))
376183234Ssimon		{
377183234Ssimon		CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
378183234Ssimon				CMS_R_MD_BIO_INIT_ERROR);
379183234Ssimon		goto err;
380183234Ssimon		}
381183234Ssimon	return mdbio;
382183234Ssimon	err:
383183234Ssimon	if (mdbio)
384183234Ssimon		BIO_free(mdbio);
385183234Ssimon	return NULL;
386183234Ssimon	}
387183234Ssimon
388183234Ssimon/* Locate a message digest content from a BIO chain based on SignerInfo */
389183234Ssimon
390183234Ssimonint cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
391183234Ssimon					X509_ALGOR *mdalg)
392183234Ssimon	{
393183234Ssimon	int nid;
394183234Ssimon	ASN1_OBJECT *mdoid;
395183234Ssimon	X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
396183234Ssimon	nid = OBJ_obj2nid(mdoid);
397183234Ssimon	/* Look for digest type to match signature */
398183234Ssimon	for (;;)
399183234Ssimon		{
400183234Ssimon		EVP_MD_CTX *mtmp;
401183234Ssimon		chain = BIO_find_type(chain, BIO_TYPE_MD);
402183234Ssimon		if (chain == NULL)
403183234Ssimon			{
404183234Ssimon			CMSerr(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX,
405183234Ssimon						CMS_R_NO_MATCHING_DIGEST);
406183234Ssimon			return 0;
407183234Ssimon			}
408183234Ssimon		BIO_get_md_ctx(chain, &mtmp);
409205128Ssimon		if (EVP_MD_CTX_type(mtmp) == nid
410205128Ssimon		/* Workaround for broken implementations that use signature
411205128Ssimon		 * algorithm  OID instead of digest.
412205128Ssimon		 */
413205128Ssimon			|| EVP_MD_pkey_type(EVP_MD_CTX_md(mtmp)) == nid)
414238405Sjkim			return EVP_MD_CTX_copy_ex(mctx, mtmp);
415183234Ssimon		chain = BIO_next(chain);
416183234Ssimon		}
417183234Ssimon	}
418183234Ssimon
419183234Ssimonstatic STACK_OF(CMS_CertificateChoices) **cms_get0_certificate_choices(CMS_ContentInfo *cms)
420183234Ssimon	{
421183234Ssimon	switch (OBJ_obj2nid(cms->contentType))
422183234Ssimon		{
423183234Ssimon
424183234Ssimon		case NID_pkcs7_signed:
425183234Ssimon		return &cms->d.signedData->certificates;
426183234Ssimon
427183234Ssimon		case NID_pkcs7_enveloped:
428183234Ssimon		return &cms->d.envelopedData->originatorInfo->certificates;
429183234Ssimon
430183234Ssimon		default:
431183234Ssimon		CMSerr(CMS_F_CMS_GET0_CERTIFICATE_CHOICES,
432183234Ssimon					CMS_R_UNSUPPORTED_CONTENT_TYPE);
433183234Ssimon		return NULL;
434183234Ssimon
435183234Ssimon		}
436183234Ssimon	}
437183234Ssimon
438183234SsimonCMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms)
439183234Ssimon	{
440183234Ssimon	STACK_OF(CMS_CertificateChoices) **pcerts;
441183234Ssimon	CMS_CertificateChoices *cch;
442183234Ssimon	pcerts = cms_get0_certificate_choices(cms);
443183234Ssimon	if (!pcerts)
444183234Ssimon		return NULL;
445183234Ssimon	if (!*pcerts)
446183234Ssimon		*pcerts = sk_CMS_CertificateChoices_new_null();
447183234Ssimon	if (!*pcerts)
448183234Ssimon		return NULL;
449183234Ssimon	cch = M_ASN1_new_of(CMS_CertificateChoices);
450183234Ssimon	if (!cch)
451183234Ssimon		return NULL;
452183234Ssimon	if (!sk_CMS_CertificateChoices_push(*pcerts, cch))
453183234Ssimon		{
454183234Ssimon		M_ASN1_free_of(cch, CMS_CertificateChoices);
455183234Ssimon		return NULL;
456183234Ssimon		}
457183234Ssimon	return cch;
458183234Ssimon	}
459183234Ssimon
460183234Ssimonint CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
461183234Ssimon	{
462183234Ssimon	CMS_CertificateChoices *cch;
463183234Ssimon	STACK_OF(CMS_CertificateChoices) **pcerts;
464183234Ssimon	int i;
465183234Ssimon	pcerts = cms_get0_certificate_choices(cms);
466183234Ssimon	if (!pcerts)
467183234Ssimon		return 0;
468183234Ssimon	for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++)
469183234Ssimon		{
470183234Ssimon		cch = sk_CMS_CertificateChoices_value(*pcerts, i);
471183234Ssimon		if (cch->type == CMS_CERTCHOICE_CERT)
472183234Ssimon			{
473183234Ssimon			if (!X509_cmp(cch->d.certificate, cert))
474183234Ssimon				{
475183234Ssimon				CMSerr(CMS_F_CMS_ADD0_CERT,
476183234Ssimon					CMS_R_CERTIFICATE_ALREADY_PRESENT);
477183234Ssimon				return 0;
478183234Ssimon				}
479183234Ssimon			}
480183234Ssimon		}
481183234Ssimon	cch = CMS_add0_CertificateChoices(cms);
482183234Ssimon	if (!cch)
483183234Ssimon		return 0;
484183234Ssimon	cch->type = CMS_CERTCHOICE_CERT;
485183234Ssimon	cch->d.certificate = cert;
486183234Ssimon	return 1;
487183234Ssimon	}
488183234Ssimon
489183234Ssimonint CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
490183234Ssimon	{
491183234Ssimon	int r;
492183234Ssimon	r = CMS_add0_cert(cms, cert);
493183234Ssimon	if (r > 0)
494183234Ssimon		CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
495183234Ssimon	return r;
496183234Ssimon	}
497183234Ssimon
498183234Ssimonstatic STACK_OF(CMS_RevocationInfoChoice) **cms_get0_revocation_choices(CMS_ContentInfo *cms)
499183234Ssimon	{
500183234Ssimon	switch (OBJ_obj2nid(cms->contentType))
501183234Ssimon		{
502183234Ssimon
503183234Ssimon		case NID_pkcs7_signed:
504183234Ssimon		return &cms->d.signedData->crls;
505183234Ssimon
506183234Ssimon		case NID_pkcs7_enveloped:
507183234Ssimon		return &cms->d.envelopedData->originatorInfo->crls;
508183234Ssimon
509183234Ssimon		default:
510183234Ssimon		CMSerr(CMS_F_CMS_GET0_REVOCATION_CHOICES,
511183234Ssimon					CMS_R_UNSUPPORTED_CONTENT_TYPE);
512183234Ssimon		return NULL;
513183234Ssimon
514183234Ssimon		}
515183234Ssimon	}
516183234Ssimon
517183234SsimonCMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)
518183234Ssimon	{
519183234Ssimon	STACK_OF(CMS_RevocationInfoChoice) **pcrls;
520183234Ssimon	CMS_RevocationInfoChoice *rch;
521183234Ssimon	pcrls = cms_get0_revocation_choices(cms);
522183234Ssimon	if (!pcrls)
523183234Ssimon		return NULL;
524183234Ssimon	if (!*pcrls)
525183234Ssimon		*pcrls = sk_CMS_RevocationInfoChoice_new_null();
526183234Ssimon	if (!*pcrls)
527183234Ssimon		return NULL;
528183234Ssimon	rch = M_ASN1_new_of(CMS_RevocationInfoChoice);
529183234Ssimon	if (!rch)
530183234Ssimon		return NULL;
531183234Ssimon	if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch))
532183234Ssimon		{
533183234Ssimon		M_ASN1_free_of(rch, CMS_RevocationInfoChoice);
534183234Ssimon		return NULL;
535183234Ssimon		}
536183234Ssimon	return rch;
537183234Ssimon	}
538183234Ssimon
539183234Ssimonint CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
540183234Ssimon	{
541183234Ssimon	CMS_RevocationInfoChoice *rch;
542183234Ssimon	rch = CMS_add0_RevocationInfoChoice(cms);
543183234Ssimon	if (!rch)
544183234Ssimon		return 0;
545183234Ssimon	rch->type = CMS_REVCHOICE_CRL;
546183234Ssimon	rch->d.crl = crl;
547183234Ssimon	return 1;
548183234Ssimon	}
549183234Ssimon
550238405Sjkimint CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl)
551238405Sjkim	{
552238405Sjkim	int r;
553238405Sjkim	r = CMS_add0_crl(cms, crl);
554238405Sjkim	if (r > 0)
555238405Sjkim		CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
556238405Sjkim	return r;
557238405Sjkim	}
558238405Sjkim
559183234SsimonSTACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms)
560183234Ssimon	{
561183234Ssimon	STACK_OF(X509) *certs = NULL;
562183234Ssimon	CMS_CertificateChoices *cch;
563183234Ssimon	STACK_OF(CMS_CertificateChoices) **pcerts;
564183234Ssimon	int i;
565183234Ssimon	pcerts = cms_get0_certificate_choices(cms);
566183234Ssimon	if (!pcerts)
567183234Ssimon		return NULL;
568183234Ssimon	for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++)
569183234Ssimon		{
570183234Ssimon		cch = sk_CMS_CertificateChoices_value(*pcerts, i);
571183234Ssimon		if (cch->type == 0)
572183234Ssimon			{
573183234Ssimon			if (!certs)
574183234Ssimon				{
575183234Ssimon				certs = sk_X509_new_null();
576183234Ssimon				if (!certs)
577183234Ssimon					return NULL;
578183234Ssimon				}
579183234Ssimon			if (!sk_X509_push(certs, cch->d.certificate))
580183234Ssimon				{
581183234Ssimon				sk_X509_pop_free(certs, X509_free);
582183234Ssimon				return NULL;
583183234Ssimon				}
584183234Ssimon			CRYPTO_add(&cch->d.certificate->references,
585183234Ssimon						1, CRYPTO_LOCK_X509);
586183234Ssimon			}
587183234Ssimon		}
588183234Ssimon	return certs;
589183234Ssimon
590183234Ssimon	}
591183234Ssimon
592183234SsimonSTACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms)
593183234Ssimon	{
594183234Ssimon	STACK_OF(X509_CRL) *crls = NULL;
595183234Ssimon	STACK_OF(CMS_RevocationInfoChoice) **pcrls;
596183234Ssimon	CMS_RevocationInfoChoice *rch;
597183234Ssimon	int i;
598183234Ssimon	pcrls = cms_get0_revocation_choices(cms);
599183234Ssimon	if (!pcrls)
600183234Ssimon		return NULL;
601183234Ssimon	for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++)
602183234Ssimon		{
603183234Ssimon		rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
604183234Ssimon		if (rch->type == 0)
605183234Ssimon			{
606183234Ssimon			if (!crls)
607183234Ssimon				{
608183234Ssimon				crls = sk_X509_CRL_new_null();
609183234Ssimon				if (!crls)
610183234Ssimon					return NULL;
611183234Ssimon				}
612183234Ssimon			if (!sk_X509_CRL_push(crls, rch->d.crl))
613183234Ssimon				{
614183234Ssimon				sk_X509_CRL_pop_free(crls, X509_CRL_free);
615183234Ssimon				return NULL;
616183234Ssimon				}
617183234Ssimon			CRYPTO_add(&rch->d.crl->references,
618183234Ssimon						1, CRYPTO_LOCK_X509_CRL);
619183234Ssimon			}
620183234Ssimon		}
621183234Ssimon	return crls;
622183234Ssimon	}
623