cms_smime.c revision 183234
1183234Ssimon/* crypto/cms/cms_smime.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 "cryptlib.h"
55183234Ssimon#include <openssl/asn1t.h>
56183234Ssimon#include <openssl/x509.h>
57183234Ssimon#include <openssl/x509v3.h>
58183234Ssimon#include <openssl/err.h>
59183234Ssimon#include <openssl/cms.h>
60183234Ssimon#include "cms_lcl.h"
61183234Ssimon
62183234Ssimonstatic int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
63183234Ssimon	{
64183234Ssimon	unsigned char buf[4096];
65183234Ssimon	int r = 0, i;
66183234Ssimon	BIO *tmpout = NULL;
67183234Ssimon
68183234Ssimon	if (out == NULL)
69183234Ssimon		tmpout = BIO_new(BIO_s_null());
70183234Ssimon	else if (flags & CMS_TEXT)
71183234Ssimon		tmpout = BIO_new(BIO_s_mem());
72183234Ssimon	else
73183234Ssimon		tmpout = out;
74183234Ssimon
75183234Ssimon	if(!tmpout)
76183234Ssimon		{
77183234Ssimon		CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE);
78183234Ssimon		goto err;
79183234Ssimon		}
80183234Ssimon
81183234Ssimon	/* Read all content through chain to process digest, decrypt etc */
82183234Ssimon	for (;;)
83183234Ssimon	{
84183234Ssimon		i=BIO_read(in,buf,sizeof(buf));
85183234Ssimon		if (i <= 0)
86183234Ssimon			{
87183234Ssimon			if (BIO_method_type(in) == BIO_TYPE_CIPHER)
88183234Ssimon				{
89183234Ssimon				if (!BIO_get_cipher_status(in))
90183234Ssimon					goto err;
91183234Ssimon				}
92183234Ssimon			if (i < 0)
93183234Ssimon				goto err;
94183234Ssimon			break;
95183234Ssimon			}
96183234Ssimon
97183234Ssimon		if (tmpout && (BIO_write(tmpout, buf, i) != i))
98183234Ssimon			goto err;
99183234Ssimon	}
100183234Ssimon
101183234Ssimon	if(flags & CMS_TEXT)
102183234Ssimon		{
103183234Ssimon		if(!SMIME_text(tmpout, out))
104183234Ssimon			{
105183234Ssimon			CMSerr(CMS_F_CMS_COPY_CONTENT,CMS_R_SMIME_TEXT_ERROR);
106183234Ssimon			goto err;
107183234Ssimon			}
108183234Ssimon		}
109183234Ssimon
110183234Ssimon	r = 1;
111183234Ssimon
112183234Ssimon	err:
113183234Ssimon	if (tmpout && (tmpout != out))
114183234Ssimon		BIO_free(tmpout);
115183234Ssimon	return r;
116183234Ssimon
117183234Ssimon	}
118183234Ssimon
119183234Ssimonstatic int check_content(CMS_ContentInfo *cms)
120183234Ssimon	{
121183234Ssimon	ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
122183234Ssimon	if (!pos || !*pos)
123183234Ssimon		{
124183234Ssimon		CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT);
125183234Ssimon		return 0;
126183234Ssimon		}
127183234Ssimon	return 1;
128183234Ssimon	}
129183234Ssimon
130183234Ssimonstatic void do_free_upto(BIO *f, BIO *upto)
131183234Ssimon	{
132183234Ssimon	if (upto)
133183234Ssimon		{
134183234Ssimon		BIO *tbio;
135183234Ssimon		do
136183234Ssimon			{
137183234Ssimon			tbio = BIO_pop(f);
138183234Ssimon			BIO_free(f);
139183234Ssimon			f = tbio;
140183234Ssimon			}
141183234Ssimon		while (f != upto);
142183234Ssimon		}
143183234Ssimon	else
144183234Ssimon		BIO_free_all(f);
145183234Ssimon	}
146183234Ssimon
147183234Ssimonint CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
148183234Ssimon	{
149183234Ssimon	BIO *cont;
150183234Ssimon	int r;
151183234Ssimon	if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data)
152183234Ssimon		{
153183234Ssimon		CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA);
154183234Ssimon		return 0;
155183234Ssimon		}
156183234Ssimon	cont = CMS_dataInit(cms, NULL);
157183234Ssimon	if (!cont)
158183234Ssimon		return 0;
159183234Ssimon	r = cms_copy_content(out, cont, flags);
160183234Ssimon	BIO_free_all(cont);
161183234Ssimon	return r;
162183234Ssimon	}
163183234Ssimon
164183234SsimonCMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
165183234Ssimon	{
166183234Ssimon	CMS_ContentInfo *cms;
167183234Ssimon	cms = cms_Data_create();
168183234Ssimon	if (!cms)
169183234Ssimon		return NULL;
170183234Ssimon
171183234Ssimon	if (CMS_final(cms, in, NULL, flags))
172183234Ssimon		return cms;
173183234Ssimon
174183234Ssimon	CMS_ContentInfo_free(cms);
175183234Ssimon
176183234Ssimon	return NULL;
177183234Ssimon	}
178183234Ssimon
179183234Ssimonint CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
180183234Ssimon							unsigned int flags)
181183234Ssimon	{
182183234Ssimon	BIO *cont;
183183234Ssimon	int r;
184183234Ssimon	if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest)
185183234Ssimon		{
186183234Ssimon		CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA);
187183234Ssimon		return 0;
188183234Ssimon		}
189183234Ssimon
190183234Ssimon	if (!dcont && !check_content(cms))
191183234Ssimon		return 0;
192183234Ssimon
193183234Ssimon	cont = CMS_dataInit(cms, dcont);
194183234Ssimon	if (!cont)
195183234Ssimon		return 0;
196183234Ssimon	r = cms_copy_content(out, cont, flags);
197183234Ssimon	if (r)
198183234Ssimon		r = cms_DigestedData_do_final(cms, cont, 1);
199183234Ssimon	do_free_upto(cont, dcont);
200183234Ssimon	return r;
201183234Ssimon	}
202183234Ssimon
203183234SsimonCMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
204183234Ssimon					unsigned int flags)
205183234Ssimon	{
206183234Ssimon	CMS_ContentInfo *cms;
207183234Ssimon	if (!md)
208183234Ssimon		md = EVP_sha1();
209183234Ssimon	cms = cms_DigestedData_create(md);
210183234Ssimon	if (!cms)
211183234Ssimon		return NULL;
212183234Ssimon
213183234Ssimon	if(!(flags & CMS_DETACHED))
214183234Ssimon		{
215183234Ssimon		flags &= ~CMS_STREAM;
216183234Ssimon		CMS_set_detached(cms, 0);
217183234Ssimon		}
218183234Ssimon
219183234Ssimon	if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
220183234Ssimon		return cms;
221183234Ssimon
222183234Ssimon	CMS_ContentInfo_free(cms);
223183234Ssimon	return NULL;
224183234Ssimon	}
225183234Ssimon
226183234Ssimonint CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
227183234Ssimon				const unsigned char *key, size_t keylen,
228183234Ssimon				BIO *dcont, BIO *out, unsigned int flags)
229183234Ssimon	{
230183234Ssimon	BIO *cont;
231183234Ssimon	int r;
232183234Ssimon	if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted)
233183234Ssimon		{
234183234Ssimon		CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT,
235183234Ssimon					CMS_R_TYPE_NOT_ENCRYPTED_DATA);
236183234Ssimon		return 0;
237183234Ssimon		}
238183234Ssimon
239183234Ssimon	if (!dcont && !check_content(cms))
240183234Ssimon		return 0;
241183234Ssimon
242183234Ssimon	if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
243183234Ssimon		return 0;
244183234Ssimon	cont = CMS_dataInit(cms, dcont);
245183234Ssimon	if (!cont)
246183234Ssimon		return 0;
247183234Ssimon	r = cms_copy_content(out, cont, flags);
248183234Ssimon	do_free_upto(cont, dcont);
249183234Ssimon	return r;
250183234Ssimon	}
251183234Ssimon
252183234SsimonCMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
253183234Ssimon					const unsigned char *key, size_t keylen,
254183234Ssimon					unsigned int flags)
255183234Ssimon	{
256183234Ssimon	CMS_ContentInfo *cms;
257183234Ssimon	if (!cipher)
258183234Ssimon		{
259183234Ssimon		CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER);
260183234Ssimon		return NULL;
261183234Ssimon		}
262183234Ssimon	cms = CMS_ContentInfo_new();
263183234Ssimon	if (!cms)
264183234Ssimon		return NULL;
265183234Ssimon	if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
266183234Ssimon		return NULL;
267183234Ssimon
268183234Ssimon	if(!(flags & CMS_DETACHED))
269183234Ssimon		{
270183234Ssimon		flags &= ~CMS_STREAM;
271183234Ssimon		CMS_set_detached(cms, 0);
272183234Ssimon		}
273183234Ssimon
274183234Ssimon	if ((flags & (CMS_STREAM|CMS_PARTIAL))
275183234Ssimon		|| CMS_final(cms, in, NULL, flags))
276183234Ssimon		return cms;
277183234Ssimon
278183234Ssimon	CMS_ContentInfo_free(cms);
279183234Ssimon	return NULL;
280183234Ssimon	}
281183234Ssimon
282183234Ssimonstatic int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
283183234Ssimon					X509_STORE *store,
284183234Ssimon					STACK_OF(X509) *certs,
285183234Ssimon					STACK_OF(X509_CRL) *crls,
286183234Ssimon					unsigned int flags)
287183234Ssimon	{
288183234Ssimon	X509_STORE_CTX ctx;
289183234Ssimon	X509 *signer;
290183234Ssimon	int i, j, r = 0;
291183234Ssimon	CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
292183234Ssimon	if (!X509_STORE_CTX_init(&ctx, store, signer, certs))
293183234Ssimon		{
294183234Ssimon		CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
295183234Ssimon						CMS_R_STORE_INIT_ERROR);
296183234Ssimon		goto err;
297183234Ssimon		}
298183234Ssimon	X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_SMIME_SIGN);
299183234Ssimon	if (crls)
300183234Ssimon		X509_STORE_CTX_set0_crls(&ctx, crls);
301183234Ssimon
302183234Ssimon	i = X509_verify_cert(&ctx);
303183234Ssimon	if (i <= 0)
304183234Ssimon		{
305183234Ssimon		j = X509_STORE_CTX_get_error(&ctx);
306183234Ssimon		CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
307183234Ssimon						CMS_R_CERTIFICATE_VERIFY_ERROR);
308183234Ssimon		ERR_add_error_data(2, "Verify error:",
309183234Ssimon					 X509_verify_cert_error_string(j));
310183234Ssimon		goto err;
311183234Ssimon		}
312183234Ssimon	r = 1;
313183234Ssimon	err:
314183234Ssimon	X509_STORE_CTX_cleanup(&ctx);
315183234Ssimon	return r;
316183234Ssimon
317183234Ssimon	}
318183234Ssimon
319183234Ssimonint CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
320183234Ssimon		 X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags)
321183234Ssimon	{
322183234Ssimon	CMS_SignerInfo *si;
323183234Ssimon	STACK_OF(CMS_SignerInfo) *sinfos;
324183234Ssimon	STACK_OF(X509) *cms_certs = NULL;
325183234Ssimon	STACK_OF(X509_CRL) *crls = NULL;
326183234Ssimon	X509 *signer;
327183234Ssimon	int i, scount = 0, ret = 0;
328183234Ssimon	BIO *cmsbio = NULL, *tmpin = NULL;
329183234Ssimon
330183234Ssimon	if (!dcont && !check_content(cms))
331183234Ssimon		return 0;
332183234Ssimon
333183234Ssimon	/* Attempt to find all signer certificates */
334183234Ssimon
335183234Ssimon	sinfos = CMS_get0_SignerInfos(cms);
336183234Ssimon
337183234Ssimon	if (sk_CMS_SignerInfo_num(sinfos) <= 0)
338183234Ssimon		{
339183234Ssimon		CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS);
340183234Ssimon		goto err;
341183234Ssimon		}
342183234Ssimon
343183234Ssimon	for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
344183234Ssimon		{
345183234Ssimon		si = sk_CMS_SignerInfo_value(sinfos, i);
346183234Ssimon		CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
347183234Ssimon		if (signer)
348183234Ssimon			scount++;
349183234Ssimon		}
350183234Ssimon
351183234Ssimon	if (scount != sk_CMS_SignerInfo_num(sinfos))
352183234Ssimon		scount += CMS_set1_signers_certs(cms, certs, flags);
353183234Ssimon
354183234Ssimon	if (scount != sk_CMS_SignerInfo_num(sinfos))
355183234Ssimon		{
356183234Ssimon		CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
357183234Ssimon		goto err;
358183234Ssimon		}
359183234Ssimon
360183234Ssimon	/* Attempt to verify all signers certs */
361183234Ssimon
362183234Ssimon	if (!(flags & CMS_NO_SIGNER_CERT_VERIFY))
363183234Ssimon		{
364183234Ssimon		cms_certs = CMS_get1_certs(cms);
365183234Ssimon		if (!(flags & CMS_NOCRL))
366183234Ssimon			crls = CMS_get1_crls(cms);
367183234Ssimon		for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
368183234Ssimon			{
369183234Ssimon			si = sk_CMS_SignerInfo_value(sinfos, i);
370183234Ssimon			if (!cms_signerinfo_verify_cert(si, store,
371183234Ssimon							cms_certs, crls, flags))
372183234Ssimon				goto err;
373183234Ssimon			}
374183234Ssimon		}
375183234Ssimon
376183234Ssimon	/* Attempt to verify all SignerInfo signed attribute signatures */
377183234Ssimon
378183234Ssimon	if (!(flags & CMS_NO_ATTR_VERIFY))
379183234Ssimon		{
380183234Ssimon		for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
381183234Ssimon			{
382183234Ssimon			si = sk_CMS_SignerInfo_value(sinfos, i);
383183234Ssimon			if (CMS_signed_get_attr_count(si) < 0)
384183234Ssimon				continue;
385183234Ssimon			if (CMS_SignerInfo_verify(si) <= 0)
386183234Ssimon				goto err;
387183234Ssimon			}
388183234Ssimon		}
389183234Ssimon
390183234Ssimon	/* Performance optimization: if the content is a memory BIO then
391183234Ssimon	 * store its contents in a temporary read only memory BIO. This
392183234Ssimon	 * avoids potentially large numbers of slow copies of data which will
393183234Ssimon	 * occur when reading from a read write memory BIO when signatures
394183234Ssimon	 * are calculated.
395183234Ssimon	 */
396183234Ssimon
397183234Ssimon	if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM))
398183234Ssimon		{
399183234Ssimon		char *ptr;
400183234Ssimon		long len;
401183234Ssimon		len = BIO_get_mem_data(dcont, &ptr);
402183234Ssimon		tmpin = BIO_new_mem_buf(ptr, len);
403183234Ssimon		if (tmpin == NULL)
404183234Ssimon			{
405183234Ssimon			CMSerr(CMS_F_CMS_VERIFY,ERR_R_MALLOC_FAILURE);
406183234Ssimon			return 0;
407183234Ssimon			}
408183234Ssimon		}
409183234Ssimon	else
410183234Ssimon		tmpin = dcont;
411183234Ssimon
412183234Ssimon
413183234Ssimon	cmsbio=CMS_dataInit(cms, tmpin);
414183234Ssimon	if (!cmsbio)
415183234Ssimon		goto err;
416183234Ssimon
417183234Ssimon	if (!cms_copy_content(out, cmsbio, flags))
418183234Ssimon		goto err;
419183234Ssimon
420183234Ssimon	if (!(flags & CMS_NO_CONTENT_VERIFY))
421183234Ssimon		{
422183234Ssimon		for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++)
423183234Ssimon			{
424183234Ssimon			si = sk_CMS_SignerInfo_value(sinfos, i);
425183234Ssimon			if (!CMS_SignerInfo_verify_content(si, cmsbio))
426183234Ssimon				{
427183234Ssimon				CMSerr(CMS_F_CMS_VERIFY,
428183234Ssimon					CMS_R_CONTENT_VERIFY_ERROR);
429183234Ssimon				goto err;
430183234Ssimon				}
431183234Ssimon			}
432183234Ssimon		}
433183234Ssimon
434183234Ssimon	ret = 1;
435183234Ssimon
436183234Ssimon	err:
437183234Ssimon
438183234Ssimon	if (dcont && (tmpin == dcont))
439183234Ssimon		do_free_upto(cmsbio, dcont);
440183234Ssimon	else
441183234Ssimon		BIO_free_all(cmsbio);
442183234Ssimon
443183234Ssimon	if (cms_certs)
444183234Ssimon		sk_X509_pop_free(cms_certs, X509_free);
445183234Ssimon	if (crls)
446183234Ssimon		sk_X509_CRL_pop_free(crls, X509_CRL_free);
447183234Ssimon
448183234Ssimon	return ret;
449183234Ssimon	}
450183234Ssimon
451183234Ssimonint CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
452183234Ssimon			STACK_OF(X509) *certs,
453183234Ssimon			X509_STORE *store, unsigned int flags)
454183234Ssimon	{
455183234Ssimon	int r;
456183234Ssimon	r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
457183234Ssimon	if (r <= 0)
458183234Ssimon		return r;
459183234Ssimon	return cms_Receipt_verify(rcms, ocms);
460183234Ssimon	}
461183234Ssimon
462183234SsimonCMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
463183234Ssimon						BIO *data, unsigned int flags)
464183234Ssimon	{
465183234Ssimon	CMS_ContentInfo *cms;
466183234Ssimon	int i;
467183234Ssimon
468183234Ssimon	cms = CMS_ContentInfo_new();
469183234Ssimon	if (!cms || !CMS_SignedData_init(cms))
470183234Ssimon		goto merr;
471183234Ssimon
472183234Ssimon	if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags))
473183234Ssimon		{
474183234Ssimon		CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR);
475183234Ssimon		goto err;
476183234Ssimon		}
477183234Ssimon
478183234Ssimon	for (i = 0; i < sk_X509_num(certs); i++)
479183234Ssimon		{
480183234Ssimon		X509 *x = sk_X509_value(certs, i);
481183234Ssimon		if (!CMS_add1_cert(cms, x))
482183234Ssimon			goto merr;
483183234Ssimon		}
484183234Ssimon
485183234Ssimon	if(!(flags & CMS_DETACHED))
486183234Ssimon		{
487183234Ssimon		flags &= ~CMS_STREAM;
488183234Ssimon		CMS_set_detached(cms, 0);
489183234Ssimon		}
490183234Ssimon
491183234Ssimon	if ((flags & (CMS_STREAM|CMS_PARTIAL))
492183234Ssimon		|| CMS_final(cms, data, NULL, flags))
493183234Ssimon		return cms;
494183234Ssimon	else
495183234Ssimon		goto err;
496183234Ssimon
497183234Ssimon	merr:
498183234Ssimon	CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE);
499183234Ssimon
500183234Ssimon	err:
501183234Ssimon	if (cms)
502183234Ssimon		CMS_ContentInfo_free(cms);
503183234Ssimon	return NULL;
504183234Ssimon	}
505183234Ssimon
506183234SsimonCMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
507183234Ssimon					X509 *signcert, EVP_PKEY *pkey,
508183234Ssimon					STACK_OF(X509) *certs,
509183234Ssimon					unsigned int flags)
510183234Ssimon	{
511183234Ssimon	CMS_SignerInfo *rct_si;
512183234Ssimon	CMS_ContentInfo *cms = NULL;
513183234Ssimon	ASN1_OCTET_STRING **pos, *os;
514183234Ssimon	BIO *rct_cont = NULL;
515183234Ssimon	int r = 0;
516183234Ssimon
517183234Ssimon	flags &= ~CMS_STREAM;
518183234Ssimon	/* Not really detached but avoids content being allocated */
519183234Ssimon	flags |= CMS_PARTIAL|CMS_BINARY|CMS_DETACHED;
520183234Ssimon	if (!pkey || !signcert)
521183234Ssimon		{
522183234Ssimon		CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT);
523183234Ssimon		return NULL;
524183234Ssimon		}
525183234Ssimon
526183234Ssimon	/* Initialize signed data */
527183234Ssimon
528183234Ssimon	cms = CMS_sign(NULL, NULL, certs, NULL, flags);
529183234Ssimon	if (!cms)
530183234Ssimon		goto err;
531183234Ssimon
532183234Ssimon	/* Set inner content type to signed receipt */
533183234Ssimon	if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt)))
534183234Ssimon		goto err;
535183234Ssimon
536183234Ssimon	rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
537183234Ssimon	if (!rct_si)
538183234Ssimon		{
539183234Ssimon		CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR);
540183234Ssimon		goto err;
541183234Ssimon		}
542183234Ssimon
543183234Ssimon	os = cms_encode_Receipt(si);
544183234Ssimon
545183234Ssimon	if (!os)
546183234Ssimon		goto err;
547183234Ssimon
548183234Ssimon	/* Set content to digest */
549183234Ssimon	rct_cont = BIO_new_mem_buf(os->data, os->length);
550183234Ssimon	if (!rct_cont)
551183234Ssimon		goto err;
552183234Ssimon
553183234Ssimon	/* Add msgSigDigest attribute */
554183234Ssimon
555183234Ssimon	if (!cms_msgSigDigest_add1(rct_si, si))
556183234Ssimon		goto err;
557183234Ssimon
558183234Ssimon	/* Finalize structure */
559183234Ssimon	if (!CMS_final(cms, rct_cont, NULL, flags))
560183234Ssimon		goto err;
561183234Ssimon
562183234Ssimon	/* Set embedded content */
563183234Ssimon	pos = CMS_get0_content(cms);
564183234Ssimon	*pos = os;
565183234Ssimon
566183234Ssimon	r = 1;
567183234Ssimon
568183234Ssimon	err:
569183234Ssimon	if (rct_cont)
570183234Ssimon		BIO_free(rct_cont);
571183234Ssimon	if (r)
572183234Ssimon		return cms;
573183234Ssimon	CMS_ContentInfo_free(cms);
574183234Ssimon	return NULL;
575183234Ssimon
576183234Ssimon	}
577183234Ssimon
578183234SsimonCMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
579183234Ssimon				const EVP_CIPHER *cipher, unsigned int flags)
580183234Ssimon	{
581183234Ssimon	CMS_ContentInfo *cms;
582183234Ssimon	int i;
583183234Ssimon	X509 *recip;
584183234Ssimon	cms = CMS_EnvelopedData_create(cipher);
585183234Ssimon	if (!cms)
586183234Ssimon		goto merr;
587183234Ssimon	for (i = 0; i < sk_X509_num(certs); i++)
588183234Ssimon		{
589183234Ssimon		recip = sk_X509_value(certs, i);
590183234Ssimon		if (!CMS_add1_recipient_cert(cms, recip, flags))
591183234Ssimon			{
592183234Ssimon			CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
593183234Ssimon			goto err;
594183234Ssimon			}
595183234Ssimon		}
596183234Ssimon
597183234Ssimon	if(!(flags & CMS_DETACHED))
598183234Ssimon		{
599183234Ssimon		flags &= ~CMS_STREAM;
600183234Ssimon		CMS_set_detached(cms, 0);
601183234Ssimon		}
602183234Ssimon
603183234Ssimon	if ((flags & (CMS_STREAM|CMS_PARTIAL))
604183234Ssimon		|| CMS_final(cms, data, NULL, flags))
605183234Ssimon		return cms;
606183234Ssimon	else
607183234Ssimon		goto err;
608183234Ssimon
609183234Ssimon	merr:
610183234Ssimon	CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
611183234Ssimon	err:
612183234Ssimon	if (cms)
613183234Ssimon		CMS_ContentInfo_free(cms);
614183234Ssimon	return NULL;
615183234Ssimon	}
616183234Ssimon
617183234Ssimonint CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
618183234Ssimon	{
619183234Ssimon	STACK_OF(CMS_RecipientInfo) *ris;
620183234Ssimon	CMS_RecipientInfo *ri;
621183234Ssimon	int i, r;
622183234Ssimon	ris = CMS_get0_RecipientInfos(cms);
623183234Ssimon	for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
624183234Ssimon		{
625183234Ssimon		ri = sk_CMS_RecipientInfo_value(ris, i);
626183234Ssimon		if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
627183234Ssimon				continue;
628183234Ssimon		/* If we have a cert try matching RecipientInfo
629183234Ssimon		 * otherwise try them all.
630183234Ssimon		 */
631183234Ssimon		if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0))
632183234Ssimon			{
633183234Ssimon			CMS_RecipientInfo_set0_pkey(ri, pk);
634183234Ssimon			r = CMS_RecipientInfo_decrypt(cms, ri);
635183234Ssimon			CMS_RecipientInfo_set0_pkey(ri, NULL);
636183234Ssimon			if (r > 0)
637183234Ssimon				return 1;
638183234Ssimon			if (cert)
639183234Ssimon				{
640183234Ssimon				CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY,
641183234Ssimon						CMS_R_DECRYPT_ERROR);
642183234Ssimon				return 0;
643183234Ssimon				}
644183234Ssimon			ERR_clear_error();
645183234Ssimon			}
646183234Ssimon		}
647183234Ssimon
648183234Ssimon	CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
649183234Ssimon	return 0;
650183234Ssimon
651183234Ssimon	}
652183234Ssimon
653183234Ssimonint CMS_decrypt_set1_key(CMS_ContentInfo *cms,
654183234Ssimon				unsigned char *key, size_t keylen,
655183234Ssimon				unsigned char *id, size_t idlen)
656183234Ssimon	{
657183234Ssimon	STACK_OF(CMS_RecipientInfo) *ris;
658183234Ssimon	CMS_RecipientInfo *ri;
659183234Ssimon	int i, r;
660183234Ssimon	ris = CMS_get0_RecipientInfos(cms);
661183234Ssimon	for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
662183234Ssimon		{
663183234Ssimon		ri = sk_CMS_RecipientInfo_value(ris, i);
664183234Ssimon		if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK)
665183234Ssimon				continue;
666183234Ssimon
667183234Ssimon		/* If we have an id try matching RecipientInfo
668183234Ssimon		 * otherwise try them all.
669183234Ssimon		 */
670183234Ssimon		if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0))
671183234Ssimon			{
672183234Ssimon			CMS_RecipientInfo_set0_key(ri, key, keylen);
673183234Ssimon			r = CMS_RecipientInfo_decrypt(cms, ri);
674183234Ssimon			CMS_RecipientInfo_set0_key(ri, NULL, 0);
675183234Ssimon			if (r > 0)
676183234Ssimon				return 1;
677183234Ssimon			if (id)
678183234Ssimon				{
679183234Ssimon				CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY,
680183234Ssimon						CMS_R_DECRYPT_ERROR);
681183234Ssimon				return 0;
682183234Ssimon				}
683183234Ssimon			ERR_clear_error();
684183234Ssimon			}
685183234Ssimon		}
686183234Ssimon
687183234Ssimon	CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT);
688183234Ssimon	return 0;
689183234Ssimon
690183234Ssimon	}
691183234Ssimon
692183234Ssimonint CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
693183234Ssimon				BIO *dcont, BIO *out,
694183234Ssimon				unsigned int flags)
695183234Ssimon	{
696183234Ssimon	int r;
697183234Ssimon	BIO *cont;
698183234Ssimon	if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped)
699183234Ssimon		{
700183234Ssimon		CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
701183234Ssimon		return 0;
702183234Ssimon		}
703183234Ssimon	if (!dcont && !check_content(cms))
704183234Ssimon		return 0;
705183234Ssimon	if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
706183234Ssimon		return 0;
707183234Ssimon
708183234Ssimon	cont = CMS_dataInit(cms, dcont);
709183234Ssimon	if (!cont)
710183234Ssimon		return 0;
711183234Ssimon	r = cms_copy_content(out, cont, flags);
712183234Ssimon	do_free_upto(cont, dcont);
713183234Ssimon	return r;
714183234Ssimon	}
715183234Ssimon
716183234Ssimonint CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
717183234Ssimon	{
718183234Ssimon	BIO *cmsbio;
719183234Ssimon	int ret = 0;
720183234Ssimon	if (!(cmsbio = CMS_dataInit(cms, dcont)))
721183234Ssimon		{
722183234Ssimon		CMSerr(CMS_F_CMS_FINAL,ERR_R_MALLOC_FAILURE);
723183234Ssimon		return 0;
724183234Ssimon		}
725183234Ssimon
726183234Ssimon	SMIME_crlf_copy(data, cmsbio, flags);
727183234Ssimon
728183234Ssimon	(void)BIO_flush(cmsbio);
729183234Ssimon
730183234Ssimon
731183234Ssimon        if (!CMS_dataFinal(cms, cmsbio))
732183234Ssimon		{
733183234Ssimon		CMSerr(CMS_F_CMS_FINAL,CMS_R_CMS_DATAFINAL_ERROR);
734183234Ssimon		goto err;
735183234Ssimon		}
736183234Ssimon
737183234Ssimon	ret = 1;
738183234Ssimon
739183234Ssimon	err:
740183234Ssimon	do_free_upto(cmsbio, dcont);
741183234Ssimon
742183234Ssimon	return ret;
743183234Ssimon
744183234Ssimon	}
745183234Ssimon
746183234Ssimon#ifdef ZLIB
747183234Ssimon
748183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
749183234Ssimon							unsigned int flags)
750183234Ssimon	{
751183234Ssimon	BIO *cont;
752183234Ssimon	int r;
753183234Ssimon	if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData)
754183234Ssimon		{
755183234Ssimon		CMSerr(CMS_F_CMS_UNCOMPRESS,
756183234Ssimon					CMS_R_TYPE_NOT_COMPRESSED_DATA);
757183234Ssimon		return 0;
758183234Ssimon		}
759183234Ssimon
760183234Ssimon	if (!dcont && !check_content(cms))
761183234Ssimon		return 0;
762183234Ssimon
763183234Ssimon	cont = CMS_dataInit(cms, dcont);
764183234Ssimon	if (!cont)
765183234Ssimon		return 0;
766183234Ssimon	r = cms_copy_content(out, cont, flags);
767183234Ssimon	do_free_upto(cont, dcont);
768183234Ssimon	return r;
769183234Ssimon	}
770183234Ssimon
771183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
772183234Ssimon	{
773183234Ssimon	CMS_ContentInfo *cms;
774183234Ssimon	if (comp_nid <= 0)
775183234Ssimon		comp_nid = NID_zlib_compression;
776183234Ssimon	cms = cms_CompressedData_create(comp_nid);
777183234Ssimon	if (!cms)
778183234Ssimon		return NULL;
779183234Ssimon
780183234Ssimon	if(!(flags & CMS_DETACHED))
781183234Ssimon		{
782183234Ssimon		flags &= ~CMS_STREAM;
783183234Ssimon		CMS_set_detached(cms, 0);
784183234Ssimon		}
785183234Ssimon
786183234Ssimon	if (CMS_final(cms, in, NULL, flags))
787183234Ssimon		return cms;
788183234Ssimon
789183234Ssimon	CMS_ContentInfo_free(cms);
790183234Ssimon	return NULL;
791183234Ssimon	}
792183234Ssimon
793183234Ssimon#else
794183234Ssimon
795183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
796183234Ssimon							unsigned int flags)
797183234Ssimon	{
798183234Ssimon	CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
799183234Ssimon	return 0;
800183234Ssimon	}
801183234Ssimon
802183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
803183234Ssimon	{
804183234Ssimon	CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
805183234Ssimon	return NULL;
806183234Ssimon	}
807183234Ssimon
808183234Ssimon#endif
809