1183234Ssimon/* crypto/cms/cms_smime.c */ 2296465Sdelphij/* 3296465Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4183234Ssimon * project. 5183234Ssimon */ 6183234Ssimon/* ==================================================================== 7183234Ssimon * Copyright (c) 2008 The OpenSSL Project. All rights reserved. 8183234Ssimon * 9183234Ssimon * Redistribution and use in source and binary forms, with or without 10183234Ssimon * modification, are permitted provided that the following conditions 11183234Ssimon * are met: 12183234Ssimon * 13183234Ssimon * 1. Redistributions of source code must retain the above copyright 14296465Sdelphij * notice, this list of conditions and the following disclaimer. 15183234Ssimon * 16183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright 17183234Ssimon * notice, this list of conditions and the following disclaimer in 18183234Ssimon * the documentation and/or other materials provided with the 19183234Ssimon * distribution. 20183234Ssimon * 21183234Ssimon * 3. All advertising materials mentioning features or use of this 22183234Ssimon * software must display the following acknowledgment: 23183234Ssimon * "This product includes software developed by the OpenSSL Project 24183234Ssimon * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25183234Ssimon * 26183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27183234Ssimon * endorse or promote products derived from this software without 28183234Ssimon * prior written permission. For written permission, please contact 29183234Ssimon * licensing@OpenSSL.org. 30183234Ssimon * 31183234Ssimon * 5. Products derived from this software may not be called "OpenSSL" 32183234Ssimon * nor may "OpenSSL" appear in their names without prior written 33183234Ssimon * permission of the OpenSSL Project. 34183234Ssimon * 35183234Ssimon * 6. Redistributions of any form whatsoever must retain the following 36183234Ssimon * acknowledgment: 37183234Ssimon * "This product includes software developed by the OpenSSL Project 38183234Ssimon * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39183234Ssimon * 40183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43183234Ssimon * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE. 52183234Ssimon * ==================================================================== 53183234Ssimon */ 54183234Ssimon 55183234Ssimon#include "cryptlib.h" 56183234Ssimon#include <openssl/asn1t.h> 57183234Ssimon#include <openssl/x509.h> 58183234Ssimon#include <openssl/x509v3.h> 59183234Ssimon#include <openssl/err.h> 60183234Ssimon#include <openssl/cms.h> 61183234Ssimon#include "cms_lcl.h" 62183234Ssimon 63183234Ssimonstatic int cms_copy_content(BIO *out, BIO *in, unsigned int flags) 64296465Sdelphij{ 65296465Sdelphij unsigned char buf[4096]; 66296465Sdelphij int r = 0, i; 67296465Sdelphij BIO *tmpout = NULL; 68183234Ssimon 69296465Sdelphij if (out == NULL) 70296465Sdelphij tmpout = BIO_new(BIO_s_null()); 71296465Sdelphij else if (flags & CMS_TEXT) { 72296465Sdelphij tmpout = BIO_new(BIO_s_mem()); 73296465Sdelphij BIO_set_mem_eof_return(tmpout, 0); 74296465Sdelphij } else 75296465Sdelphij tmpout = out; 76183234Ssimon 77296465Sdelphij if (!tmpout) { 78296465Sdelphij CMSerr(CMS_F_CMS_COPY_CONTENT, ERR_R_MALLOC_FAILURE); 79296465Sdelphij goto err; 80296465Sdelphij } 81183234Ssimon 82296465Sdelphij /* Read all content through chain to process digest, decrypt etc */ 83296465Sdelphij for (;;) { 84296465Sdelphij i = BIO_read(in, buf, sizeof(buf)); 85296465Sdelphij if (i <= 0) { 86296465Sdelphij if (BIO_method_type(in) == BIO_TYPE_CIPHER) { 87296465Sdelphij if (!BIO_get_cipher_status(in)) 88296465Sdelphij goto err; 89296465Sdelphij } 90296465Sdelphij if (i < 0) 91296465Sdelphij goto err; 92296465Sdelphij break; 93296465Sdelphij } 94183234Ssimon 95296465Sdelphij if (tmpout && (BIO_write(tmpout, buf, i) != i)) 96296465Sdelphij goto err; 97296465Sdelphij } 98183234Ssimon 99296465Sdelphij if (flags & CMS_TEXT) { 100296465Sdelphij if (!SMIME_text(tmpout, out)) { 101296465Sdelphij CMSerr(CMS_F_CMS_COPY_CONTENT, CMS_R_SMIME_TEXT_ERROR); 102296465Sdelphij goto err; 103296465Sdelphij } 104296465Sdelphij } 105183234Ssimon 106296465Sdelphij r = 1; 107183234Ssimon 108296465Sdelphij err: 109296465Sdelphij if (tmpout && (tmpout != out)) 110296465Sdelphij BIO_free(tmpout); 111296465Sdelphij return r; 112183234Ssimon 113296465Sdelphij} 114296465Sdelphij 115183234Ssimonstatic int check_content(CMS_ContentInfo *cms) 116296465Sdelphij{ 117296465Sdelphij ASN1_OCTET_STRING **pos = CMS_get0_content(cms); 118296465Sdelphij if (!pos || !*pos) { 119296465Sdelphij CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT); 120296465Sdelphij return 0; 121296465Sdelphij } 122296465Sdelphij return 1; 123296465Sdelphij} 124183234Ssimon 125183234Ssimonstatic void do_free_upto(BIO *f, BIO *upto) 126296465Sdelphij{ 127296465Sdelphij if (upto) { 128296465Sdelphij BIO *tbio; 129296465Sdelphij do { 130296465Sdelphij tbio = BIO_pop(f); 131296465Sdelphij BIO_free(f); 132296465Sdelphij f = tbio; 133296465Sdelphij } 134296465Sdelphij while (f && f != upto); 135296465Sdelphij } else 136296465Sdelphij BIO_free_all(f); 137296465Sdelphij} 138183234Ssimon 139183234Ssimonint CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags) 140296465Sdelphij{ 141296465Sdelphij BIO *cont; 142296465Sdelphij int r; 143296465Sdelphij if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) { 144296465Sdelphij CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA); 145296465Sdelphij return 0; 146296465Sdelphij } 147296465Sdelphij cont = CMS_dataInit(cms, NULL); 148296465Sdelphij if (!cont) 149296465Sdelphij return 0; 150296465Sdelphij r = cms_copy_content(out, cont, flags); 151296465Sdelphij BIO_free_all(cont); 152296465Sdelphij return r; 153296465Sdelphij} 154183234Ssimon 155183234SsimonCMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags) 156296465Sdelphij{ 157296465Sdelphij CMS_ContentInfo *cms; 158296465Sdelphij cms = cms_Data_create(); 159296465Sdelphij if (!cms) 160296465Sdelphij return NULL; 161183234Ssimon 162296465Sdelphij if (CMS_final(cms, in, NULL, flags)) 163296465Sdelphij return cms; 164183234Ssimon 165296465Sdelphij CMS_ContentInfo_free(cms); 166183234Ssimon 167296465Sdelphij return NULL; 168296465Sdelphij} 169183234Ssimon 170183234Ssimonint CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 171296465Sdelphij unsigned int flags) 172296465Sdelphij{ 173296465Sdelphij BIO *cont; 174296465Sdelphij int r; 175296465Sdelphij if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) { 176296465Sdelphij CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA); 177296465Sdelphij return 0; 178296465Sdelphij } 179183234Ssimon 180296465Sdelphij if (!dcont && !check_content(cms)) 181296465Sdelphij return 0; 182183234Ssimon 183296465Sdelphij cont = CMS_dataInit(cms, dcont); 184296465Sdelphij if (!cont) 185296465Sdelphij return 0; 186296465Sdelphij r = cms_copy_content(out, cont, flags); 187296465Sdelphij if (r) 188296465Sdelphij r = cms_DigestedData_do_final(cms, cont, 1); 189296465Sdelphij do_free_upto(cont, dcont); 190296465Sdelphij return r; 191296465Sdelphij} 192183234Ssimon 193183234SsimonCMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, 194296465Sdelphij unsigned int flags) 195296465Sdelphij{ 196296465Sdelphij CMS_ContentInfo *cms; 197296465Sdelphij if (!md) 198296465Sdelphij md = EVP_sha1(); 199296465Sdelphij cms = cms_DigestedData_create(md); 200296465Sdelphij if (!cms) 201296465Sdelphij return NULL; 202183234Ssimon 203296465Sdelphij if (!(flags & CMS_DETACHED)) { 204296465Sdelphij flags &= ~CMS_STREAM; 205296465Sdelphij CMS_set_detached(cms, 0); 206296465Sdelphij } 207183234Ssimon 208296465Sdelphij if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) 209296465Sdelphij return cms; 210183234Ssimon 211296465Sdelphij CMS_ContentInfo_free(cms); 212296465Sdelphij return NULL; 213296465Sdelphij} 214183234Ssimon 215183234Ssimonint CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, 216296465Sdelphij const unsigned char *key, size_t keylen, 217296465Sdelphij BIO *dcont, BIO *out, unsigned int flags) 218296465Sdelphij{ 219296465Sdelphij BIO *cont; 220296465Sdelphij int r; 221296465Sdelphij if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) { 222296465Sdelphij CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT, 223296465Sdelphij CMS_R_TYPE_NOT_ENCRYPTED_DATA); 224296465Sdelphij return 0; 225296465Sdelphij } 226183234Ssimon 227296465Sdelphij if (!dcont && !check_content(cms)) 228296465Sdelphij return 0; 229183234Ssimon 230296465Sdelphij if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0) 231296465Sdelphij return 0; 232296465Sdelphij cont = CMS_dataInit(cms, dcont); 233296465Sdelphij if (!cont) 234296465Sdelphij return 0; 235296465Sdelphij r = cms_copy_content(out, cont, flags); 236296465Sdelphij do_free_upto(cont, dcont); 237296465Sdelphij return r; 238296465Sdelphij} 239183234Ssimon 240183234SsimonCMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, 241296465Sdelphij const unsigned char *key, 242296465Sdelphij size_t keylen, unsigned int flags) 243296465Sdelphij{ 244296465Sdelphij CMS_ContentInfo *cms; 245296465Sdelphij if (!cipher) { 246296465Sdelphij CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER); 247296465Sdelphij return NULL; 248296465Sdelphij } 249296465Sdelphij cms = CMS_ContentInfo_new(); 250296465Sdelphij if (!cms) 251296465Sdelphij return NULL; 252296465Sdelphij if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) 253296465Sdelphij return NULL; 254183234Ssimon 255296465Sdelphij if (!(flags & CMS_DETACHED)) { 256296465Sdelphij flags &= ~CMS_STREAM; 257296465Sdelphij CMS_set_detached(cms, 0); 258296465Sdelphij } 259183234Ssimon 260296465Sdelphij if ((flags & (CMS_STREAM | CMS_PARTIAL)) 261296465Sdelphij || CMS_final(cms, in, NULL, flags)) 262296465Sdelphij return cms; 263183234Ssimon 264296465Sdelphij CMS_ContentInfo_free(cms); 265296465Sdelphij return NULL; 266296465Sdelphij} 267183234Ssimon 268183234Ssimonstatic int cms_signerinfo_verify_cert(CMS_SignerInfo *si, 269296465Sdelphij X509_STORE *store, 270296465Sdelphij STACK_OF(X509) *certs, 271296465Sdelphij STACK_OF(X509_CRL) *crls, 272296465Sdelphij unsigned int flags) 273296465Sdelphij{ 274296465Sdelphij X509_STORE_CTX ctx; 275296465Sdelphij X509 *signer; 276296465Sdelphij int i, j, r = 0; 277296465Sdelphij CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); 278296465Sdelphij if (!X509_STORE_CTX_init(&ctx, store, signer, certs)) { 279296465Sdelphij CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, CMS_R_STORE_INIT_ERROR); 280296465Sdelphij goto err; 281296465Sdelphij } 282296465Sdelphij X509_STORE_CTX_set_default(&ctx, "smime_sign"); 283296465Sdelphij if (crls) 284296465Sdelphij X509_STORE_CTX_set0_crls(&ctx, crls); 285183234Ssimon 286296465Sdelphij i = X509_verify_cert(&ctx); 287296465Sdelphij if (i <= 0) { 288296465Sdelphij j = X509_STORE_CTX_get_error(&ctx); 289296465Sdelphij CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, 290296465Sdelphij CMS_R_CERTIFICATE_VERIFY_ERROR); 291296465Sdelphij ERR_add_error_data(2, "Verify error:", 292296465Sdelphij X509_verify_cert_error_string(j)); 293296465Sdelphij goto err; 294296465Sdelphij } 295296465Sdelphij r = 1; 296296465Sdelphij err: 297296465Sdelphij X509_STORE_CTX_cleanup(&ctx); 298296465Sdelphij return r; 299183234Ssimon 300296465Sdelphij} 301183234Ssimon 302183234Ssimonint CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, 303296465Sdelphij X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags) 304296465Sdelphij{ 305296465Sdelphij CMS_SignerInfo *si; 306296465Sdelphij STACK_OF(CMS_SignerInfo) *sinfos; 307296465Sdelphij STACK_OF(X509) *cms_certs = NULL; 308296465Sdelphij STACK_OF(X509_CRL) *crls = NULL; 309296465Sdelphij X509 *signer; 310296465Sdelphij int i, scount = 0, ret = 0; 311296465Sdelphij BIO *cmsbio = NULL, *tmpin = NULL; 312183234Ssimon 313296465Sdelphij if (!dcont && !check_content(cms)) 314296465Sdelphij return 0; 315183234Ssimon 316296465Sdelphij /* Attempt to find all signer certificates */ 317183234Ssimon 318296465Sdelphij sinfos = CMS_get0_SignerInfos(cms); 319183234Ssimon 320296465Sdelphij if (sk_CMS_SignerInfo_num(sinfos) <= 0) { 321296465Sdelphij CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS); 322296465Sdelphij goto err; 323296465Sdelphij } 324183234Ssimon 325296465Sdelphij for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 326296465Sdelphij si = sk_CMS_SignerInfo_value(sinfos, i); 327296465Sdelphij CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); 328296465Sdelphij if (signer) 329296465Sdelphij scount++; 330296465Sdelphij } 331183234Ssimon 332296465Sdelphij if (scount != sk_CMS_SignerInfo_num(sinfos)) 333296465Sdelphij scount += CMS_set1_signers_certs(cms, certs, flags); 334183234Ssimon 335296465Sdelphij if (scount != sk_CMS_SignerInfo_num(sinfos)) { 336296465Sdelphij CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND); 337296465Sdelphij goto err; 338296465Sdelphij } 339183234Ssimon 340296465Sdelphij /* Attempt to verify all signers certs */ 341183234Ssimon 342296465Sdelphij if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) { 343296465Sdelphij cms_certs = CMS_get1_certs(cms); 344296465Sdelphij if (!(flags & CMS_NOCRL)) 345296465Sdelphij crls = CMS_get1_crls(cms); 346296465Sdelphij for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 347296465Sdelphij si = sk_CMS_SignerInfo_value(sinfos, i); 348296465Sdelphij if (!cms_signerinfo_verify_cert(si, store, 349296465Sdelphij cms_certs, crls, flags)) 350296465Sdelphij goto err; 351296465Sdelphij } 352296465Sdelphij } 353183234Ssimon 354296465Sdelphij /* Attempt to verify all SignerInfo signed attribute signatures */ 355183234Ssimon 356296465Sdelphij if (!(flags & CMS_NO_ATTR_VERIFY)) { 357296465Sdelphij for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 358296465Sdelphij si = sk_CMS_SignerInfo_value(sinfos, i); 359296465Sdelphij if (CMS_signed_get_attr_count(si) < 0) 360296465Sdelphij continue; 361296465Sdelphij if (CMS_SignerInfo_verify(si) <= 0) 362296465Sdelphij goto err; 363296465Sdelphij } 364296465Sdelphij } 365183234Ssimon 366296465Sdelphij /* 367296465Sdelphij * Performance optimization: if the content is a memory BIO then store 368296465Sdelphij * its contents in a temporary read only memory BIO. This avoids 369296465Sdelphij * potentially large numbers of slow copies of data which will occur when 370296465Sdelphij * reading from a read write memory BIO when signatures are calculated. 371296465Sdelphij */ 372183234Ssimon 373296465Sdelphij if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) { 374296465Sdelphij char *ptr; 375296465Sdelphij long len; 376296465Sdelphij len = BIO_get_mem_data(dcont, &ptr); 377296465Sdelphij tmpin = BIO_new_mem_buf(ptr, len); 378296465Sdelphij if (tmpin == NULL) { 379296465Sdelphij CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE); 380296465Sdelphij return 0; 381296465Sdelphij } 382296465Sdelphij } else 383296465Sdelphij tmpin = dcont; 384183234Ssimon 385296465Sdelphij cmsbio = CMS_dataInit(cms, tmpin); 386296465Sdelphij if (!cmsbio) 387296465Sdelphij goto err; 388183234Ssimon 389296465Sdelphij if (!cms_copy_content(out, cmsbio, flags)) 390296465Sdelphij goto err; 391183234Ssimon 392296465Sdelphij if (!(flags & CMS_NO_CONTENT_VERIFY)) { 393296465Sdelphij for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 394296465Sdelphij si = sk_CMS_SignerInfo_value(sinfos, i); 395296465Sdelphij if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) { 396296465Sdelphij CMSerr(CMS_F_CMS_VERIFY, CMS_R_CONTENT_VERIFY_ERROR); 397296465Sdelphij goto err; 398296465Sdelphij } 399296465Sdelphij } 400296465Sdelphij } 401183234Ssimon 402296465Sdelphij ret = 1; 403183234Ssimon 404296465Sdelphij err: 405183234Ssimon 406296465Sdelphij if (dcont && (tmpin == dcont)) 407296465Sdelphij do_free_upto(cmsbio, dcont); 408296465Sdelphij else 409296465Sdelphij BIO_free_all(cmsbio); 410183234Ssimon 411296465Sdelphij if (cms_certs) 412296465Sdelphij sk_X509_pop_free(cms_certs, X509_free); 413296465Sdelphij if (crls) 414296465Sdelphij sk_X509_CRL_pop_free(crls, X509_CRL_free); 415183234Ssimon 416296465Sdelphij return ret; 417296465Sdelphij} 418296465Sdelphij 419183234Ssimonint CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, 420296465Sdelphij STACK_OF(X509) *certs, 421296465Sdelphij X509_STORE *store, unsigned int flags) 422296465Sdelphij{ 423296465Sdelphij int r; 424296465Sdelphij r = CMS_verify(rcms, certs, store, NULL, NULL, flags); 425296465Sdelphij if (r <= 0) 426296465Sdelphij return r; 427296465Sdelphij return cms_Receipt_verify(rcms, ocms); 428296465Sdelphij} 429183234Ssimon 430296465SdelphijCMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, 431296465Sdelphij STACK_OF(X509) *certs, BIO *data, 432296465Sdelphij unsigned int flags) 433296465Sdelphij{ 434296465Sdelphij CMS_ContentInfo *cms; 435296465Sdelphij int i; 436183234Ssimon 437296465Sdelphij cms = CMS_ContentInfo_new(); 438296465Sdelphij if (!cms || !CMS_SignedData_init(cms)) 439296465Sdelphij goto merr; 440183234Ssimon 441296465Sdelphij if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) { 442296465Sdelphij CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR); 443296465Sdelphij goto err; 444296465Sdelphij } 445183234Ssimon 446296465Sdelphij for (i = 0; i < sk_X509_num(certs); i++) { 447296465Sdelphij X509 *x = sk_X509_value(certs, i); 448296465Sdelphij if (!CMS_add1_cert(cms, x)) 449296465Sdelphij goto merr; 450296465Sdelphij } 451183234Ssimon 452296465Sdelphij if (!(flags & CMS_DETACHED)) { 453296465Sdelphij flags &= ~CMS_STREAM; 454296465Sdelphij CMS_set_detached(cms, 0); 455296465Sdelphij } 456183234Ssimon 457296465Sdelphij if ((flags & (CMS_STREAM | CMS_PARTIAL)) 458296465Sdelphij || CMS_final(cms, data, NULL, flags)) 459296465Sdelphij return cms; 460296465Sdelphij else 461296465Sdelphij goto err; 462183234Ssimon 463296465Sdelphij merr: 464296465Sdelphij CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE); 465183234Ssimon 466296465Sdelphij err: 467296465Sdelphij if (cms) 468296465Sdelphij CMS_ContentInfo_free(cms); 469296465Sdelphij return NULL; 470296465Sdelphij} 471183234Ssimon 472183234SsimonCMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, 473296465Sdelphij X509 *signcert, EVP_PKEY *pkey, 474296465Sdelphij STACK_OF(X509) *certs, unsigned int flags) 475296465Sdelphij{ 476296465Sdelphij CMS_SignerInfo *rct_si; 477296465Sdelphij CMS_ContentInfo *cms = NULL; 478296465Sdelphij ASN1_OCTET_STRING **pos, *os; 479296465Sdelphij BIO *rct_cont = NULL; 480296465Sdelphij int r = 0; 481183234Ssimon 482296465Sdelphij flags &= ~CMS_STREAM; 483296465Sdelphij /* Not really detached but avoids content being allocated */ 484296465Sdelphij flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED; 485296465Sdelphij if (!pkey || !signcert) { 486296465Sdelphij CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT); 487296465Sdelphij return NULL; 488296465Sdelphij } 489183234Ssimon 490296465Sdelphij /* Initialize signed data */ 491183234Ssimon 492296465Sdelphij cms = CMS_sign(NULL, NULL, certs, NULL, flags); 493296465Sdelphij if (!cms) 494296465Sdelphij goto err; 495183234Ssimon 496296465Sdelphij /* Set inner content type to signed receipt */ 497296465Sdelphij if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt))) 498296465Sdelphij goto err; 499183234Ssimon 500296465Sdelphij rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags); 501296465Sdelphij if (!rct_si) { 502296465Sdelphij CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR); 503296465Sdelphij goto err; 504296465Sdelphij } 505183234Ssimon 506296465Sdelphij os = cms_encode_Receipt(si); 507183234Ssimon 508296465Sdelphij if (!os) 509296465Sdelphij goto err; 510183234Ssimon 511296465Sdelphij /* Set content to digest */ 512296465Sdelphij rct_cont = BIO_new_mem_buf(os->data, os->length); 513296465Sdelphij if (!rct_cont) 514296465Sdelphij goto err; 515183234Ssimon 516296465Sdelphij /* Add msgSigDigest attribute */ 517183234Ssimon 518296465Sdelphij if (!cms_msgSigDigest_add1(rct_si, si)) 519296465Sdelphij goto err; 520183234Ssimon 521296465Sdelphij /* Finalize structure */ 522296465Sdelphij if (!CMS_final(cms, rct_cont, NULL, flags)) 523296465Sdelphij goto err; 524183234Ssimon 525296465Sdelphij /* Set embedded content */ 526296465Sdelphij pos = CMS_get0_content(cms); 527296465Sdelphij *pos = os; 528183234Ssimon 529296465Sdelphij r = 1; 530183234Ssimon 531296465Sdelphij err: 532296465Sdelphij if (rct_cont) 533296465Sdelphij BIO_free(rct_cont); 534296465Sdelphij if (r) 535296465Sdelphij return cms; 536296465Sdelphij CMS_ContentInfo_free(cms); 537296465Sdelphij return NULL; 538183234Ssimon 539296465Sdelphij} 540183234Ssimon 541183234SsimonCMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, 542296465Sdelphij const EVP_CIPHER *cipher, unsigned int flags) 543296465Sdelphij{ 544296465Sdelphij CMS_ContentInfo *cms; 545296465Sdelphij int i; 546296465Sdelphij X509 *recip; 547296465Sdelphij cms = CMS_EnvelopedData_create(cipher); 548296465Sdelphij if (!cms) 549296465Sdelphij goto merr; 550296465Sdelphij for (i = 0; i < sk_X509_num(certs); i++) { 551296465Sdelphij recip = sk_X509_value(certs, i); 552296465Sdelphij if (!CMS_add1_recipient_cert(cms, recip, flags)) { 553296465Sdelphij CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR); 554296465Sdelphij goto err; 555296465Sdelphij } 556296465Sdelphij } 557183234Ssimon 558296465Sdelphij if (!(flags & CMS_DETACHED)) { 559296465Sdelphij flags &= ~CMS_STREAM; 560296465Sdelphij CMS_set_detached(cms, 0); 561296465Sdelphij } 562183234Ssimon 563296465Sdelphij if ((flags & (CMS_STREAM | CMS_PARTIAL)) 564296465Sdelphij || CMS_final(cms, data, NULL, flags)) 565296465Sdelphij return cms; 566296465Sdelphij else 567296465Sdelphij goto err; 568183234Ssimon 569296465Sdelphij merr: 570296465Sdelphij CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE); 571296465Sdelphij err: 572296465Sdelphij if (cms) 573296465Sdelphij CMS_ContentInfo_free(cms); 574296465Sdelphij return NULL; 575296465Sdelphij} 576183234Ssimon 577183234Ssimonint CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) 578296465Sdelphij{ 579296465Sdelphij STACK_OF(CMS_RecipientInfo) *ris; 580296465Sdelphij CMS_RecipientInfo *ri; 581296465Sdelphij int i, r; 582296465Sdelphij int debug = 0, ri_match = 0; 583296465Sdelphij ris = CMS_get0_RecipientInfos(cms); 584296465Sdelphij if (ris) 585296465Sdelphij debug = cms->d.envelopedData->encryptedContentInfo->debug; 586296465Sdelphij for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { 587296465Sdelphij ri = sk_CMS_RecipientInfo_value(ris, i); 588296465Sdelphij if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS) 589296465Sdelphij continue; 590296465Sdelphij ri_match = 1; 591296465Sdelphij /* 592296465Sdelphij * If we have a cert try matching RecipientInfo otherwise try them 593296465Sdelphij * all. 594296465Sdelphij */ 595296465Sdelphij if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) { 596296465Sdelphij CMS_RecipientInfo_set0_pkey(ri, pk); 597296465Sdelphij r = CMS_RecipientInfo_decrypt(cms, ri); 598296465Sdelphij CMS_RecipientInfo_set0_pkey(ri, NULL); 599296465Sdelphij if (cert) { 600296465Sdelphij /* 601296465Sdelphij * If not debugging clear any error and return success to 602296465Sdelphij * avoid leaking of information useful to MMA 603296465Sdelphij */ 604296465Sdelphij if (!debug) { 605296465Sdelphij ERR_clear_error(); 606296465Sdelphij return 1; 607296465Sdelphij } 608296465Sdelphij if (r > 0) 609296465Sdelphij return 1; 610296465Sdelphij CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR); 611296465Sdelphij return 0; 612296465Sdelphij } 613296465Sdelphij /* 614296465Sdelphij * If no cert and not debugging don't leave loop after first 615296465Sdelphij * successful decrypt. Always attempt to decrypt all recipients 616296465Sdelphij * to avoid leaking timing of a successful decrypt. 617296465Sdelphij */ 618296465Sdelphij else if (r > 0 && debug) 619296465Sdelphij return 1; 620296465Sdelphij } 621296465Sdelphij } 622296465Sdelphij /* If no cert and not debugging always return success */ 623296465Sdelphij if (ri_match && !cert && !debug) { 624296465Sdelphij ERR_clear_error(); 625296465Sdelphij return 1; 626296465Sdelphij } 627183234Ssimon 628296465Sdelphij CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT); 629296465Sdelphij return 0; 630183234Ssimon 631296465Sdelphij} 632183234Ssimon 633296465Sdelphijint CMS_decrypt_set1_key(CMS_ContentInfo *cms, 634296465Sdelphij unsigned char *key, size_t keylen, 635296465Sdelphij unsigned char *id, size_t idlen) 636296465Sdelphij{ 637296465Sdelphij STACK_OF(CMS_RecipientInfo) *ris; 638296465Sdelphij CMS_RecipientInfo *ri; 639296465Sdelphij int i, r; 640296465Sdelphij ris = CMS_get0_RecipientInfos(cms); 641296465Sdelphij for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { 642296465Sdelphij ri = sk_CMS_RecipientInfo_value(ris, i); 643296465Sdelphij if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK) 644296465Sdelphij continue; 645183234Ssimon 646296465Sdelphij /* 647296465Sdelphij * If we have an id try matching RecipientInfo otherwise try them 648296465Sdelphij * all. 649296465Sdelphij */ 650296465Sdelphij if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) { 651296465Sdelphij CMS_RecipientInfo_set0_key(ri, key, keylen); 652296465Sdelphij r = CMS_RecipientInfo_decrypt(cms, ri); 653296465Sdelphij CMS_RecipientInfo_set0_key(ri, NULL, 0); 654296465Sdelphij if (r > 0) 655296465Sdelphij return 1; 656296465Sdelphij if (id) { 657296465Sdelphij CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_DECRYPT_ERROR); 658296465Sdelphij return 0; 659296465Sdelphij } 660296465Sdelphij ERR_clear_error(); 661296465Sdelphij } 662296465Sdelphij } 663183234Ssimon 664296465Sdelphij CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT); 665296465Sdelphij return 0; 666183234Ssimon 667296465Sdelphij} 668296465Sdelphij 669183234Ssimonint CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, 670296465Sdelphij BIO *dcont, BIO *out, unsigned int flags) 671296465Sdelphij{ 672296465Sdelphij int r; 673296465Sdelphij BIO *cont; 674296465Sdelphij if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) { 675296465Sdelphij CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA); 676296465Sdelphij return 0; 677296465Sdelphij } 678296465Sdelphij if (!dcont && !check_content(cms)) 679296465Sdelphij return 0; 680296465Sdelphij if (flags & CMS_DEBUG_DECRYPT) 681296465Sdelphij cms->d.envelopedData->encryptedContentInfo->debug = 1; 682296465Sdelphij else 683296465Sdelphij cms->d.envelopedData->encryptedContentInfo->debug = 0; 684296465Sdelphij if (!pk && !cert && !dcont && !out) 685296465Sdelphij return 1; 686296465Sdelphij if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert)) 687296465Sdelphij return 0; 688296465Sdelphij cont = CMS_dataInit(cms, dcont); 689296465Sdelphij if (!cont) 690296465Sdelphij return 0; 691296465Sdelphij r = cms_copy_content(out, cont, flags); 692296465Sdelphij do_free_upto(cont, dcont); 693296465Sdelphij return r; 694296465Sdelphij} 695183234Ssimon 696183234Ssimonint CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags) 697296465Sdelphij{ 698296465Sdelphij BIO *cmsbio; 699296465Sdelphij int ret = 0; 700296465Sdelphij if (!(cmsbio = CMS_dataInit(cms, dcont))) { 701296465Sdelphij CMSerr(CMS_F_CMS_FINAL, ERR_R_MALLOC_FAILURE); 702296465Sdelphij return 0; 703296465Sdelphij } 704183234Ssimon 705296465Sdelphij SMIME_crlf_copy(data, cmsbio, flags); 706183234Ssimon 707296465Sdelphij (void)BIO_flush(cmsbio); 708183234Ssimon 709296465Sdelphij if (!CMS_dataFinal(cms, cmsbio)) { 710296465Sdelphij CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_DATAFINAL_ERROR); 711296465Sdelphij goto err; 712296465Sdelphij } 713183234Ssimon 714296465Sdelphij ret = 1; 715183234Ssimon 716296465Sdelphij err: 717296465Sdelphij do_free_upto(cmsbio, dcont); 718183234Ssimon 719296465Sdelphij return ret; 720183234Ssimon 721296465Sdelphij} 722183234Ssimon 723183234Ssimon#ifdef ZLIB 724183234Ssimon 725183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 726296465Sdelphij unsigned int flags) 727296465Sdelphij{ 728296465Sdelphij BIO *cont; 729296465Sdelphij int r; 730296465Sdelphij if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) { 731296465Sdelphij CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_TYPE_NOT_COMPRESSED_DATA); 732296465Sdelphij return 0; 733296465Sdelphij } 734183234Ssimon 735296465Sdelphij if (!dcont && !check_content(cms)) 736296465Sdelphij return 0; 737183234Ssimon 738296465Sdelphij cont = CMS_dataInit(cms, dcont); 739296465Sdelphij if (!cont) 740296465Sdelphij return 0; 741296465Sdelphij r = cms_copy_content(out, cont, flags); 742296465Sdelphij do_free_upto(cont, dcont); 743296465Sdelphij return r; 744296465Sdelphij} 745183234Ssimon 746183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) 747296465Sdelphij{ 748296465Sdelphij CMS_ContentInfo *cms; 749296465Sdelphij if (comp_nid <= 0) 750296465Sdelphij comp_nid = NID_zlib_compression; 751296465Sdelphij cms = cms_CompressedData_create(comp_nid); 752296465Sdelphij if (!cms) 753296465Sdelphij return NULL; 754183234Ssimon 755296465Sdelphij if (!(flags & CMS_DETACHED)) { 756296465Sdelphij flags &= ~CMS_STREAM; 757296465Sdelphij CMS_set_detached(cms, 0); 758296465Sdelphij } 759183234Ssimon 760296465Sdelphij if (CMS_final(cms, in, NULL, flags)) 761296465Sdelphij return cms; 762183234Ssimon 763296465Sdelphij CMS_ContentInfo_free(cms); 764296465Sdelphij return NULL; 765296465Sdelphij} 766183234Ssimon 767183234Ssimon#else 768183234Ssimon 769183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 770296465Sdelphij unsigned int flags) 771296465Sdelphij{ 772296465Sdelphij CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); 773296465Sdelphij return 0; 774296465Sdelphij} 775183234Ssimon 776183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) 777296465Sdelphij{ 778296465Sdelphij CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); 779296465Sdelphij return NULL; 780296465Sdelphij} 781183234Ssimon 782183234Ssimon#endif 783