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