159191Skris/* pk7_smime.c */ 2280304Sjkim/* 3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4160814Ssimon * project. 559191Skris */ 659191Skris/* ==================================================================== 7160814Ssimon * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. 859191Skris * 959191Skris * Redistribution and use in source and binary forms, with or without 1059191Skris * modification, are permitted provided that the following conditions 1159191Skris * are met: 1259191Skris * 1359191Skris * 1. Redistributions of source code must retain the above copyright 14280304Sjkim * notice, this list of conditions and the following disclaimer. 1559191Skris * 1659191Skris * 2. Redistributions in binary form must reproduce the above copyright 1759191Skris * notice, this list of conditions and the following disclaimer in 1859191Skris * the documentation and/or other materials provided with the 1959191Skris * distribution. 2059191Skris * 2159191Skris * 3. All advertising materials mentioning features or use of this 2259191Skris * software must display the following acknowledgment: 2359191Skris * "This product includes software developed by the OpenSSL Project 2459191Skris * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 2559191Skris * 2659191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 2759191Skris * endorse or promote products derived from this software without 2859191Skris * prior written permission. For written permission, please contact 2959191Skris * licensing@OpenSSL.org. 3059191Skris * 3159191Skris * 5. Products derived from this software may not be called "OpenSSL" 3259191Skris * nor may "OpenSSL" appear in their names without prior written 3359191Skris * permission of the OpenSSL Project. 3459191Skris * 3559191Skris * 6. Redistributions of any form whatsoever must retain the following 3659191Skris * acknowledgment: 3759191Skris * "This product includes software developed by the OpenSSL Project 3859191Skris * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 3959191Skris * 4059191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 4159191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4259191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4359191Skris * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 4459191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4559191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4659191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4759191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4859191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4959191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5059191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 5159191Skris * OF THE POSSIBILITY OF SUCH DAMAGE. 5259191Skris * ==================================================================== 5359191Skris * 5459191Skris * This product includes cryptographic software written by Eric Young 5559191Skris * (eay@cryptsoft.com). This product includes software written by Tim 5659191Skris * Hudson (tjh@cryptsoft.com). 5759191Skris * 5859191Skris */ 5959191Skris 6059191Skris/* Simple PKCS#7 processing functions */ 6159191Skris 6259191Skris#include <stdio.h> 6359191Skris#include "cryptlib.h" 6459191Skris#include <openssl/x509.h> 6559191Skris#include <openssl/x509v3.h> 6659191Skris 67238405Sjkimstatic int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si); 68238405Sjkim 6959191SkrisPKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, 70280304Sjkim BIO *data, int flags) 7159191Skris{ 72280304Sjkim PKCS7 *p7; 73280304Sjkim int i; 7459191Skris 75280304Sjkim if (!(p7 = PKCS7_new())) { 76280304Sjkim PKCS7err(PKCS7_F_PKCS7_SIGN, ERR_R_MALLOC_FAILURE); 77280304Sjkim return NULL; 78280304Sjkim } 7959191Skris 80280304Sjkim if (!PKCS7_set_type(p7, NID_pkcs7_signed)) 81280304Sjkim goto err; 8259191Skris 83280304Sjkim if (!PKCS7_content_new(p7, NID_pkcs7_data)) 84280304Sjkim goto err; 8559191Skris 86280304Sjkim if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags)) { 87280304Sjkim PKCS7err(PKCS7_F_PKCS7_SIGN, PKCS7_R_PKCS7_ADD_SIGNER_ERROR); 88280304Sjkim goto err; 89280304Sjkim } 9059191Skris 91280304Sjkim if (!(flags & PKCS7_NOCERTS)) { 92280304Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 93280304Sjkim if (!PKCS7_add_certificate(p7, sk_X509_value(certs, i))) 94280304Sjkim goto err; 95280304Sjkim } 96280304Sjkim } 9759191Skris 98280304Sjkim if (flags & PKCS7_DETACHED) 99280304Sjkim PKCS7_set_detached(p7, 1); 100238405Sjkim 101280304Sjkim if (flags & (PKCS7_STREAM | PKCS7_PARTIAL)) 102280304Sjkim return p7; 103238405Sjkim 104280304Sjkim if (PKCS7_final(p7, data, flags)) 105280304Sjkim return p7; 106238405Sjkim 107280304Sjkim err: 108280304Sjkim PKCS7_free(p7); 109280304Sjkim return NULL; 110238405Sjkim} 111238405Sjkim 112238405Sjkimint PKCS7_final(PKCS7 *p7, BIO *data, int flags) 113280304Sjkim{ 114280304Sjkim BIO *p7bio; 115280304Sjkim int ret = 0; 116280304Sjkim if (!(p7bio = PKCS7_dataInit(p7, NULL))) { 117280304Sjkim PKCS7err(PKCS7_F_PKCS7_FINAL, ERR_R_MALLOC_FAILURE); 118280304Sjkim return 0; 119280304Sjkim } 120238405Sjkim 121280304Sjkim SMIME_crlf_copy(data, p7bio, flags); 122238405Sjkim 123280304Sjkim (void)BIO_flush(p7bio); 124238405Sjkim 125280304Sjkim if (!PKCS7_dataFinal(p7, p7bio)) { 126280304Sjkim PKCS7err(PKCS7_F_PKCS7_FINAL, PKCS7_R_PKCS7_DATASIGN); 127280304Sjkim goto err; 128280304Sjkim } 129238405Sjkim 130280304Sjkim ret = 1; 13159191Skris 132280304Sjkim err: 133280304Sjkim BIO_free_all(p7bio); 134162911Ssimon 135280304Sjkim return ret; 136160814Ssimon 137280304Sjkim} 138162911Ssimon 139238405Sjkim/* Check to see if a cipher exists and if so add S/MIME capabilities */ 140160814Ssimon 141238405Sjkimstatic int add_cipher_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg) 142280304Sjkim{ 143280304Sjkim if (EVP_get_cipherbynid(nid)) 144280304Sjkim return PKCS7_simple_smimecap(sk, nid, arg); 145280304Sjkim return 1; 146280304Sjkim} 14759191Skris 148238405Sjkimstatic int add_digest_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg) 149280304Sjkim{ 150280304Sjkim if (EVP_get_digestbynid(nid)) 151280304Sjkim return PKCS7_simple_smimecap(sk, nid, arg); 152280304Sjkim return 1; 153280304Sjkim} 15459191Skris 155238405SjkimPKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert, 156280304Sjkim EVP_PKEY *pkey, const EVP_MD *md, 157280304Sjkim int flags) 158280304Sjkim{ 159280304Sjkim PKCS7_SIGNER_INFO *si = NULL; 160280304Sjkim STACK_OF(X509_ALGOR) *smcap = NULL; 161280304Sjkim if (!X509_check_private_key(signcert, pkey)) { 162280304Sjkim PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER, 163280304Sjkim PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); 164280304Sjkim return NULL; 165280304Sjkim } 166238405Sjkim 167280304Sjkim if (!(si = PKCS7_add_signature(p7, signcert, pkey, md))) { 168280304Sjkim PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER, 169280304Sjkim PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR); 170280304Sjkim return NULL; 171280304Sjkim } 172238405Sjkim 173280304Sjkim if (!(flags & PKCS7_NOCERTS)) { 174280304Sjkim if (!PKCS7_add_certificate(p7, signcert)) 175280304Sjkim goto err; 176280304Sjkim } 177238405Sjkim 178280304Sjkim if (!(flags & PKCS7_NOATTR)) { 179280304Sjkim if (!PKCS7_add_attrib_content_type(si, NULL)) 180280304Sjkim goto err; 181280304Sjkim /* Add SMIMECapabilities */ 182280304Sjkim if (!(flags & PKCS7_NOSMIMECAP)) { 183280304Sjkim if (!(smcap = sk_X509_ALGOR_new_null())) { 184280304Sjkim PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER, ERR_R_MALLOC_FAILURE); 185280304Sjkim goto err; 186280304Sjkim } 187280304Sjkim if (!add_cipher_smcap(smcap, NID_aes_256_cbc, -1) 188280304Sjkim || !add_digest_smcap(smcap, NID_id_GostR3411_94, -1) 189280304Sjkim || !add_cipher_smcap(smcap, NID_id_Gost28147_89, -1) 190280304Sjkim || !add_cipher_smcap(smcap, NID_aes_192_cbc, -1) 191280304Sjkim || !add_cipher_smcap(smcap, NID_aes_128_cbc, -1) 192280304Sjkim || !add_cipher_smcap(smcap, NID_des_ede3_cbc, -1) 193280304Sjkim || !add_cipher_smcap(smcap, NID_rc2_cbc, 128) 194280304Sjkim || !add_cipher_smcap(smcap, NID_rc2_cbc, 64) 195280304Sjkim || !add_cipher_smcap(smcap, NID_des_cbc, -1) 196280304Sjkim || !add_cipher_smcap(smcap, NID_rc2_cbc, 40) 197280304Sjkim || !PKCS7_add_attrib_smimecap(si, smcap)) 198280304Sjkim goto err; 199280304Sjkim sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); 200280304Sjkim smcap = NULL; 201280304Sjkim } 202280304Sjkim if (flags & PKCS7_REUSE_DIGEST) { 203280304Sjkim if (!pkcs7_copy_existing_digest(p7, si)) 204280304Sjkim goto err; 205280304Sjkim if (!(flags & PKCS7_PARTIAL) && !PKCS7_SIGNER_INFO_sign(si)) 206280304Sjkim goto err; 207280304Sjkim } 208280304Sjkim } 209280304Sjkim return si; 210280304Sjkim err: 211280304Sjkim if (smcap) 212280304Sjkim sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); 213280304Sjkim return NULL; 214280304Sjkim} 21559191Skris 216280304Sjkim/* 217280304Sjkim * Search for a digest matching SignerInfo digest type and if found copy 218280304Sjkim * across. 219238405Sjkim */ 220238405Sjkim 221238405Sjkimstatic int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si) 222280304Sjkim{ 223280304Sjkim int i; 224280304Sjkim STACK_OF(PKCS7_SIGNER_INFO) *sinfos; 225280304Sjkim PKCS7_SIGNER_INFO *sitmp; 226280304Sjkim ASN1_OCTET_STRING *osdig = NULL; 227280304Sjkim sinfos = PKCS7_get_signer_info(p7); 228280304Sjkim for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { 229280304Sjkim sitmp = sk_PKCS7_SIGNER_INFO_value(sinfos, i); 230280304Sjkim if (si == sitmp) 231280304Sjkim break; 232280304Sjkim if (sk_X509_ATTRIBUTE_num(sitmp->auth_attr) <= 0) 233280304Sjkim continue; 234280304Sjkim if (!OBJ_cmp(si->digest_alg->algorithm, sitmp->digest_alg->algorithm)) { 235280304Sjkim osdig = PKCS7_digest_from_attributes(sitmp->auth_attr); 236280304Sjkim break; 237280304Sjkim } 238238405Sjkim 239280304Sjkim } 240238405Sjkim 241280304Sjkim if (osdig) 242280304Sjkim return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length); 243238405Sjkim 244280304Sjkim PKCS7err(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST, 245280304Sjkim PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND); 246280304Sjkim return 0; 247280304Sjkim} 248238405Sjkim 24959191Skrisint PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, 250280304Sjkim BIO *indata, BIO *out, int flags) 25159191Skris{ 252280304Sjkim STACK_OF(X509) *signers; 253280304Sjkim X509 *signer; 254280304Sjkim STACK_OF(PKCS7_SIGNER_INFO) *sinfos; 255280304Sjkim PKCS7_SIGNER_INFO *si; 256280304Sjkim X509_STORE_CTX cert_ctx; 257280304Sjkim char buf[4096]; 258280304Sjkim int i, j = 0, k, ret = 0; 259280304Sjkim BIO *p7bio; 260280304Sjkim BIO *tmpin, *tmpout; 26159191Skris 262280304Sjkim if (!p7) { 263280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_INVALID_NULL_POINTER); 264280304Sjkim return 0; 265280304Sjkim } 26659191Skris 267280304Sjkim if (!PKCS7_type_is_signed(p7)) { 268280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_WRONG_CONTENT_TYPE); 269280304Sjkim return 0; 270280304Sjkim } 27159191Skris 272280304Sjkim /* Check for no data and no content: no data to verify signature */ 273280304Sjkim if (PKCS7_get_detached(p7) && !indata) { 274280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_NO_CONTENT); 275280304Sjkim return 0; 276280304Sjkim } 27768651Skris#if 0 278280304Sjkim /* 279280304Sjkim * NB: this test commented out because some versions of Netscape 280280304Sjkim * illegally include zero length content when signing data. 281280304Sjkim */ 28259191Skris 283280304Sjkim /* Check for data and content: two sets of data */ 284280304Sjkim if (!PKCS7_get_detached(p7) && indata) { 285280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_CONTENT_AND_DATA_PRESENT); 286280304Sjkim return 0; 287280304Sjkim } 28868651Skris#endif 28959191Skris 290280304Sjkim sinfos = PKCS7_get_signer_info(p7); 29159191Skris 292280304Sjkim if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { 293280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_NO_SIGNATURES_ON_DATA); 294280304Sjkim return 0; 295280304Sjkim } 29659191Skris 297280304Sjkim signers = PKCS7_get0_signers(p7, certs, flags); 29859191Skris 299280304Sjkim if (!signers) 300280304Sjkim return 0; 30159191Skris 302280304Sjkim /* Now verify the certificates */ 30359191Skris 304280304Sjkim if (!(flags & PKCS7_NOVERIFY)) 305280304Sjkim for (k = 0; k < sk_X509_num(signers); k++) { 306280304Sjkim signer = sk_X509_value(signers, k); 307280304Sjkim if (!(flags & PKCS7_NOCHAIN)) { 308280304Sjkim if (!X509_STORE_CTX_init(&cert_ctx, store, signer, 309280304Sjkim p7->d.sign->cert)) { 310280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB); 311280304Sjkim sk_X509_free(signers); 312280304Sjkim return 0; 313280304Sjkim } 314280304Sjkim X509_STORE_CTX_set_default(&cert_ctx, "smime_sign"); 315280304Sjkim } else if (!X509_STORE_CTX_init(&cert_ctx, store, signer, NULL)) { 316280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB); 317280304Sjkim sk_X509_free(signers); 318280304Sjkim return 0; 319280304Sjkim } 320280304Sjkim if (!(flags & PKCS7_NOCRL)) 321280304Sjkim X509_STORE_CTX_set0_crls(&cert_ctx, p7->d.sign->crl); 322280304Sjkim i = X509_verify_cert(&cert_ctx); 323280304Sjkim if (i <= 0) 324280304Sjkim j = X509_STORE_CTX_get_error(&cert_ctx); 325280304Sjkim X509_STORE_CTX_cleanup(&cert_ctx); 326280304Sjkim if (i <= 0) { 327280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, 328280304Sjkim PKCS7_R_CERTIFICATE_VERIFY_ERROR); 329280304Sjkim ERR_add_error_data(2, "Verify error:", 330280304Sjkim X509_verify_cert_error_string(j)); 331280304Sjkim sk_X509_free(signers); 332280304Sjkim return 0; 333280304Sjkim } 334280304Sjkim /* Check for revocation status here */ 335280304Sjkim } 33659191Skris 337280304Sjkim /* 338280304Sjkim * Performance optimization: if the content is a memory BIO then store 339280304Sjkim * its contents in a temporary read only memory BIO. This avoids 340280304Sjkim * potentially large numbers of slow copies of data which will occur when 341280304Sjkim * reading from a read write memory BIO when signatures are calculated. 342280304Sjkim */ 34359191Skris 344280304Sjkim if (indata && (BIO_method_type(indata) == BIO_TYPE_MEM)) { 345280304Sjkim char *ptr; 346280304Sjkim long len; 347280304Sjkim len = BIO_get_mem_data(indata, &ptr); 348280304Sjkim tmpin = BIO_new_mem_buf(ptr, len); 349280304Sjkim if (tmpin == NULL) { 350280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_MALLOC_FAILURE); 351280304Sjkim return 0; 352280304Sjkim } 353280304Sjkim } else 354280304Sjkim tmpin = indata; 35559191Skris 356280304Sjkim if (!(p7bio = PKCS7_dataInit(p7, tmpin))) 357280304Sjkim goto err; 358160814Ssimon 359280304Sjkim if (flags & PKCS7_TEXT) { 360280304Sjkim if (!(tmpout = BIO_new(BIO_s_mem()))) { 361280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_MALLOC_FAILURE); 362280304Sjkim goto err; 363280304Sjkim } 364280304Sjkim BIO_set_mem_eof_return(tmpout, 0); 365280304Sjkim } else 366280304Sjkim tmpout = out; 367160814Ssimon 368280304Sjkim /* We now have to 'read' from p7bio to calculate digests etc. */ 369280304Sjkim for (;;) { 370280304Sjkim i = BIO_read(p7bio, buf, sizeof(buf)); 371280304Sjkim if (i <= 0) 372280304Sjkim break; 373280304Sjkim if (tmpout) 374280304Sjkim BIO_write(tmpout, buf, i); 375280304Sjkim } 37659191Skris 377280304Sjkim if (flags & PKCS7_TEXT) { 378280304Sjkim if (!SMIME_text(tmpout, out)) { 379280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_SMIME_TEXT_ERROR); 380280304Sjkim BIO_free(tmpout); 381280304Sjkim goto err; 382280304Sjkim } 383280304Sjkim BIO_free(tmpout); 384280304Sjkim } 38559191Skris 386280304Sjkim /* Now Verify All Signatures */ 387280304Sjkim if (!(flags & PKCS7_NOSIGS)) 388280304Sjkim for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { 389280304Sjkim si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); 390280304Sjkim signer = sk_X509_value(signers, i); 391280304Sjkim j = PKCS7_signatureVerify(p7bio, p7, si, signer); 392280304Sjkim if (j <= 0) { 393280304Sjkim PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_SIGNATURE_FAILURE); 394280304Sjkim goto err; 395280304Sjkim } 396280304Sjkim } 39759191Skris 398280304Sjkim ret = 1; 39959191Skris 400280304Sjkim err: 40159191Skris 402280304Sjkim if (tmpin == indata) { 403280304Sjkim if (indata) 404280304Sjkim BIO_pop(p7bio); 405280304Sjkim } 406280304Sjkim BIO_free_all(p7bio); 40759191Skris 408280304Sjkim sk_X509_free(signers); 40959191Skris 410280304Sjkim return ret; 41159191Skris} 41259191Skris 413280304SjkimSTACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, 414280304Sjkim int flags) 41559191Skris{ 416280304Sjkim STACK_OF(X509) *signers; 417280304Sjkim STACK_OF(PKCS7_SIGNER_INFO) *sinfos; 418280304Sjkim PKCS7_SIGNER_INFO *si; 419280304Sjkim PKCS7_ISSUER_AND_SERIAL *ias; 420280304Sjkim X509 *signer; 421280304Sjkim int i; 42259191Skris 423280304Sjkim if (!p7) { 424280304Sjkim PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_INVALID_NULL_POINTER); 425280304Sjkim return NULL; 426280304Sjkim } 42759191Skris 428280304Sjkim if (!PKCS7_type_is_signed(p7)) { 429280304Sjkim PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_WRONG_CONTENT_TYPE); 430280304Sjkim return NULL; 431280304Sjkim } 43259191Skris 433280304Sjkim /* Collect all the signers together */ 43459191Skris 435280304Sjkim sinfos = PKCS7_get_signer_info(p7); 43659191Skris 437280304Sjkim if (sk_PKCS7_SIGNER_INFO_num(sinfos) <= 0) { 438280304Sjkim PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_NO_SIGNERS); 439280304Sjkim return 0; 440280304Sjkim } 44159191Skris 442280304Sjkim if (!(signers = sk_X509_new_null())) { 443280304Sjkim PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, ERR_R_MALLOC_FAILURE); 444280304Sjkim return NULL; 445280304Sjkim } 446160814Ssimon 447280304Sjkim for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { 448280304Sjkim si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); 449280304Sjkim ias = si->issuer_and_serial; 450280304Sjkim signer = NULL; 451280304Sjkim /* If any certificates passed they take priority */ 452280304Sjkim if (certs) 453280304Sjkim signer = X509_find_by_issuer_and_serial(certs, 454280304Sjkim ias->issuer, ias->serial); 455280304Sjkim if (!signer && !(flags & PKCS7_NOINTERN) 456280304Sjkim && p7->d.sign->cert) 457280304Sjkim signer = 458280304Sjkim X509_find_by_issuer_and_serial(p7->d.sign->cert, 459280304Sjkim ias->issuer, ias->serial); 460280304Sjkim if (!signer) { 461280304Sjkim PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, 462280304Sjkim PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND); 463280304Sjkim sk_X509_free(signers); 464280304Sjkim return 0; 465280304Sjkim } 46659191Skris 467280304Sjkim if (!sk_X509_push(signers, signer)) { 468280304Sjkim sk_X509_free(signers); 469280304Sjkim return NULL; 470280304Sjkim } 471280304Sjkim } 472280304Sjkim return signers; 47359191Skris} 47459191Skris 47559191Skris/* Build a complete PKCS#7 enveloped data */ 47659191Skris 477109998SmarkmPKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, 478280304Sjkim int flags) 47959191Skris{ 480280304Sjkim PKCS7 *p7; 481280304Sjkim BIO *p7bio = NULL; 482280304Sjkim int i; 483280304Sjkim X509 *x509; 484280304Sjkim if (!(p7 = PKCS7_new())) { 485280304Sjkim PKCS7err(PKCS7_F_PKCS7_ENCRYPT, ERR_R_MALLOC_FAILURE); 486280304Sjkim return NULL; 487280304Sjkim } 48859191Skris 489280304Sjkim if (!PKCS7_set_type(p7, NID_pkcs7_enveloped)) 490280304Sjkim goto err; 491280304Sjkim if (!PKCS7_set_cipher(p7, cipher)) { 492280304Sjkim PKCS7err(PKCS7_F_PKCS7_ENCRYPT, PKCS7_R_ERROR_SETTING_CIPHER); 493280304Sjkim goto err; 494280304Sjkim } 49559191Skris 496280304Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 497280304Sjkim x509 = sk_X509_value(certs, i); 498280304Sjkim if (!PKCS7_add_recipient(p7, x509)) { 499280304Sjkim PKCS7err(PKCS7_F_PKCS7_ENCRYPT, PKCS7_R_ERROR_ADDING_RECIPIENT); 500280304Sjkim goto err; 501280304Sjkim } 502280304Sjkim } 50359191Skris 504280304Sjkim if (flags & PKCS7_STREAM) 505280304Sjkim return p7; 50659191Skris 507280304Sjkim if (PKCS7_final(p7, in, flags)) 508280304Sjkim return p7; 50959191Skris 510280304Sjkim err: 51159191Skris 512280304Sjkim BIO_free_all(p7bio); 513280304Sjkim PKCS7_free(p7); 514280304Sjkim return NULL; 51559191Skris 51659191Skris} 51759191Skris 51859191Skrisint PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags) 51959191Skris{ 520280304Sjkim BIO *tmpmem; 521280304Sjkim int ret, i; 522280304Sjkim char buf[4096]; 52359191Skris 524280304Sjkim if (!p7) { 525280304Sjkim PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_INVALID_NULL_POINTER); 526280304Sjkim return 0; 527280304Sjkim } 52859191Skris 529280304Sjkim if (!PKCS7_type_is_enveloped(p7)) { 530280304Sjkim PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_WRONG_CONTENT_TYPE); 531280304Sjkim return 0; 532280304Sjkim } 53359191Skris 534280304Sjkim if (cert && !X509_check_private_key(cert, pkey)) { 535280304Sjkim PKCS7err(PKCS7_F_PKCS7_DECRYPT, 536280304Sjkim PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); 537280304Sjkim return 0; 538280304Sjkim } 53959191Skris 540280304Sjkim if (!(tmpmem = PKCS7_dataDecode(p7, pkey, NULL, cert))) { 541280304Sjkim PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_DECRYPT_ERROR); 542280304Sjkim return 0; 543280304Sjkim } 54459191Skris 545280304Sjkim if (flags & PKCS7_TEXT) { 546280304Sjkim BIO *tmpbuf, *bread; 547280304Sjkim /* Encrypt BIOs can't do BIO_gets() so add a buffer BIO */ 548280304Sjkim if (!(tmpbuf = BIO_new(BIO_f_buffer()))) { 549280304Sjkim PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE); 550280304Sjkim BIO_free_all(tmpmem); 551280304Sjkim return 0; 552280304Sjkim } 553280304Sjkim if (!(bread = BIO_push(tmpbuf, tmpmem))) { 554280304Sjkim PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE); 555280304Sjkim BIO_free_all(tmpbuf); 556280304Sjkim BIO_free_all(tmpmem); 557280304Sjkim return 0; 558280304Sjkim } 559280304Sjkim ret = SMIME_text(bread, data); 560280304Sjkim if (ret > 0 && BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) { 561280304Sjkim if (!BIO_get_cipher_status(tmpmem)) 562280304Sjkim ret = 0; 563280304Sjkim } 564280304Sjkim BIO_free_all(bread); 565280304Sjkim return ret; 566280304Sjkim } else { 567280304Sjkim for (;;) { 568280304Sjkim i = BIO_read(tmpmem, buf, sizeof(buf)); 569280304Sjkim if (i <= 0) { 570280304Sjkim ret = 1; 571280304Sjkim if (BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) { 572280304Sjkim if (!BIO_get_cipher_status(tmpmem)) 573280304Sjkim ret = 0; 574280304Sjkim } 575280304Sjkim 576280304Sjkim break; 577280304Sjkim } 578280304Sjkim if (BIO_write(data, buf, i) != i) { 579280304Sjkim ret = 0; 580280304Sjkim break; 581280304Sjkim } 582280304Sjkim } 583280304Sjkim BIO_free_all(tmpmem); 584280304Sjkim return ret; 585280304Sjkim } 58659191Skris} 587