1272343Sngie/* $OpenBSD: cms_lib.c,v 1.25 2024/03/30 01:53:05 joshua Exp $ */
2272343Sngie/*
3272343Sngie * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4272343Sngie * project.
5272343Sngie */
6272343Sngie/* ====================================================================
7272343Sngie * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
8272343Sngie *
9272343Sngie * Redistribution and use in source and binary forms, with or without
10272343Sngie * modification, are permitted provided that the following conditions
11272343Sngie * are met:
12272343Sngie *
13272343Sngie * 1. Redistributions of source code must retain the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer.
15272343Sngie *
16272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
17272343Sngie *    notice, this list of conditions and the following disclaimer in
18272343Sngie *    the documentation and/or other materials provided with the
19272343Sngie *    distribution.
20272343Sngie *
21272343Sngie * 3. All advertising materials mentioning features or use of this
22272343Sngie *    software must display the following acknowledgment:
23272343Sngie *    "This product includes software developed by the OpenSSL Project
24272343Sngie *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25272343Sngie *
26272343Sngie * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27272343Sngie *    endorse or promote products derived from this software without
28272343Sngie *    prior written permission. For written permission, please contact
29272343Sngie *    licensing@OpenSSL.org.
30272343Sngie *
31272343Sngie * 5. Products derived from this software may not be called "OpenSSL"
32272343Sngie *    nor may "OpenSSL" appear in their names without prior written
33272343Sngie *    permission of the OpenSSL Project.
34272343Sngie *
35272343Sngie * 6. Redistributions of any form whatsoever must retain the following
36272343Sngie *    acknowledgment:
37272343Sngie *    "This product includes software developed by the OpenSSL Project
38272343Sngie *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39272343Sngie *
40272343Sngie * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41272343Sngie * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42272343Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43272343Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44272343Sngie * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45272343Sngie * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46272343Sngie * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47272343Sngie * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49272343Sngie * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51272343Sngie * OF THE POSSIBILITY OF SUCH DAMAGE.
52272343Sngie * ====================================================================
53272343Sngie */
54272343Sngie
55272343Sngie#include <openssl/asn1t.h>
56272343Sngie#include <openssl/x509v3.h>
57272343Sngie#include <openssl/err.h>
58272343Sngie#include <openssl/pem.h>
59272343Sngie#include <openssl/bio.h>
60272343Sngie#include <openssl/asn1.h>
61272343Sngie#include <openssl/cms.h>
62272343Sngie
63272343Sngie#include "cms_local.h"
64272343Sngie#include "x509_local.h"
65272343Sngie
66272343SngieCMS_ContentInfo *
67272343Sngied2i_CMS_ContentInfo(CMS_ContentInfo **a, const unsigned char **in, long len)
68272343Sngie{
69272343Sngie	return (CMS_ContentInfo *)ASN1_item_d2i((ASN1_VALUE **)a, in, len,
70272343Sngie	    &CMS_ContentInfo_it);
71272343Sngie}
72272343SngieLCRYPTO_ALIAS(d2i_CMS_ContentInfo);
73272343Sngie
74272343Sngieint
75272343Sngiei2d_CMS_ContentInfo(CMS_ContentInfo *a, unsigned char **out)
76272343Sngie{
77272343Sngie	return ASN1_item_i2d((ASN1_VALUE *)a, out, &CMS_ContentInfo_it);
78272343Sngie}
79272343SngieLCRYPTO_ALIAS(i2d_CMS_ContentInfo);
80272343Sngie
81272343SngieCMS_ContentInfo *
82272343SngieCMS_ContentInfo_new(void)
83272343Sngie{
84272343Sngie	return (CMS_ContentInfo *)ASN1_item_new(&CMS_ContentInfo_it);
85272343Sngie}
86272343SngieLCRYPTO_ALIAS(CMS_ContentInfo_new);
87272343Sngie
88272343Sngievoid
89272343SngieCMS_ContentInfo_free(CMS_ContentInfo *a)
90272343Sngie{
91272343Sngie	ASN1_item_free((ASN1_VALUE *)a, &CMS_ContentInfo_it);
92272343Sngie}
93272343SngieLCRYPTO_ALIAS(CMS_ContentInfo_free);
94272343Sngie
95272343Sngieint
96272343SngieCMS_ContentInfo_print_ctx(BIO *out, CMS_ContentInfo *x, int indent, const ASN1_PCTX *pctx)
97272343Sngie{
98272343Sngie	return ASN1_item_print(out, (ASN1_VALUE *)x, indent,
99272343Sngie	    &CMS_ContentInfo_it, pctx);
100272343Sngie}
101272343SngieLCRYPTO_ALIAS(CMS_ContentInfo_print_ctx);
102272343Sngie
103272343Sngieconst ASN1_OBJECT *
104272343SngieCMS_get0_type(const CMS_ContentInfo *cms)
105272343Sngie{
106272343Sngie	return cms->contentType;
107272343Sngie}
108272343SngieLCRYPTO_ALIAS(CMS_get0_type);
109272343Sngie
110272343SngieCMS_ContentInfo *
111272343Sngiecms_Data_create(void)
112272343Sngie{
113272343Sngie	CMS_ContentInfo *cms;
114272343Sngie
115272343Sngie	cms = CMS_ContentInfo_new();
116272343Sngie	if (cms != NULL) {
117272343Sngie		cms->contentType = OBJ_nid2obj(NID_pkcs7_data);
118272343Sngie		/* Never detached */
119272343Sngie		CMS_set_detached(cms, 0);
120272343Sngie	}
121272343Sngie	return cms;
122272343Sngie}
123272343Sngie
124272343Sngiestatic BIO *
125272343Sngiecms_content_bio(CMS_ContentInfo *cms)
126272343Sngie{
127272343Sngie	ASN1_OCTET_STRING **pos;
128272343Sngie
129272343Sngie	if ((pos = CMS_get0_content(cms)) == NULL)
130272343Sngie		return NULL;
131272343Sngie
132272343Sngie	/* If content is detached, data goes nowhere: create null BIO. */
133272343Sngie	if (*pos == NULL)
134272343Sngie		return BIO_new(BIO_s_null());
135272343Sngie
136272343Sngie	/* If content is not detached and was created, return memory BIO. */
137272343Sngie	if ((*pos)->flags == ASN1_STRING_FLAG_CONT)
138272343Sngie		return BIO_new(BIO_s_mem());
139272343Sngie
140272343Sngie	/* Else content was read in: return read-only BIO for it. */
141272343Sngie	return BIO_new_mem_buf((*pos)->data, (*pos)->length);
142272343Sngie}
143272343Sngie
144272343SngieBIO *
145272343SngieCMS_dataInit(CMS_ContentInfo *cms, BIO *in_content_bio)
146272343Sngie{
147272343Sngie	BIO *cms_bio = NULL, *content_bio = NULL;
148272343Sngie
149272343Sngie	if ((content_bio = in_content_bio) == NULL)
150272343Sngie		content_bio = cms_content_bio(cms);
151272343Sngie	if (content_bio == NULL) {
152272343Sngie		CMSerror(CMS_R_NO_CONTENT);
153272343Sngie		goto err;
154272343Sngie	}
155272343Sngie
156272343Sngie	switch (OBJ_obj2nid(cms->contentType)) {
157272343Sngie	case NID_pkcs7_data:
158272343Sngie		return content_bio;
159272343Sngie	case NID_pkcs7_signed:
160272343Sngie		if ((cms_bio = cms_SignedData_init_bio(cms)) == NULL)
161272343Sngie			goto err;
162272343Sngie		break;
163272343Sngie	case NID_pkcs7_digest:
164272343Sngie		if ((cms_bio = cms_DigestedData_init_bio(cms)) == NULL)
165272343Sngie			goto err;
166272343Sngie		break;
167272343Sngie	case NID_pkcs7_encrypted:
168272343Sngie		if ((cms_bio = cms_EncryptedData_init_bio(cms)) == NULL)
169272343Sngie			goto err;
170272343Sngie		break;
171272343Sngie	case NID_pkcs7_enveloped:
172272343Sngie		if ((cms_bio = cms_EnvelopedData_init_bio(cms)) == NULL)
173272343Sngie			goto err;
174272343Sngie		break;
175272343Sngie	default:
176272343Sngie		CMSerror(CMS_R_UNSUPPORTED_TYPE);
177272343Sngie		goto err;
178272343Sngie	}
179272343Sngie
180272343Sngie	return BIO_push(cms_bio, content_bio);
181272343Sngie
182272343Sngie err:
183272343Sngie	if (content_bio != in_content_bio)
184272343Sngie		BIO_free(content_bio);
185272343Sngie
186272343Sngie	return NULL;
187272343Sngie}
188272343SngieLCRYPTO_ALIAS(CMS_dataInit);
189272343Sngie
190272343Sngieint
191272343SngieCMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
192272343Sngie{
193272343Sngie	ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
194272343Sngie
195272343Sngie	if (!pos)
196272343Sngie		return 0;
197272343Sngie	/* If embedded content find memory BIO and set content */
198272343Sngie	if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT)) {
199272343Sngie		BIO *mbio;
200272343Sngie		unsigned char *cont;
201272343Sngie		long contlen;
202272343Sngie		mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM);
203272343Sngie		if (!mbio) {
204272343Sngie			CMSerror(CMS_R_CONTENT_NOT_FOUND);
205272343Sngie			return 0;
206272343Sngie		}
207272343Sngie		contlen = BIO_get_mem_data(mbio, &cont);
208272343Sngie		/* Set bio as read only so its content can't be clobbered */
209272343Sngie		BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY);
210272343Sngie		BIO_set_mem_eof_return(mbio, 0);
211272343Sngie		ASN1_STRING_set0(*pos, cont, contlen);
212272343Sngie		(*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
213272343Sngie	}
214272343Sngie
215272343Sngie	switch (OBJ_obj2nid(cms->contentType)) {
216272343Sngie
217272343Sngie	case NID_pkcs7_data:
218272343Sngie	case NID_pkcs7_enveloped:
219272343Sngie	case NID_pkcs7_encrypted:
220272343Sngie	case NID_id_smime_ct_compressedData:
221272343Sngie		/* Nothing to do */
222272343Sngie		return 1;
223272343Sngie
224272343Sngie	case NID_pkcs7_signed:
225272343Sngie		return cms_SignedData_final(cms, cmsbio);
226272343Sngie
227272343Sngie	case NID_pkcs7_digest:
228272343Sngie		return cms_DigestedData_do_final(cms, cmsbio, 0);
229272343Sngie
230272343Sngie	default:
231272343Sngie		CMSerror(CMS_R_UNSUPPORTED_TYPE);
232272343Sngie		return 0;
233272343Sngie	}
234272343Sngie}
235272343SngieLCRYPTO_ALIAS(CMS_dataFinal);
236272343Sngie
237272343Sngieint
238272343SngieCMS_get_version(const CMS_ContentInfo *cms, long *version)
239272343Sngie{
240272343Sngie	switch (OBJ_obj2nid(cms->contentType)) {
241272343Sngie	case NID_pkcs7_signed:
242272343Sngie		*version = cms->d.signedData->version;
243272343Sngie		return 1;
244272343Sngie
245272343Sngie	case NID_pkcs7_enveloped:
246272343Sngie		*version = cms->d.envelopedData->version;
247272343Sngie		return 1;
248272343Sngie
249272343Sngie	case NID_pkcs7_digest:
250272343Sngie		*version = cms->d.digestedData->version;
251272343Sngie		return 1;
252272343Sngie
253272343Sngie	case NID_pkcs7_encrypted:
254272343Sngie		*version = cms->d.encryptedData->version;
255272343Sngie		return 1;
256272343Sngie
257272343Sngie	case NID_id_smime_ct_authData:
258272343Sngie		*version = cms->d.authenticatedData->version;
259272343Sngie		return 1;
260272343Sngie
261272343Sngie	case NID_id_smime_ct_compressedData:
262272343Sngie		*version = cms->d.compressedData->version;
263272343Sngie		return 1;
264272343Sngie
265272343Sngie	default:
266272343Sngie		CMSerror(CMS_R_UNSUPPORTED_TYPE);
267272343Sngie		return 0;
268272343Sngie	}
269272343Sngie}
270272343SngieLCRYPTO_ALIAS(CMS_get_version);
271272343Sngie
272272343Sngieint
273272343SngieCMS_SignerInfo_get_version(const CMS_SignerInfo *si, long *version)
274272343Sngie{
275272343Sngie	*version = si->version;
276272343Sngie	return 1;
277272343Sngie}
278272343SngieLCRYPTO_ALIAS(CMS_SignerInfo_get_version);
279272343Sngie
280272343Sngie/*
281272343Sngie * Return an OCTET STRING pointer to content. This allows it to be accessed
282272343Sngie * or set later.
283272343Sngie */
284272343Sngie
285272343SngieASN1_OCTET_STRING **
286272343SngieCMS_get0_content(CMS_ContentInfo *cms)
287272343Sngie{
288272343Sngie	switch (OBJ_obj2nid(cms->contentType)) {
289272343Sngie	case NID_pkcs7_data:
290272343Sngie		return &cms->d.data;
291272343Sngie
292272343Sngie	case NID_pkcs7_signed:
293272343Sngie		return &cms->d.signedData->encapContentInfo->eContent;
294272343Sngie
295272343Sngie	case NID_pkcs7_enveloped:
296272343Sngie		return &cms->d.envelopedData->encryptedContentInfo->encryptedContent;
297272343Sngie
298272343Sngie	case NID_pkcs7_digest:
299272343Sngie		return &cms->d.digestedData->encapContentInfo->eContent;
300272343Sngie
301272343Sngie	case NID_pkcs7_encrypted:
302272343Sngie		return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
303272343Sngie
304272343Sngie	case NID_id_smime_ct_authData:
305272343Sngie		return &cms->d.authenticatedData->encapContentInfo->eContent;
306272343Sngie
307272343Sngie	case NID_id_smime_ct_compressedData:
308272343Sngie		return &cms->d.compressedData->encapContentInfo->eContent;
309272343Sngie
310272343Sngie	default:
311272343Sngie		if (cms->d.other->type == V_ASN1_OCTET_STRING)
312272343Sngie			return &cms->d.other->value.octet_string;
313272343Sngie		CMSerror(CMS_R_UNSUPPORTED_CONTENT_TYPE);
314272343Sngie		return NULL;
315272343Sngie	}
316272343Sngie}
317272343SngieLCRYPTO_ALIAS(CMS_get0_content);
318272343Sngie
319272343Sngie/*
320272343Sngie * Return an ASN1_OBJECT pointer to content type. This allows it to be
321272343Sngie * accessed or set later.
322272343Sngie */
323272343Sngie
324272343Sngiestatic ASN1_OBJECT **
325272343Sngiecms_get0_econtent_type(CMS_ContentInfo *cms)
326272343Sngie{
327272343Sngie	switch (OBJ_obj2nid(cms->contentType)) {
328272343Sngie	case NID_pkcs7_signed:
329272343Sngie		return &cms->d.signedData->encapContentInfo->eContentType;
330272343Sngie
331272343Sngie	case NID_pkcs7_enveloped:
332272343Sngie		return &cms->d.envelopedData->encryptedContentInfo->contentType;
333272343Sngie
334272343Sngie	case NID_pkcs7_digest:
335272343Sngie		return &cms->d.digestedData->encapContentInfo->eContentType;
336272343Sngie
337272343Sngie	case NID_pkcs7_encrypted:
338272343Sngie		return &cms->d.encryptedData->encryptedContentInfo->contentType;
339272343Sngie
340272343Sngie	case NID_id_smime_ct_authData:
341272343Sngie		return &cms->d.authenticatedData->encapContentInfo->eContentType;
342272343Sngie
343272343Sngie	case NID_id_smime_ct_compressedData:
344272343Sngie		return &cms->d.compressedData->encapContentInfo->eContentType;
345272343Sngie
346272343Sngie	default:
347272343Sngie		CMSerror(CMS_R_UNSUPPORTED_CONTENT_TYPE);
348272343Sngie		return NULL;
349272343Sngie	}
350272343Sngie}
351272343Sngie
352const ASN1_OBJECT *
353CMS_get0_eContentType(CMS_ContentInfo *cms)
354{
355	ASN1_OBJECT **petype;
356
357	petype = cms_get0_econtent_type(cms);
358	if (petype)
359		return *petype;
360
361	return NULL;
362}
363LCRYPTO_ALIAS(CMS_get0_eContentType);
364
365int
366CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid)
367{
368	ASN1_OBJECT **petype, *etype;
369
370	petype = cms_get0_econtent_type(cms);
371	if (!petype)
372		return 0;
373	if (!oid)
374		return 1;
375	etype = OBJ_dup(oid);
376	if (!etype)
377		return 0;
378	ASN1_OBJECT_free(*petype);
379	*petype = etype;
380
381	return 1;
382}
383LCRYPTO_ALIAS(CMS_set1_eContentType);
384
385int
386CMS_is_detached(CMS_ContentInfo *cms)
387{
388	ASN1_OCTET_STRING **pos;
389
390	pos = CMS_get0_content(cms);
391	if (!pos)
392		return -1;
393	if (*pos)
394		return 0;
395
396	return 1;
397}
398LCRYPTO_ALIAS(CMS_is_detached);
399
400int
401CMS_set_detached(CMS_ContentInfo *cms, int detached)
402{
403	ASN1_OCTET_STRING **pos;
404
405	pos = CMS_get0_content(cms);
406	if (!pos)
407		return 0;
408	if (detached) {
409		ASN1_OCTET_STRING_free(*pos);
410		*pos = NULL;
411		return 1;
412	}
413	if (*pos == NULL)
414		*pos = ASN1_OCTET_STRING_new();
415	if (*pos != NULL) {
416		/*
417		 * NB: special flag to show content is created and not read in.
418		 */
419		(*pos)->flags |= ASN1_STRING_FLAG_CONT;
420		return 1;
421	}
422	CMSerror(ERR_R_MALLOC_FAILURE);
423
424	return 0;
425}
426LCRYPTO_ALIAS(CMS_set_detached);
427
428/* Create a digest BIO from an X509_ALGOR structure */
429
430BIO *
431cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
432{
433	BIO *mdbio = NULL;
434	const ASN1_OBJECT *digestoid;
435	const EVP_MD *digest;
436
437	X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
438	digest = EVP_get_digestbyobj(digestoid);
439	if (!digest) {
440		CMSerror(CMS_R_UNKNOWN_DIGEST_ALGORITHM);
441		goto err;
442	}
443	mdbio = BIO_new(BIO_f_md());
444	if (mdbio == NULL || !BIO_set_md(mdbio, digest)) {
445		CMSerror(CMS_R_MD_BIO_INIT_ERROR);
446		goto err;
447	}
448	return mdbio;
449
450 err:
451	BIO_free(mdbio);
452
453	return NULL;
454}
455
456/* Locate a message digest content from a BIO chain based on SignerInfo */
457
458int
459cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain, X509_ALGOR *mdalg)
460{
461	int nid;
462	const ASN1_OBJECT *mdoid;
463
464	X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
465	nid = OBJ_obj2nid(mdoid);
466	/* Look for digest type to match signature */
467	for (;;) {
468		EVP_MD_CTX *mtmp;
469		chain = BIO_find_type(chain, BIO_TYPE_MD);
470		if (chain == NULL) {
471			CMSerror(CMS_R_NO_MATCHING_DIGEST);
472			return 0;
473		}
474		BIO_get_md_ctx(chain, &mtmp);
475		if (EVP_MD_CTX_type(mtmp) == nid
476			/*
477			 * Workaround for broken implementations that use signature
478			 * algorithm OID instead of digest.
479			 */
480			|| EVP_MD_pkey_type(EVP_MD_CTX_md(mtmp)) == nid)
481			return EVP_MD_CTX_copy_ex(mctx, mtmp);
482		chain = BIO_next(chain);
483	}
484}
485
486static STACK_OF(CMS_CertificateChoices) **
487cms_get0_certificate_choices(CMS_ContentInfo *cms)
488{
489	switch (OBJ_obj2nid(cms->contentType)) {
490	case NID_pkcs7_signed:
491		return &cms->d.signedData->certificates;
492
493	case NID_pkcs7_enveloped:
494		if (cms->d.envelopedData->originatorInfo == NULL)
495			return NULL;
496		return &cms->d.envelopedData->originatorInfo->certificates;
497
498	default:
499		CMSerror(CMS_R_UNSUPPORTED_CONTENT_TYPE);
500		return NULL;
501	}
502}
503
504CMS_CertificateChoices *
505CMS_add0_CertificateChoices(CMS_ContentInfo *cms)
506{
507	STACK_OF(CMS_CertificateChoices) **pcerts;
508	CMS_CertificateChoices *cch;
509
510	pcerts = cms_get0_certificate_choices(cms);
511	if (!pcerts)
512		return NULL;
513	if (!*pcerts)
514		*pcerts = sk_CMS_CertificateChoices_new_null();
515	if (!*pcerts)
516		return NULL;
517	cch = (CMS_CertificateChoices *)ASN1_item_new(&CMS_CertificateChoices_it);
518	if (!cch)
519		return NULL;
520	if (!sk_CMS_CertificateChoices_push(*pcerts, cch)) {
521		ASN1_item_free((ASN1_VALUE *)cch, &CMS_CertificateChoices_it);
522		return NULL;
523	}
524
525	return cch;
526}
527LCRYPTO_ALIAS(CMS_add0_CertificateChoices);
528
529int
530CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
531{
532	CMS_CertificateChoices *cch;
533	STACK_OF(CMS_CertificateChoices) **pcerts;
534	int i;
535
536	pcerts = cms_get0_certificate_choices(cms);
537	if (!pcerts)
538		return 0;
539	for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
540		cch = sk_CMS_CertificateChoices_value(*pcerts, i);
541		if (cch->type == CMS_CERTCHOICE_CERT) {
542			if (!X509_cmp(cch->d.certificate, cert)) {
543			    CMSerror(CMS_R_CERTIFICATE_ALREADY_PRESENT);
544			    return 0;
545			}
546		}
547	}
548	cch = CMS_add0_CertificateChoices(cms);
549	if (!cch)
550		return 0;
551	cch->type = CMS_CERTCHOICE_CERT;
552	cch->d.certificate = cert;
553
554	return 1;
555}
556LCRYPTO_ALIAS(CMS_add0_cert);
557
558int
559CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
560{
561	int r;
562
563	r = CMS_add0_cert(cms, cert);
564	if (r > 0)
565		X509_up_ref(cert);
566
567	return r;
568}
569LCRYPTO_ALIAS(CMS_add1_cert);
570
571static STACK_OF(CMS_RevocationInfoChoice) **
572cms_get0_revocation_choices(CMS_ContentInfo *cms)
573{
574	switch (OBJ_obj2nid(cms->contentType)) {
575	case NID_pkcs7_signed:
576		return &cms->d.signedData->crls;
577
578	case NID_pkcs7_enveloped:
579		if (cms->d.envelopedData->originatorInfo == NULL)
580			return NULL;
581		return &cms->d.envelopedData->originatorInfo->crls;
582
583	default:
584		CMSerror(CMS_R_UNSUPPORTED_CONTENT_TYPE);
585		return NULL;
586	}
587}
588
589CMS_RevocationInfoChoice *
590CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)
591{
592	STACK_OF(CMS_RevocationInfoChoice) **pcrls;
593	CMS_RevocationInfoChoice *rch;
594
595	pcrls = cms_get0_revocation_choices(cms);
596	if (!pcrls)
597		return NULL;
598	if (!*pcrls)
599		*pcrls = sk_CMS_RevocationInfoChoice_new_null();
600	if (!*pcrls)
601		return NULL;
602	rch = (CMS_RevocationInfoChoice *)ASN1_item_new(&CMS_RevocationInfoChoice_it);
603	if (!rch)
604		return NULL;
605	if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch)) {
606		ASN1_item_free((ASN1_VALUE *)rch, &CMS_RevocationInfoChoice_it);
607		return NULL;
608	}
609
610	return rch;
611}
612LCRYPTO_ALIAS(CMS_add0_RevocationInfoChoice);
613
614int
615CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
616{
617	CMS_RevocationInfoChoice *rch;
618
619	rch = CMS_add0_RevocationInfoChoice(cms);
620	if (!rch)
621		return 0;
622	rch->type = CMS_REVCHOICE_CRL;
623	rch->d.crl = crl;
624
625	return 1;
626}
627LCRYPTO_ALIAS(CMS_add0_crl);
628
629int
630CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl)
631{
632	int r;
633
634	r = CMS_add0_crl(cms, crl);
635	if (r > 0)
636		X509_CRL_up_ref(crl);
637
638	return r;
639}
640LCRYPTO_ALIAS(CMS_add1_crl);
641
642STACK_OF(X509) *
643CMS_get1_certs(CMS_ContentInfo *cms)
644{
645	STACK_OF(X509) *certs = NULL;
646	CMS_CertificateChoices *cch;
647	STACK_OF(CMS_CertificateChoices) **pcerts;
648	int i;
649
650	pcerts = cms_get0_certificate_choices(cms);
651	if (!pcerts)
652		return NULL;
653	for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
654		cch = sk_CMS_CertificateChoices_value(*pcerts, i);
655		if (cch->type == 0) {
656			if (!certs) {
657			    certs = sk_X509_new_null();
658			    if (!certs)
659			        return NULL;
660			}
661			if (!sk_X509_push(certs, cch->d.certificate)) {
662			    sk_X509_pop_free(certs, X509_free);
663			    return NULL;
664			}
665			X509_up_ref(cch->d.certificate);
666		}
667	}
668	return certs;
669}
670LCRYPTO_ALIAS(CMS_get1_certs);
671
672STACK_OF(X509_CRL) *
673CMS_get1_crls(CMS_ContentInfo *cms)
674{
675	STACK_OF(X509_CRL) *crls = NULL;
676	STACK_OF(CMS_RevocationInfoChoice) **pcrls;
677	CMS_RevocationInfoChoice *rch;
678	int i;
679
680	pcrls = cms_get0_revocation_choices(cms);
681	if (!pcrls)
682		return NULL;
683	for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++) {
684		rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
685		if (rch->type == 0) {
686			if (!crls) {
687			    crls = sk_X509_CRL_new_null();
688			    if (!crls)
689			        return NULL;
690			}
691			if (!sk_X509_CRL_push(crls, rch->d.crl)) {
692			    sk_X509_CRL_pop_free(crls, X509_CRL_free);
693			    return NULL;
694			}
695			X509_CRL_up_ref(rch->d.crl);
696		}
697	}
698	return crls;
699}
700LCRYPTO_ALIAS(CMS_get1_crls);
701
702static const ASN1_OCTET_STRING *
703cms_X509_get0_subject_key_id(X509 *x)
704{
705	/* Call for side-effect of computing hash and caching extensions */
706	X509_check_purpose(x, -1, -1);
707	return x->skid;
708}
709
710int
711cms_ias_cert_cmp(CMS_IssuerAndSerialNumber *ias, X509 *cert)
712{
713	int ret;
714
715	ret = X509_NAME_cmp(ias->issuer, X509_get_issuer_name(cert));
716	if (ret)
717		return ret;
718
719	return ASN1_INTEGER_cmp(ias->serialNumber, X509_get_serialNumber(cert));
720}
721
722int
723cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert)
724{
725	const ASN1_OCTET_STRING *cert_keyid = cms_X509_get0_subject_key_id(cert);
726
727	if (cert_keyid == NULL)
728		return -1;
729
730	return ASN1_OCTET_STRING_cmp(keyid, cert_keyid);
731}
732
733int
734cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert)
735{
736	CMS_IssuerAndSerialNumber *ias;
737
738	ias = (CMS_IssuerAndSerialNumber *)ASN1_item_new(&CMS_IssuerAndSerialNumber_it);
739	if (!ias)
740		goto err;
741	if (!X509_NAME_set(&ias->issuer, X509_get_issuer_name(cert)))
742		goto err;
743	if (!ASN1_STRING_copy(ias->serialNumber, X509_get_serialNumber(cert)))
744		goto err;
745	ASN1_item_free((ASN1_VALUE *)*pias, &CMS_IssuerAndSerialNumber_it);
746	*pias = ias;
747
748	return 1;
749
750 err:
751	ASN1_item_free((ASN1_VALUE *)ias, &CMS_IssuerAndSerialNumber_it);
752	CMSerror(ERR_R_MALLOC_FAILURE);
753
754	return 0;
755}
756
757int
758cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert)
759{
760	ASN1_OCTET_STRING *keyid = NULL;
761	const ASN1_OCTET_STRING *cert_keyid;
762
763	cert_keyid = cms_X509_get0_subject_key_id(cert);
764	if (cert_keyid == NULL) {
765		CMSerror(CMS_R_CERTIFICATE_HAS_NO_KEYID);
766		return 0;
767	}
768	keyid = ASN1_STRING_dup(cert_keyid);
769	if (!keyid) {
770		CMSerror(ERR_R_MALLOC_FAILURE);
771		return 0;
772	}
773	ASN1_OCTET_STRING_free(*pkeyid);
774	*pkeyid = keyid;
775
776	return 1;
777}
778