159191Skris/* pk7_smime.c */
2194206Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3160814Ssimon * project.
459191Skris */
559191Skris/* ====================================================================
6160814Ssimon * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
759191Skris *
859191Skris * Redistribution and use in source and binary forms, with or without
959191Skris * modification, are permitted provided that the following conditions
1059191Skris * are met:
1159191Skris *
1259191Skris * 1. Redistributions of source code must retain the above copyright
1359191Skris *    notice, this list of conditions and the following disclaimer.
1459191Skris *
1559191Skris * 2. Redistributions in binary form must reproduce the above copyright
1659191Skris *    notice, this list of conditions and the following disclaimer in
1759191Skris *    the documentation and/or other materials provided with the
1859191Skris *    distribution.
1959191Skris *
2059191Skris * 3. All advertising materials mentioning features or use of this
2159191Skris *    software must display the following acknowledgment:
2259191Skris *    "This product includes software developed by the OpenSSL Project
2359191Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2459191Skris *
2559191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2659191Skris *    endorse or promote products derived from this software without
2759191Skris *    prior written permission. For written permission, please contact
2859191Skris *    licensing@OpenSSL.org.
2959191Skris *
3059191Skris * 5. Products derived from this software may not be called "OpenSSL"
3159191Skris *    nor may "OpenSSL" appear in their names without prior written
3259191Skris *    permission of the OpenSSL Project.
3359191Skris *
3459191Skris * 6. Redistributions of any form whatsoever must retain the following
3559191Skris *    acknowledgment:
3659191Skris *    "This product includes software developed by the OpenSSL Project
3759191Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3859191Skris *
3959191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4059191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4159191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4259191Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4359191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4459191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4559191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4659191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4759191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4859191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4959191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5059191Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5159191Skris * ====================================================================
5259191Skris *
5359191Skris * This product includes cryptographic software written by Eric Young
5459191Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5559191Skris * Hudson (tjh@cryptsoft.com).
5659191Skris *
5759191Skris */
5859191Skris
5959191Skris/* Simple PKCS#7 processing functions */
6059191Skris
6159191Skris#include <stdio.h>
6259191Skris#include "cryptlib.h"
6359191Skris#include <openssl/x509.h>
6459191Skris#include <openssl/x509v3.h>
6559191Skris
66238405Sjkimstatic int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
67238405Sjkim
6859191SkrisPKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
6968651Skris		  BIO *data, int flags)
7059191Skris{
71238405Sjkim	PKCS7 *p7;
7259191Skris	int i;
7359191Skris
74238405Sjkim	if(!(p7 = PKCS7_new()))
75238405Sjkim		{
7659191Skris		PKCS7err(PKCS7_F_PKCS7_SIGN,ERR_R_MALLOC_FAILURE);
7759191Skris		return NULL;
78238405Sjkim		}
7959191Skris
80167612Ssimon	if (!PKCS7_set_type(p7, NID_pkcs7_signed))
81167612Ssimon		goto err;
8259191Skris
83167612Ssimon	if (!PKCS7_content_new(p7, NID_pkcs7_data))
84167612Ssimon		goto err;
8559191Skris
86238405Sjkim    	if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags))
87238405Sjkim		{
88238405Sjkim		PKCS7err(PKCS7_F_PKCS7_SIGN,PKCS7_R_PKCS7_ADD_SIGNER_ERROR);
89167612Ssimon		goto err;
90238405Sjkim		}
9159191Skris
92238405Sjkim	if(!(flags & PKCS7_NOCERTS))
93238405Sjkim		{
94238405Sjkim		for(i = 0; i < sk_X509_num(certs); i++)
95238405Sjkim			{
96167612Ssimon			if (!PKCS7_add_certificate(p7, sk_X509_value(certs, i)))
97167612Ssimon				goto err;
98238405Sjkim			}
99238405Sjkim		}
10059191Skris
101238405Sjkim	if(flags & PKCS7_DETACHED)
102238405Sjkim		PKCS7_set_detached(p7, 1);
103238405Sjkim
104238405Sjkim	if (flags & (PKCS7_STREAM|PKCS7_PARTIAL))
105238405Sjkim		return p7;
106238405Sjkim
107238405Sjkim	if (PKCS7_final(p7, data, flags))
108238405Sjkim		return p7;
109238405Sjkim
110238405Sjkim	err:
111238405Sjkim	PKCS7_free(p7);
112238405Sjkim	return NULL;
113238405Sjkim}
114238405Sjkim
115238405Sjkimint PKCS7_final(PKCS7 *p7, BIO *data, int flags)
116238405Sjkim	{
117238405Sjkim	BIO *p7bio;
118238405Sjkim	int ret = 0;
119238405Sjkim	if (!(p7bio = PKCS7_dataInit(p7, NULL)))
12068651Skris		{
121238405Sjkim		PKCS7err(PKCS7_F_PKCS7_FINAL,ERR_R_MALLOC_FAILURE);
122238405Sjkim		return 0;
12359191Skris		}
124238405Sjkim
125238405Sjkim	SMIME_crlf_copy(data, p7bio, flags);
126238405Sjkim
127238405Sjkim	(void)BIO_flush(p7bio);
128238405Sjkim
129238405Sjkim
130238405Sjkim        if (!PKCS7_dataFinal(p7,p7bio))
131238405Sjkim		{
132238405Sjkim		PKCS7err(PKCS7_F_PKCS7_FINAL,PKCS7_R_PKCS7_DATASIGN);
133238405Sjkim		goto err;
13468651Skris		}
13559191Skris
136238405Sjkim	ret = 1;
137162911Ssimon
138238405Sjkim	err:
139238405Sjkim	BIO_free_all(p7bio);
140160814Ssimon
141238405Sjkim	return ret;
142162911Ssimon
143160814Ssimon	}
144160814Ssimon
145238405Sjkim/* Check to see if a cipher exists and if so add S/MIME capabilities */
146160814Ssimon
147238405Sjkimstatic int add_cipher_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
148238405Sjkim	{
149238405Sjkim	if (EVP_get_cipherbynid(nid))
150238405Sjkim		return PKCS7_simple_smimecap(sk, nid, arg);
151238405Sjkim	return 1;
152238405Sjkim	}
15359191Skris
154238405Sjkimstatic int add_digest_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
155238405Sjkim	{
156238405Sjkim	if (EVP_get_digestbynid(nid))
157238405Sjkim		return PKCS7_simple_smimecap(sk, nid, arg);
158238405Sjkim	return 1;
15959191Skris	}
16059191Skris
161238405SjkimPKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert,
162238405Sjkim					EVP_PKEY *pkey, const EVP_MD *md,
163238405Sjkim					int flags)
164238405Sjkim	{
165238405Sjkim	PKCS7_SIGNER_INFO *si = NULL;
166238405Sjkim	STACK_OF(X509_ALGOR) *smcap = NULL;
167238405Sjkim	if(!X509_check_private_key(signcert, pkey))
168238405Sjkim		{
169238405Sjkim		PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER,
170238405Sjkim			PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
171238405Sjkim                return NULL;
172238405Sjkim		}
173238405Sjkim
174238405Sjkim    	if (!(si = PKCS7_add_signature(p7,signcert,pkey, md)))
175238405Sjkim		{
176238405Sjkim		PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER,
177238405Sjkim				PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR);
178238405Sjkim		return NULL;
179238405Sjkim		}
180238405Sjkim
181238405Sjkim	if(!(flags & PKCS7_NOCERTS))
182238405Sjkim		{
183238405Sjkim		if (!PKCS7_add_certificate(p7, signcert))
184238405Sjkim			goto err;
185238405Sjkim		}
186238405Sjkim
187238405Sjkim	if(!(flags & PKCS7_NOATTR))
188238405Sjkim		{
189238405Sjkim		if (!PKCS7_add_attrib_content_type(si, NULL))
190238405Sjkim			goto err;
191238405Sjkim		/* Add SMIMECapabilities */
192238405Sjkim		if(!(flags & PKCS7_NOSMIMECAP))
193238405Sjkim			{
194238405Sjkim			if(!(smcap = sk_X509_ALGOR_new_null()))
195238405Sjkim				{
196238405Sjkim				PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER,
197238405Sjkim					ERR_R_MALLOC_FAILURE);
198238405Sjkim				goto err;
199238405Sjkim				}
200238405Sjkim			if (!add_cipher_smcap(smcap, NID_aes_256_cbc, -1)
201238405Sjkim			|| !add_digest_smcap(smcap, NID_id_GostR3411_94, -1)
202238405Sjkim			|| !add_cipher_smcap(smcap, NID_id_Gost28147_89, -1)
203238405Sjkim				|| !add_cipher_smcap(smcap, NID_aes_192_cbc, -1)
204238405Sjkim				|| !add_cipher_smcap(smcap, NID_aes_128_cbc, -1)
205238405Sjkim			|| !add_cipher_smcap(smcap, NID_des_ede3_cbc, -1)
206238405Sjkim				|| !add_cipher_smcap(smcap, NID_rc2_cbc, 128)
207238405Sjkim				|| !add_cipher_smcap(smcap, NID_rc2_cbc, 64)
208238405Sjkim				|| !add_cipher_smcap(smcap, NID_des_cbc, -1)
209238405Sjkim				|| !add_cipher_smcap(smcap, NID_rc2_cbc, 40)
210238405Sjkim				|| !PKCS7_add_attrib_smimecap (si, smcap))
211238405Sjkim				goto err;
212238405Sjkim			sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
213238405Sjkim			smcap = NULL;
214238405Sjkim			}
215238405Sjkim		if (flags & PKCS7_REUSE_DIGEST)
216238405Sjkim			{
217238405Sjkim			if (!pkcs7_copy_existing_digest(p7, si))
218238405Sjkim				goto err;
219238405Sjkim			if (!(flags & PKCS7_PARTIAL) &&
220238405Sjkim					!PKCS7_SIGNER_INFO_sign(si))
221238405Sjkim				goto err;
222238405Sjkim			}
223238405Sjkim		}
224238405Sjkim	return si;
225238405Sjkim	err:
226238405Sjkim	if (smcap)
227238405Sjkim		sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
228167612Ssimon	return NULL;
229238405Sjkim	}
23059191Skris
231238405Sjkim/* Search for a digest matching SignerInfo digest type and if found
232238405Sjkim * copy across.
233238405Sjkim */
234238405Sjkim
235238405Sjkimstatic int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si)
236238405Sjkim	{
237238405Sjkim	int i;
238238405Sjkim	STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
239238405Sjkim	PKCS7_SIGNER_INFO *sitmp;
240238405Sjkim	ASN1_OCTET_STRING *osdig = NULL;
241238405Sjkim	sinfos = PKCS7_get_signer_info(p7);
242238405Sjkim	for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
243238405Sjkim		{
244238405Sjkim		sitmp = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
245238405Sjkim		if (si == sitmp)
246238405Sjkim			break;
247238405Sjkim		if (sk_X509_ATTRIBUTE_num(sitmp->auth_attr) <= 0)
248238405Sjkim			continue;
249238405Sjkim		if (!OBJ_cmp(si->digest_alg->algorithm,
250238405Sjkim				sitmp->digest_alg->algorithm))
251238405Sjkim			{
252238405Sjkim			osdig = PKCS7_digest_from_attributes(sitmp->auth_attr);
253238405Sjkim			break;
254238405Sjkim			}
255238405Sjkim
256238405Sjkim		}
257238405Sjkim
258238405Sjkim	if (osdig)
259238405Sjkim		return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length);
260238405Sjkim
261238405Sjkim	PKCS7err(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST,
262238405Sjkim			PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND);
263238405Sjkim	return 0;
264238405Sjkim	}
265238405Sjkim
26659191Skrisint PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
26759191Skris					BIO *indata, BIO *out, int flags)
26859191Skris{
26959191Skris	STACK_OF(X509) *signers;
27059191Skris	X509 *signer;
27159191Skris	STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
27259191Skris	PKCS7_SIGNER_INFO *si;
27359191Skris	X509_STORE_CTX cert_ctx;
27459191Skris	char buf[4096];
27576866Skris	int i, j=0, k, ret = 0;
27659191Skris	BIO *p7bio;
277160814Ssimon	BIO *tmpin, *tmpout;
27859191Skris
27959191Skris	if(!p7) {
28059191Skris		PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_INVALID_NULL_POINTER);
28159191Skris		return 0;
28259191Skris	}
28359191Skris
28459191Skris	if(!PKCS7_type_is_signed(p7)) {
28559191Skris		PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_WRONG_CONTENT_TYPE);
28659191Skris		return 0;
28759191Skris	}
28859191Skris
28959191Skris	/* Check for no data and no content: no data to verify signature */
29059191Skris	if(PKCS7_get_detached(p7) && !indata) {
29159191Skris		PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_NO_CONTENT);
29259191Skris		return 0;
29359191Skris	}
29468651Skris#if 0
29568651Skris	/* NB: this test commented out because some versions of Netscape
29668651Skris	 * illegally include zero length content when signing data.
29768651Skris	 */
29859191Skris
29959191Skris	/* Check for data and content: two sets of data */
30059191Skris	if(!PKCS7_get_detached(p7) && indata) {
30159191Skris				PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_CONTENT_AND_DATA_PRESENT);
30259191Skris		return 0;
30359191Skris	}
30468651Skris#endif
30559191Skris
30659191Skris	sinfos = PKCS7_get_signer_info(p7);
30759191Skris
30859191Skris	if(!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) {
30959191Skris		PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_NO_SIGNATURES_ON_DATA);
31059191Skris		return 0;
31159191Skris	}
31259191Skris
31359191Skris
31459191Skris	signers = PKCS7_get0_signers(p7, certs, flags);
31559191Skris
31659191Skris	if(!signers) return 0;
31759191Skris
31859191Skris	/* Now verify the certificates */
31959191Skris
32068651Skris	if (!(flags & PKCS7_NOVERIFY)) for (k = 0; k < sk_X509_num(signers); k++) {
32168651Skris		signer = sk_X509_value (signers, k);
32259191Skris		if (!(flags & PKCS7_NOCHAIN)) {
323109998Smarkm			if(!X509_STORE_CTX_init(&cert_ctx, store, signer,
324109998Smarkm							p7->d.sign->cert))
325109998Smarkm				{
326109998Smarkm				PKCS7err(PKCS7_F_PKCS7_VERIFY,ERR_R_X509_LIB);
327109998Smarkm				sk_X509_free(signers);
328109998Smarkm				return 0;
329109998Smarkm				}
330194206Ssimon			X509_STORE_CTX_set_default(&cert_ctx, "smime_sign");
331109998Smarkm		} else if(!X509_STORE_CTX_init (&cert_ctx, store, signer, NULL)) {
332109998Smarkm			PKCS7err(PKCS7_F_PKCS7_VERIFY,ERR_R_X509_LIB);
333109998Smarkm			sk_X509_free(signers);
334109998Smarkm			return 0;
335109998Smarkm		}
336160814Ssimon		if (!(flags & PKCS7_NOCRL))
337160814Ssimon			X509_STORE_CTX_set0_crls(&cert_ctx, p7->d.sign->crl);
33859191Skris		i = X509_verify_cert(&cert_ctx);
33959191Skris		if (i <= 0) j = X509_STORE_CTX_get_error(&cert_ctx);
34059191Skris		X509_STORE_CTX_cleanup(&cert_ctx);
34159191Skris		if (i <= 0) {
34259191Skris			PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_CERTIFICATE_VERIFY_ERROR);
34359191Skris			ERR_add_error_data(2, "Verify error:",
34459191Skris					 X509_verify_cert_error_string(j));
34559191Skris			sk_X509_free(signers);
34659191Skris			return 0;
34759191Skris		}
34859191Skris		/* Check for revocation status here */
34959191Skris	}
35059191Skris
351160814Ssimon	/* Performance optimization: if the content is a memory BIO then
352160814Ssimon	 * store its contents in a temporary read only memory BIO. This
353160814Ssimon	 * avoids potentially large numbers of slow copies of data which will
354160814Ssimon	 * occur when reading from a read write memory BIO when signatures
355160814Ssimon	 * are calculated.
356160814Ssimon	 */
35759191Skris
358160814Ssimon	if (indata && (BIO_method_type(indata) == BIO_TYPE_MEM))
359160814Ssimon		{
360160814Ssimon		char *ptr;
361160814Ssimon		long len;
362160814Ssimon		len = BIO_get_mem_data(indata, &ptr);
363160814Ssimon		tmpin = BIO_new_mem_buf(ptr, len);
364160814Ssimon		if (tmpin == NULL)
365160814Ssimon			{
366160814Ssimon			PKCS7err(PKCS7_F_PKCS7_VERIFY,ERR_R_MALLOC_FAILURE);
367160814Ssimon			return 0;
368160814Ssimon			}
369160814Ssimon		}
370160814Ssimon	else
371160814Ssimon		tmpin = indata;
372160814Ssimon
373160814Ssimon
374167612Ssimon	if (!(p7bio=PKCS7_dataInit(p7,tmpin)))
375167612Ssimon		goto err;
376160814Ssimon
37759191Skris	if(flags & PKCS7_TEXT) {
37859191Skris		if(!(tmpout = BIO_new(BIO_s_mem()))) {
37959191Skris			PKCS7err(PKCS7_F_PKCS7_VERIFY,ERR_R_MALLOC_FAILURE);
38059191Skris			goto err;
38159191Skris		}
382194206Ssimon		BIO_set_mem_eof_return(tmpout, 0);
38359191Skris	} else tmpout = out;
38459191Skris
38559191Skris	/* We now have to 'read' from p7bio to calculate digests etc. */
38659191Skris	for (;;)
38759191Skris	{
38859191Skris		i=BIO_read(p7bio,buf,sizeof(buf));
38959191Skris		if (i <= 0) break;
39059191Skris		if (tmpout) BIO_write(tmpout, buf, i);
39159191Skris	}
39259191Skris
39359191Skris	if(flags & PKCS7_TEXT) {
39459191Skris		if(!SMIME_text(tmpout, out)) {
39559191Skris			PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_SMIME_TEXT_ERROR);
39659191Skris			BIO_free(tmpout);
39759191Skris			goto err;
39859191Skris		}
39959191Skris		BIO_free(tmpout);
40059191Skris	}
40159191Skris
40259191Skris	/* Now Verify All Signatures */
40359191Skris	if (!(flags & PKCS7_NOSIGS))
40459191Skris	    for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
40559191Skris		{
40659191Skris		si=sk_PKCS7_SIGNER_INFO_value(sinfos,i);
40759191Skris		signer = sk_X509_value (signers, i);
40859191Skris		j=PKCS7_signatureVerify(p7bio,p7,si, signer);
40959191Skris		if (j <= 0) {
41059191Skris			PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_SIGNATURE_FAILURE);
41159191Skris			goto err;
41259191Skris		}
41359191Skris	}
41459191Skris
41576866Skris	ret = 1;
41659191Skris
41759191Skris	err:
418160814Ssimon
419160814Ssimon	if (tmpin == indata)
420160814Ssimon		{
421160814Ssimon		if (indata) BIO_pop(p7bio);
422160814Ssimon		}
423160814Ssimon	BIO_free_all(p7bio);
42459191Skris
42559191Skris	sk_X509_free(signers);
42659191Skris
42776866Skris	return ret;
42859191Skris}
42959191Skris
43059191SkrisSTACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags)
43159191Skris{
43259191Skris	STACK_OF(X509) *signers;
43359191Skris	STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
43459191Skris	PKCS7_SIGNER_INFO *si;
43559191Skris	PKCS7_ISSUER_AND_SERIAL *ias;
43659191Skris	X509 *signer;
43759191Skris	int i;
43859191Skris
43959191Skris	if(!p7) {
44059191Skris		PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,PKCS7_R_INVALID_NULL_POINTER);
44159191Skris		return NULL;
44259191Skris	}
44359191Skris
44459191Skris	if(!PKCS7_type_is_signed(p7)) {
44559191Skris		PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,PKCS7_R_WRONG_CONTENT_TYPE);
44659191Skris		return NULL;
44759191Skris	}
44859191Skris
44959191Skris	/* Collect all the signers together */
45059191Skris
45159191Skris	sinfos = PKCS7_get_signer_info(p7);
45259191Skris
45359191Skris	if(sk_PKCS7_SIGNER_INFO_num(sinfos) <= 0) {
45459191Skris		PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,PKCS7_R_NO_SIGNERS);
455238405Sjkim		return 0;
45659191Skris	}
45759191Skris
458160814Ssimon	if(!(signers = sk_X509_new_null())) {
459160814Ssimon		PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,ERR_R_MALLOC_FAILURE);
460160814Ssimon		return NULL;
461160814Ssimon	}
462160814Ssimon
46359191Skris	for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
46459191Skris	{
46559191Skris	    si = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
46659191Skris	    ias = si->issuer_and_serial;
46759191Skris	    signer = NULL;
46859191Skris		/* If any certificates passed they take priority */
46959191Skris	    if (certs) signer = X509_find_by_issuer_and_serial (certs,
47059191Skris					 	ias->issuer, ias->serial);
47159191Skris	    if (!signer && !(flags & PKCS7_NOINTERN)
47259191Skris			&& p7->d.sign->cert) signer =
47359191Skris		              X509_find_by_issuer_and_serial (p7->d.sign->cert,
47459191Skris					      	ias->issuer, ias->serial);
47559191Skris	    if (!signer) {
47659191Skris			PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND);
47759191Skris			sk_X509_free(signers);
478238405Sjkim			return 0;
47959191Skris	    }
48059191Skris
481167612Ssimon	    if (!sk_X509_push(signers, signer)) {
482238405Sjkim		sk_X509_free(signers);
483238405Sjkim		return NULL;
484167612Ssimon	    }
48559191Skris	}
48659191Skris	return signers;
48759191Skris}
48859191Skris
48959191Skris
49059191Skris/* Build a complete PKCS#7 enveloped data */
49159191Skris
492109998SmarkmPKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
49359191Skris								int flags)
49459191Skris{
49559191Skris	PKCS7 *p7;
49659191Skris	BIO *p7bio = NULL;
49759191Skris	int i;
49859191Skris	X509 *x509;
49959191Skris	if(!(p7 = PKCS7_new())) {
50059191Skris		PKCS7err(PKCS7_F_PKCS7_ENCRYPT,ERR_R_MALLOC_FAILURE);
50159191Skris		return NULL;
50259191Skris	}
50359191Skris
504167612Ssimon	if (!PKCS7_set_type(p7, NID_pkcs7_enveloped))
505167612Ssimon		goto err;
506238405Sjkim	if (!PKCS7_set_cipher(p7, cipher)) {
50759191Skris		PKCS7err(PKCS7_F_PKCS7_ENCRYPT,PKCS7_R_ERROR_SETTING_CIPHER);
50859191Skris		goto err;
50959191Skris	}
51059191Skris
51159191Skris	for(i = 0; i < sk_X509_num(certs); i++) {
51259191Skris		x509 = sk_X509_value(certs, i);
51359191Skris		if(!PKCS7_add_recipient(p7, x509)) {
51459191Skris			PKCS7err(PKCS7_F_PKCS7_ENCRYPT,
51559191Skris					PKCS7_R_ERROR_ADDING_RECIPIENT);
51659191Skris			goto err;
51759191Skris		}
51859191Skris	}
51959191Skris
520238405Sjkim	if (flags & PKCS7_STREAM)
521238405Sjkim		return p7;
52259191Skris
523238405Sjkim	if (PKCS7_final(p7, in, flags))
524238405Sjkim		return p7;
52559191Skris
52659191Skris	err:
52759191Skris
528167612Ssimon	BIO_free_all(p7bio);
52959191Skris	PKCS7_free(p7);
53059191Skris	return NULL;
53159191Skris
53259191Skris}
53359191Skris
53459191Skrisint PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags)
53559191Skris{
53659191Skris	BIO *tmpmem;
53759191Skris	int ret, i;
53859191Skris	char buf[4096];
53959191Skris
54059191Skris	if(!p7) {
54159191Skris		PKCS7err(PKCS7_F_PKCS7_DECRYPT,PKCS7_R_INVALID_NULL_POINTER);
54259191Skris		return 0;
54359191Skris	}
54459191Skris
54559191Skris	if(!PKCS7_type_is_enveloped(p7)) {
54659191Skris		PKCS7err(PKCS7_F_PKCS7_DECRYPT,PKCS7_R_WRONG_CONTENT_TYPE);
54759191Skris		return 0;
54859191Skris	}
54959191Skris
550160814Ssimon	if(cert && !X509_check_private_key(cert, pkey)) {
55159191Skris		PKCS7err(PKCS7_F_PKCS7_DECRYPT,
55259191Skris				PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
55359191Skris		return 0;
55459191Skris	}
55559191Skris
55659191Skris	if(!(tmpmem = PKCS7_dataDecode(p7, pkey, NULL, cert))) {
55759191Skris		PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_DECRYPT_ERROR);
55859191Skris		return 0;
55959191Skris	}
56059191Skris
56159191Skris	if (flags & PKCS7_TEXT) {
56259191Skris		BIO *tmpbuf, *bread;
56359191Skris		/* Encrypt BIOs can't do BIO_gets() so add a buffer BIO */
56459191Skris		if(!(tmpbuf = BIO_new(BIO_f_buffer()))) {
56559191Skris			PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE);
566167612Ssimon			BIO_free_all(tmpmem);
56759191Skris			return 0;
56859191Skris		}
56959191Skris		if(!(bread = BIO_push(tmpbuf, tmpmem))) {
57059191Skris			PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE);
571167612Ssimon			BIO_free_all(tmpbuf);
572167612Ssimon			BIO_free_all(tmpmem);
57359191Skris			return 0;
57459191Skris		}
57559191Skris		ret = SMIME_text(bread, data);
576237657Sjkim		if (ret > 0 && BIO_method_type(tmpmem) == BIO_TYPE_CIPHER)
577237657Sjkim			{
578237657Sjkim			if (!BIO_get_cipher_status(tmpmem))
579237657Sjkim				ret = 0;
580237657Sjkim			}
58159191Skris		BIO_free_all(bread);
58259191Skris		return ret;
58359191Skris	} else {
58459191Skris		for(;;) {
58559191Skris			i = BIO_read(tmpmem, buf, sizeof(buf));
586237657Sjkim			if(i <= 0)
587237657Sjkim				{
588237657Sjkim				ret = 1;
589237657Sjkim				if (BIO_method_type(tmpmem) == BIO_TYPE_CIPHER)
590237657Sjkim					{
591237657Sjkim					if (!BIO_get_cipher_status(tmpmem))
592237657Sjkim						ret = 0;
593237657Sjkim					}
594237657Sjkim
595237657Sjkim				break;
596237657Sjkim				}
597237657Sjkim			if (BIO_write(data, buf, i) != i)
598237657Sjkim				{
599237657Sjkim				ret = 0;
600237657Sjkim				break;
601237657Sjkim				}
60259191Skris		}
60359191Skris		BIO_free_all(tmpmem);
604237657Sjkim		return ret;
60559191Skris	}
60659191Skris}
607