1/* crypto/cms/cms_lib.c */
2/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3 * project.
4 */
5/* ====================================================================
6 * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in
17 *    the documentation and/or other materials provided with the
18 *    distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 *    software must display the following acknowledgment:
22 *    "This product includes software developed by the OpenSSL Project
23 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26 *    endorse or promote products derived from this software without
27 *    prior written permission. For written permission, please contact
28 *    licensing@OpenSSL.org.
29 *
30 * 5. Products derived from this software may not be called "OpenSSL"
31 *    nor may "OpenSSL" appear in their names without prior written
32 *    permission of the OpenSSL Project.
33 *
34 * 6. Redistributions of any form whatsoever must retain the following
35 *    acknowledgment:
36 *    "This product includes software developed by the OpenSSL Project
37 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 */
53
54#include <openssl/asn1t.h>
55#include <openssl/x509.h>
56#include <openssl/err.h>
57#include <openssl/pem.h>
58#include <openssl/bio.h>
59#include <openssl/asn1.h>
60#include "cms.h"
61#include "cms_lcl.h"
62
63IMPLEMENT_ASN1_FUNCTIONS(CMS_ContentInfo)
64IMPLEMENT_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
65
66DECLARE_ASN1_ITEM(CMS_CertificateChoices)
67DECLARE_ASN1_ITEM(CMS_RevocationInfoChoice)
68DECLARE_STACK_OF(CMS_CertificateChoices)
69DECLARE_STACK_OF(CMS_RevocationInfoChoice)
70
71const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms)
72	{
73	return cms->contentType;
74	}
75
76CMS_ContentInfo *cms_Data_create(void)
77	{
78	CMS_ContentInfo *cms;
79	cms = CMS_ContentInfo_new();
80	if (cms)
81		{
82		cms->contentType = OBJ_nid2obj(NID_pkcs7_data);
83		/* Never detached */
84		CMS_set_detached(cms, 0);
85		}
86	return cms;
87	}
88
89BIO *cms_content_bio(CMS_ContentInfo *cms)
90	{
91	ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
92	if (!pos)
93		return NULL;
94	/* If content detached data goes nowhere: create NULL BIO */
95	if (!*pos)
96		return BIO_new(BIO_s_null());
97	/* If content not detached and created return memory BIO
98	 */
99	if (!*pos || ((*pos)->flags == ASN1_STRING_FLAG_CONT))
100		return BIO_new(BIO_s_mem());
101	/* Else content was read in: return read only BIO for it */
102	return BIO_new_mem_buf((*pos)->data, (*pos)->length);
103	}
104
105BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont)
106	{
107	BIO *cmsbio, *cont;
108	if (icont)
109		cont = icont;
110	else
111		cont = cms_content_bio(cms);
112	if (!cont)
113		{
114		CMSerr(CMS_F_CMS_DATAINIT, CMS_R_NO_CONTENT);
115		return NULL;
116		}
117	switch (OBJ_obj2nid(cms->contentType))
118		{
119
120		case NID_pkcs7_data:
121		return cont;
122
123		case NID_pkcs7_signed:
124		cmsbio = cms_SignedData_init_bio(cms);
125		break;
126
127		case NID_pkcs7_digest:
128		cmsbio = cms_DigestedData_init_bio(cms);
129		break;
130#ifdef ZLIB
131		case NID_id_smime_ct_compressedData:
132		cmsbio = cms_CompressedData_init_bio(cms);
133		break;
134#endif
135
136		case NID_pkcs7_encrypted:
137		cmsbio = cms_EncryptedData_init_bio(cms);
138		break;
139
140		case NID_pkcs7_enveloped:
141		cmsbio = cms_EnvelopedData_init_bio(cms);
142		break;
143
144		default:
145		CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE);
146		return NULL;
147		}
148
149	if (cmsbio)
150		return BIO_push(cmsbio, cont);
151
152	if (!icont)
153		BIO_free(cont);
154	return NULL;
155
156	}
157
158int CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
159	{
160	ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
161	if (!pos)
162		return 0;
163	/* If ebmedded content find memory BIO and set content */
164	if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT))
165		{
166		BIO *mbio;
167		unsigned char *cont;
168		long contlen;
169		mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM);
170		if (!mbio)
171			{
172			CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_CONTENT_NOT_FOUND);
173			return 0;
174			}
175		contlen = BIO_get_mem_data(mbio, &cont);
176		/* Set bio as read only so its content can't be clobbered */
177		BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY);
178		BIO_set_mem_eof_return(mbio, 0);
179		ASN1_STRING_set0(*pos, cont, contlen);
180		(*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
181		}
182
183	switch (OBJ_obj2nid(cms->contentType))
184		{
185
186		case NID_pkcs7_data:
187		case NID_pkcs7_enveloped:
188		case NID_pkcs7_encrypted:
189		case NID_id_smime_ct_compressedData:
190		/* Nothing to do */
191		return 1;
192
193		case NID_pkcs7_signed:
194		return cms_SignedData_final(cms, cmsbio);
195
196		case NID_pkcs7_digest:
197		return cms_DigestedData_do_final(cms, cmsbio, 0);
198
199		default:
200		CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_UNSUPPORTED_TYPE);
201		return 0;
202		}
203	}
204
205/* Return an OCTET STRING pointer to content. This allows it to
206 * be accessed or set later.
207 */
208
209ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms)
210	{
211	switch (OBJ_obj2nid(cms->contentType))
212		{
213
214		case NID_pkcs7_data:
215		return &cms->d.data;
216
217		case NID_pkcs7_signed:
218		return &cms->d.signedData->encapContentInfo->eContent;
219
220		case NID_pkcs7_enveloped:
221		return &cms->d.envelopedData->encryptedContentInfo->encryptedContent;
222
223		case NID_pkcs7_digest:
224		return &cms->d.digestedData->encapContentInfo->eContent;
225
226		case NID_pkcs7_encrypted:
227		return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
228
229		case NID_id_smime_ct_authData:
230		return &cms->d.authenticatedData->encapContentInfo->eContent;
231
232		case NID_id_smime_ct_compressedData:
233		return &cms->d.compressedData->encapContentInfo->eContent;
234
235		default:
236		if (cms->d.other->type == V_ASN1_OCTET_STRING)
237			return &cms->d.other->value.octet_string;
238		CMSerr(CMS_F_CMS_GET0_CONTENT, CMS_R_UNSUPPORTED_CONTENT_TYPE);
239		return NULL;
240
241		}
242	}
243
244/* Return an ASN1_OBJECT pointer to content type. This allows it to
245 * be accessed or set later.
246 */
247
248static ASN1_OBJECT **cms_get0_econtent_type(CMS_ContentInfo *cms)
249	{
250	switch (OBJ_obj2nid(cms->contentType))
251		{
252
253		case NID_pkcs7_signed:
254		return &cms->d.signedData->encapContentInfo->eContentType;
255
256		case NID_pkcs7_enveloped:
257		return &cms->d.envelopedData->encryptedContentInfo->contentType;
258
259		case NID_pkcs7_digest:
260		return &cms->d.digestedData->encapContentInfo->eContentType;
261
262		case NID_pkcs7_encrypted:
263		return &cms->d.encryptedData->encryptedContentInfo->contentType;
264
265		case NID_id_smime_ct_authData:
266		return &cms->d.authenticatedData->encapContentInfo->eContentType;
267
268		case NID_id_smime_ct_compressedData:
269		return &cms->d.compressedData->encapContentInfo->eContentType;
270
271		default:
272		CMSerr(CMS_F_CMS_GET0_ECONTENT_TYPE,
273					CMS_R_UNSUPPORTED_CONTENT_TYPE);
274		return NULL;
275
276		}
277	}
278
279const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms)
280	{
281	ASN1_OBJECT **petype;
282	petype = cms_get0_econtent_type(cms);
283	if (petype)
284		return *petype;
285	return NULL;
286	}
287
288int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid)
289	{
290	ASN1_OBJECT **petype, *etype;
291	petype = cms_get0_econtent_type(cms);
292	if (!petype)
293		return 0;
294	if (!oid)
295		return 1;
296	etype = OBJ_dup(oid);
297	if (!etype)
298		return 0;
299	ASN1_OBJECT_free(*petype);
300	*petype = etype;
301	return 1;
302	}
303
304int CMS_is_detached(CMS_ContentInfo *cms)
305	{
306	ASN1_OCTET_STRING **pos;
307	pos = CMS_get0_content(cms);
308	if (!pos)
309		return -1;
310	if (*pos)
311		return 0;
312	return 1;
313	}
314
315int CMS_set_detached(CMS_ContentInfo *cms, int detached)
316	{
317	ASN1_OCTET_STRING **pos;
318	pos = CMS_get0_content(cms);
319	if (!pos)
320		return 0;
321	if (detached)
322		{
323		if (*pos)
324			{
325			ASN1_OCTET_STRING_free(*pos);
326			*pos = NULL;
327			}
328		return 1;
329		}
330	if (!*pos)
331		*pos = ASN1_OCTET_STRING_new();
332	if (*pos)
333		{
334		/* NB: special flag to show content is created and not
335		 * read in.
336		 */
337		(*pos)->flags |= ASN1_STRING_FLAG_CONT;
338		return 1;
339		}
340	CMSerr(CMS_F_CMS_SET_DETACHED, ERR_R_MALLOC_FAILURE);
341	return 0;
342	}
343
344/* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */
345
346void cms_DigestAlgorithm_set(X509_ALGOR *alg, const EVP_MD *md)
347	{
348	int param_type;
349
350	if (md->flags & EVP_MD_FLAG_DIGALGID_ABSENT)
351		param_type = V_ASN1_UNDEF;
352	else
353		param_type = V_ASN1_NULL;
354
355	X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL);
356
357	}
358
359/* Create a digest BIO from an X509_ALGOR structure */
360
361BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
362	{
363	BIO *mdbio = NULL;
364	ASN1_OBJECT *digestoid;
365	const EVP_MD *digest;
366	X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
367	digest = EVP_get_digestbyobj(digestoid);
368	if (!digest)
369		{
370		CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
371				CMS_R_UNKNOWN_DIGEST_ALGORIHM);
372		goto err;
373		}
374	mdbio = BIO_new(BIO_f_md());
375	if (!mdbio || !BIO_set_md(mdbio, digest))
376		{
377		CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
378				CMS_R_MD_BIO_INIT_ERROR);
379		goto err;
380		}
381	return mdbio;
382	err:
383	if (mdbio)
384		BIO_free(mdbio);
385	return NULL;
386	}
387
388/* Locate a message digest content from a BIO chain based on SignerInfo */
389
390int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
391					X509_ALGOR *mdalg)
392	{
393	int nid;
394	ASN1_OBJECT *mdoid;
395	X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
396	nid = OBJ_obj2nid(mdoid);
397	/* Look for digest type to match signature */
398	for (;;)
399		{
400		EVP_MD_CTX *mtmp;
401		chain = BIO_find_type(chain, BIO_TYPE_MD);
402		if (chain == NULL)
403			{
404			CMSerr(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX,
405						CMS_R_NO_MATCHING_DIGEST);
406			return 0;
407			}
408		BIO_get_md_ctx(chain, &mtmp);
409		if (EVP_MD_CTX_type(mtmp) == nid
410		/* Workaround for broken implementations that use signature
411		 * algorithm  OID instead of digest.
412		 */
413			|| EVP_MD_pkey_type(EVP_MD_CTX_md(mtmp)) == nid)
414			return EVP_MD_CTX_copy_ex(mctx, mtmp);
415		chain = BIO_next(chain);
416		}
417	}
418
419static STACK_OF(CMS_CertificateChoices) **cms_get0_certificate_choices(CMS_ContentInfo *cms)
420	{
421	switch (OBJ_obj2nid(cms->contentType))
422		{
423
424		case NID_pkcs7_signed:
425		return &cms->d.signedData->certificates;
426
427		case NID_pkcs7_enveloped:
428		return &cms->d.envelopedData->originatorInfo->certificates;
429
430		default:
431		CMSerr(CMS_F_CMS_GET0_CERTIFICATE_CHOICES,
432					CMS_R_UNSUPPORTED_CONTENT_TYPE);
433		return NULL;
434
435		}
436	}
437
438CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms)
439	{
440	STACK_OF(CMS_CertificateChoices) **pcerts;
441	CMS_CertificateChoices *cch;
442	pcerts = cms_get0_certificate_choices(cms);
443	if (!pcerts)
444		return NULL;
445	if (!*pcerts)
446		*pcerts = sk_CMS_CertificateChoices_new_null();
447	if (!*pcerts)
448		return NULL;
449	cch = M_ASN1_new_of(CMS_CertificateChoices);
450	if (!cch)
451		return NULL;
452	if (!sk_CMS_CertificateChoices_push(*pcerts, cch))
453		{
454		M_ASN1_free_of(cch, CMS_CertificateChoices);
455		return NULL;
456		}
457	return cch;
458	}
459
460int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
461	{
462	CMS_CertificateChoices *cch;
463	STACK_OF(CMS_CertificateChoices) **pcerts;
464	int i;
465	pcerts = cms_get0_certificate_choices(cms);
466	if (!pcerts)
467		return 0;
468	for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++)
469		{
470		cch = sk_CMS_CertificateChoices_value(*pcerts, i);
471		if (cch->type == CMS_CERTCHOICE_CERT)
472			{
473			if (!X509_cmp(cch->d.certificate, cert))
474				{
475				CMSerr(CMS_F_CMS_ADD0_CERT,
476					CMS_R_CERTIFICATE_ALREADY_PRESENT);
477				return 0;
478				}
479			}
480		}
481	cch = CMS_add0_CertificateChoices(cms);
482	if (!cch)
483		return 0;
484	cch->type = CMS_CERTCHOICE_CERT;
485	cch->d.certificate = cert;
486	return 1;
487	}
488
489int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
490	{
491	int r;
492	r = CMS_add0_cert(cms, cert);
493	if (r > 0)
494		CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
495	return r;
496	}
497
498static STACK_OF(CMS_RevocationInfoChoice) **cms_get0_revocation_choices(CMS_ContentInfo *cms)
499	{
500	switch (OBJ_obj2nid(cms->contentType))
501		{
502
503		case NID_pkcs7_signed:
504		return &cms->d.signedData->crls;
505
506		case NID_pkcs7_enveloped:
507		return &cms->d.envelopedData->originatorInfo->crls;
508
509		default:
510		CMSerr(CMS_F_CMS_GET0_REVOCATION_CHOICES,
511					CMS_R_UNSUPPORTED_CONTENT_TYPE);
512		return NULL;
513
514		}
515	}
516
517CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)
518	{
519	STACK_OF(CMS_RevocationInfoChoice) **pcrls;
520	CMS_RevocationInfoChoice *rch;
521	pcrls = cms_get0_revocation_choices(cms);
522	if (!pcrls)
523		return NULL;
524	if (!*pcrls)
525		*pcrls = sk_CMS_RevocationInfoChoice_new_null();
526	if (!*pcrls)
527		return NULL;
528	rch = M_ASN1_new_of(CMS_RevocationInfoChoice);
529	if (!rch)
530		return NULL;
531	if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch))
532		{
533		M_ASN1_free_of(rch, CMS_RevocationInfoChoice);
534		return NULL;
535		}
536	return rch;
537	}
538
539int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
540	{
541	CMS_RevocationInfoChoice *rch;
542	rch = CMS_add0_RevocationInfoChoice(cms);
543	if (!rch)
544		return 0;
545	rch->type = CMS_REVCHOICE_CRL;
546	rch->d.crl = crl;
547	return 1;
548	}
549
550int CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl)
551	{
552	int r;
553	r = CMS_add0_crl(cms, crl);
554	if (r > 0)
555		CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
556	return r;
557	}
558
559STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms)
560	{
561	STACK_OF(X509) *certs = NULL;
562	CMS_CertificateChoices *cch;
563	STACK_OF(CMS_CertificateChoices) **pcerts;
564	int i;
565	pcerts = cms_get0_certificate_choices(cms);
566	if (!pcerts)
567		return NULL;
568	for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++)
569		{
570		cch = sk_CMS_CertificateChoices_value(*pcerts, i);
571		if (cch->type == 0)
572			{
573			if (!certs)
574				{
575				certs = sk_X509_new_null();
576				if (!certs)
577					return NULL;
578				}
579			if (!sk_X509_push(certs, cch->d.certificate))
580				{
581				sk_X509_pop_free(certs, X509_free);
582				return NULL;
583				}
584			CRYPTO_add(&cch->d.certificate->references,
585						1, CRYPTO_LOCK_X509);
586			}
587		}
588	return certs;
589
590	}
591
592STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms)
593	{
594	STACK_OF(X509_CRL) *crls = NULL;
595	STACK_OF(CMS_RevocationInfoChoice) **pcrls;
596	CMS_RevocationInfoChoice *rch;
597	int i;
598	pcrls = cms_get0_revocation_choices(cms);
599	if (!pcrls)
600		return NULL;
601	for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++)
602		{
603		rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
604		if (rch->type == 0)
605			{
606			if (!crls)
607				{
608				crls = sk_X509_CRL_new_null();
609				if (!crls)
610					return NULL;
611				}
612			if (!sk_X509_CRL_push(crls, rch->d.crl))
613				{
614				sk_X509_CRL_pop_free(crls, X509_CRL_free);
615				return NULL;
616				}
617			CRYPTO_add(&rch->d.crl->references,
618						1, CRYPTO_LOCK_X509_CRL);
619			}
620		}
621	return crls;
622	}
623