1183234Ssimon/* crypto/cms/cms_smime.c */ 2280304Sjkim/* 3280304Sjkim * 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 14280304Sjkim * 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) 64280304Sjkim{ 65280304Sjkim unsigned char buf[4096]; 66280304Sjkim int r = 0, i; 67280304Sjkim BIO *tmpout = NULL; 68183234Ssimon 69280304Sjkim if (out == NULL) 70280304Sjkim tmpout = BIO_new(BIO_s_null()); 71280304Sjkim else if (flags & CMS_TEXT) { 72280304Sjkim tmpout = BIO_new(BIO_s_mem()); 73280304Sjkim BIO_set_mem_eof_return(tmpout, 0); 74280304Sjkim } else 75280304Sjkim tmpout = out; 76183234Ssimon 77280304Sjkim if (!tmpout) { 78280304Sjkim CMSerr(CMS_F_CMS_COPY_CONTENT, ERR_R_MALLOC_FAILURE); 79280304Sjkim goto err; 80280304Sjkim } 81183234Ssimon 82280304Sjkim /* Read all content through chain to process digest, decrypt etc */ 83280304Sjkim for (;;) { 84280304Sjkim i = BIO_read(in, buf, sizeof(buf)); 85280304Sjkim if (i <= 0) { 86280304Sjkim if (BIO_method_type(in) == BIO_TYPE_CIPHER) { 87280304Sjkim if (!BIO_get_cipher_status(in)) 88280304Sjkim goto err; 89280304Sjkim } 90280304Sjkim if (i < 0) 91280304Sjkim goto err; 92280304Sjkim break; 93280304Sjkim } 94183234Ssimon 95280304Sjkim if (tmpout && (BIO_write(tmpout, buf, i) != i)) 96280304Sjkim goto err; 97280304Sjkim } 98183234Ssimon 99280304Sjkim if (flags & CMS_TEXT) { 100280304Sjkim if (!SMIME_text(tmpout, out)) { 101280304Sjkim CMSerr(CMS_F_CMS_COPY_CONTENT, CMS_R_SMIME_TEXT_ERROR); 102280304Sjkim goto err; 103280304Sjkim } 104280304Sjkim } 105183234Ssimon 106280304Sjkim r = 1; 107183234Ssimon 108280304Sjkim err: 109280304Sjkim if (tmpout && (tmpout != out)) 110280304Sjkim BIO_free(tmpout); 111280304Sjkim return r; 112183234Ssimon 113280304Sjkim} 114280304Sjkim 115183234Ssimonstatic int check_content(CMS_ContentInfo *cms) 116280304Sjkim{ 117280304Sjkim ASN1_OCTET_STRING **pos = CMS_get0_content(cms); 118280304Sjkim if (!pos || !*pos) { 119280304Sjkim CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT); 120280304Sjkim return 0; 121280304Sjkim } 122280304Sjkim return 1; 123280304Sjkim} 124183234Ssimon 125183234Ssimonstatic void do_free_upto(BIO *f, BIO *upto) 126280304Sjkim{ 127280304Sjkim if (upto) { 128280304Sjkim BIO *tbio; 129280304Sjkim do { 130280304Sjkim tbio = BIO_pop(f); 131280304Sjkim BIO_free(f); 132280304Sjkim f = tbio; 133280304Sjkim } 134284285Sjkim while (f && f != upto); 135280304Sjkim } else 136280304Sjkim BIO_free_all(f); 137280304Sjkim} 138183234Ssimon 139183234Ssimonint CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags) 140280304Sjkim{ 141280304Sjkim BIO *cont; 142280304Sjkim int r; 143280304Sjkim if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) { 144280304Sjkim CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA); 145280304Sjkim return 0; 146280304Sjkim } 147280304Sjkim cont = CMS_dataInit(cms, NULL); 148280304Sjkim if (!cont) 149280304Sjkim return 0; 150280304Sjkim r = cms_copy_content(out, cont, flags); 151280304Sjkim BIO_free_all(cont); 152280304Sjkim return r; 153280304Sjkim} 154183234Ssimon 155183234SsimonCMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags) 156280304Sjkim{ 157280304Sjkim CMS_ContentInfo *cms; 158280304Sjkim cms = cms_Data_create(); 159280304Sjkim if (!cms) 160280304Sjkim return NULL; 161183234Ssimon 162280304Sjkim if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) 163280304Sjkim return cms; 164183234Ssimon 165280304Sjkim CMS_ContentInfo_free(cms); 166183234Ssimon 167280304Sjkim return NULL; 168280304Sjkim} 169183234Ssimon 170183234Ssimonint CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 171280304Sjkim unsigned int flags) 172280304Sjkim{ 173280304Sjkim BIO *cont; 174280304Sjkim int r; 175280304Sjkim if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) { 176280304Sjkim CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA); 177280304Sjkim return 0; 178280304Sjkim } 179183234Ssimon 180280304Sjkim if (!dcont && !check_content(cms)) 181280304Sjkim return 0; 182183234Ssimon 183280304Sjkim cont = CMS_dataInit(cms, dcont); 184280304Sjkim if (!cont) 185280304Sjkim return 0; 186280304Sjkim r = cms_copy_content(out, cont, flags); 187280304Sjkim if (r) 188280304Sjkim r = cms_DigestedData_do_final(cms, cont, 1); 189280304Sjkim do_free_upto(cont, dcont); 190280304Sjkim return r; 191280304Sjkim} 192183234Ssimon 193183234SsimonCMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, 194280304Sjkim unsigned int flags) 195280304Sjkim{ 196280304Sjkim CMS_ContentInfo *cms; 197280304Sjkim if (!md) 198280304Sjkim md = EVP_sha1(); 199280304Sjkim cms = cms_DigestedData_create(md); 200280304Sjkim if (!cms) 201280304Sjkim return NULL; 202183234Ssimon 203280304Sjkim if (!(flags & CMS_DETACHED)) 204280304Sjkim CMS_set_detached(cms, 0); 205183234Ssimon 206280304Sjkim if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) 207280304Sjkim return cms; 208183234Ssimon 209280304Sjkim CMS_ContentInfo_free(cms); 210280304Sjkim return NULL; 211280304Sjkim} 212183234Ssimon 213183234Ssimonint CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, 214280304Sjkim const unsigned char *key, size_t keylen, 215280304Sjkim BIO *dcont, BIO *out, unsigned int flags) 216280304Sjkim{ 217280304Sjkim BIO *cont; 218280304Sjkim int r; 219280304Sjkim if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) { 220280304Sjkim CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT, 221280304Sjkim CMS_R_TYPE_NOT_ENCRYPTED_DATA); 222280304Sjkim return 0; 223280304Sjkim } 224183234Ssimon 225280304Sjkim if (!dcont && !check_content(cms)) 226280304Sjkim return 0; 227183234Ssimon 228280304Sjkim if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0) 229280304Sjkim return 0; 230280304Sjkim cont = CMS_dataInit(cms, dcont); 231280304Sjkim if (!cont) 232280304Sjkim return 0; 233280304Sjkim r = cms_copy_content(out, cont, flags); 234280304Sjkim do_free_upto(cont, dcont); 235280304Sjkim return r; 236280304Sjkim} 237183234Ssimon 238183234SsimonCMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, 239280304Sjkim const unsigned char *key, 240280304Sjkim size_t keylen, unsigned int flags) 241280304Sjkim{ 242280304Sjkim CMS_ContentInfo *cms; 243280304Sjkim if (!cipher) { 244280304Sjkim CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER); 245280304Sjkim return NULL; 246280304Sjkim } 247280304Sjkim cms = CMS_ContentInfo_new(); 248280304Sjkim if (!cms) 249280304Sjkim return NULL; 250280304Sjkim if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) 251280304Sjkim return NULL; 252183234Ssimon 253280304Sjkim if (!(flags & CMS_DETACHED)) 254280304Sjkim CMS_set_detached(cms, 0); 255183234Ssimon 256280304Sjkim if ((flags & (CMS_STREAM | CMS_PARTIAL)) 257280304Sjkim || CMS_final(cms, in, NULL, flags)) 258280304Sjkim return cms; 259183234Ssimon 260280304Sjkim CMS_ContentInfo_free(cms); 261280304Sjkim return NULL; 262280304Sjkim} 263183234Ssimon 264183234Ssimonstatic int cms_signerinfo_verify_cert(CMS_SignerInfo *si, 265280304Sjkim X509_STORE *store, 266280304Sjkim STACK_OF(X509) *certs, 267280304Sjkim STACK_OF(X509_CRL) *crls, 268280304Sjkim unsigned int flags) 269280304Sjkim{ 270280304Sjkim X509_STORE_CTX ctx; 271280304Sjkim X509 *signer; 272280304Sjkim int i, j, r = 0; 273280304Sjkim CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); 274280304Sjkim if (!X509_STORE_CTX_init(&ctx, store, signer, certs)) { 275280304Sjkim CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, CMS_R_STORE_INIT_ERROR); 276280304Sjkim goto err; 277280304Sjkim } 278280304Sjkim X509_STORE_CTX_set_default(&ctx, "smime_sign"); 279280304Sjkim if (crls) 280280304Sjkim X509_STORE_CTX_set0_crls(&ctx, crls); 281183234Ssimon 282280304Sjkim i = X509_verify_cert(&ctx); 283280304Sjkim if (i <= 0) { 284280304Sjkim j = X509_STORE_CTX_get_error(&ctx); 285280304Sjkim CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, 286280304Sjkim CMS_R_CERTIFICATE_VERIFY_ERROR); 287280304Sjkim ERR_add_error_data(2, "Verify error:", 288280304Sjkim X509_verify_cert_error_string(j)); 289280304Sjkim goto err; 290280304Sjkim } 291280304Sjkim r = 1; 292280304Sjkim err: 293280304Sjkim X509_STORE_CTX_cleanup(&ctx); 294280304Sjkim return r; 295183234Ssimon 296280304Sjkim} 297183234Ssimon 298183234Ssimonint CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, 299280304Sjkim X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags) 300280304Sjkim{ 301280304Sjkim CMS_SignerInfo *si; 302280304Sjkim STACK_OF(CMS_SignerInfo) *sinfos; 303280304Sjkim STACK_OF(X509) *cms_certs = NULL; 304280304Sjkim STACK_OF(X509_CRL) *crls = NULL; 305280304Sjkim X509 *signer; 306280304Sjkim int i, scount = 0, ret = 0; 307280304Sjkim BIO *cmsbio = NULL, *tmpin = NULL; 308183234Ssimon 309280304Sjkim if (!dcont && !check_content(cms)) 310280304Sjkim return 0; 311183234Ssimon 312280304Sjkim /* Attempt to find all signer certificates */ 313183234Ssimon 314280304Sjkim sinfos = CMS_get0_SignerInfos(cms); 315183234Ssimon 316280304Sjkim if (sk_CMS_SignerInfo_num(sinfos) <= 0) { 317280304Sjkim CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS); 318280304Sjkim goto err; 319280304Sjkim } 320183234Ssimon 321280304Sjkim for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 322280304Sjkim si = sk_CMS_SignerInfo_value(sinfos, i); 323280304Sjkim CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); 324280304Sjkim if (signer) 325280304Sjkim scount++; 326280304Sjkim } 327183234Ssimon 328280304Sjkim if (scount != sk_CMS_SignerInfo_num(sinfos)) 329280304Sjkim scount += CMS_set1_signers_certs(cms, certs, flags); 330183234Ssimon 331280304Sjkim if (scount != sk_CMS_SignerInfo_num(sinfos)) { 332280304Sjkim CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND); 333280304Sjkim goto err; 334280304Sjkim } 335183234Ssimon 336280304Sjkim /* Attempt to verify all signers certs */ 337183234Ssimon 338280304Sjkim if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) { 339280304Sjkim cms_certs = CMS_get1_certs(cms); 340280304Sjkim if (!(flags & CMS_NOCRL)) 341280304Sjkim crls = CMS_get1_crls(cms); 342280304Sjkim for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 343280304Sjkim si = sk_CMS_SignerInfo_value(sinfos, i); 344280304Sjkim if (!cms_signerinfo_verify_cert(si, store, 345280304Sjkim cms_certs, crls, flags)) 346280304Sjkim goto err; 347280304Sjkim } 348280304Sjkim } 349183234Ssimon 350280304Sjkim /* Attempt to verify all SignerInfo signed attribute signatures */ 351183234Ssimon 352280304Sjkim if (!(flags & CMS_NO_ATTR_VERIFY)) { 353280304Sjkim for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 354280304Sjkim si = sk_CMS_SignerInfo_value(sinfos, i); 355280304Sjkim if (CMS_signed_get_attr_count(si) < 0) 356280304Sjkim continue; 357280304Sjkim if (CMS_SignerInfo_verify(si) <= 0) 358280304Sjkim goto err; 359280304Sjkim } 360280304Sjkim } 361183234Ssimon 362280304Sjkim /* 363280304Sjkim * Performance optimization: if the content is a memory BIO then store 364280304Sjkim * its contents in a temporary read only memory BIO. This avoids 365280304Sjkim * potentially large numbers of slow copies of data which will occur when 366280304Sjkim * reading from a read write memory BIO when signatures are calculated. 367280304Sjkim */ 368183234Ssimon 369280304Sjkim if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) { 370280304Sjkim char *ptr; 371280304Sjkim long len; 372280304Sjkim len = BIO_get_mem_data(dcont, &ptr); 373280304Sjkim tmpin = BIO_new_mem_buf(ptr, len); 374280304Sjkim if (tmpin == NULL) { 375280304Sjkim CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE); 376280304Sjkim return 0; 377280304Sjkim } 378280304Sjkim } else 379280304Sjkim tmpin = dcont; 380183234Ssimon 381280304Sjkim cmsbio = CMS_dataInit(cms, tmpin); 382280304Sjkim if (!cmsbio) 383280304Sjkim goto err; 384183234Ssimon 385280304Sjkim if (!cms_copy_content(out, cmsbio, flags)) 386280304Sjkim goto err; 387183234Ssimon 388280304Sjkim if (!(flags & CMS_NO_CONTENT_VERIFY)) { 389280304Sjkim for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 390280304Sjkim si = sk_CMS_SignerInfo_value(sinfos, i); 391280304Sjkim if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) { 392280304Sjkim CMSerr(CMS_F_CMS_VERIFY, CMS_R_CONTENT_VERIFY_ERROR); 393280304Sjkim goto err; 394280304Sjkim } 395280304Sjkim } 396280304Sjkim } 397183234Ssimon 398280304Sjkim ret = 1; 399183234Ssimon 400280304Sjkim err: 401183234Ssimon 402280304Sjkim if (dcont && (tmpin == dcont)) 403280304Sjkim do_free_upto(cmsbio, dcont); 404280304Sjkim else 405280304Sjkim BIO_free_all(cmsbio); 406183234Ssimon 407280304Sjkim if (cms_certs) 408280304Sjkim sk_X509_pop_free(cms_certs, X509_free); 409280304Sjkim if (crls) 410280304Sjkim sk_X509_CRL_pop_free(crls, X509_CRL_free); 411183234Ssimon 412280304Sjkim return ret; 413280304Sjkim} 414280304Sjkim 415183234Ssimonint CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, 416280304Sjkim STACK_OF(X509) *certs, 417280304Sjkim X509_STORE *store, unsigned int flags) 418280304Sjkim{ 419280304Sjkim int r; 420280304Sjkim flags &= ~(CMS_DETACHED | CMS_TEXT); 421280304Sjkim r = CMS_verify(rcms, certs, store, NULL, NULL, flags); 422280304Sjkim if (r <= 0) 423280304Sjkim return r; 424280304Sjkim return cms_Receipt_verify(rcms, ocms); 425280304Sjkim} 426183234Ssimon 427280304SjkimCMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, 428280304Sjkim STACK_OF(X509) *certs, BIO *data, 429280304Sjkim unsigned int flags) 430280304Sjkim{ 431280304Sjkim CMS_ContentInfo *cms; 432280304Sjkim int i; 433183234Ssimon 434280304Sjkim cms = CMS_ContentInfo_new(); 435280304Sjkim if (!cms || !CMS_SignedData_init(cms)) 436280304Sjkim goto merr; 437183234Ssimon 438280304Sjkim if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) { 439280304Sjkim CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR); 440280304Sjkim goto err; 441280304Sjkim } 442183234Ssimon 443280304Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 444280304Sjkim X509 *x = sk_X509_value(certs, i); 445280304Sjkim if (!CMS_add1_cert(cms, x)) 446280304Sjkim goto merr; 447280304Sjkim } 448183234Ssimon 449280304Sjkim if (!(flags & CMS_DETACHED)) 450280304Sjkim CMS_set_detached(cms, 0); 451183234Ssimon 452280304Sjkim if ((flags & (CMS_STREAM | CMS_PARTIAL)) 453280304Sjkim || CMS_final(cms, data, NULL, flags)) 454280304Sjkim return cms; 455280304Sjkim else 456280304Sjkim goto err; 457183234Ssimon 458280304Sjkim merr: 459280304Sjkim CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE); 460183234Ssimon 461280304Sjkim err: 462280304Sjkim if (cms) 463280304Sjkim CMS_ContentInfo_free(cms); 464280304Sjkim return NULL; 465280304Sjkim} 466183234Ssimon 467183234SsimonCMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, 468280304Sjkim X509 *signcert, EVP_PKEY *pkey, 469280304Sjkim STACK_OF(X509) *certs, unsigned int flags) 470280304Sjkim{ 471280304Sjkim CMS_SignerInfo *rct_si; 472280304Sjkim CMS_ContentInfo *cms = NULL; 473280304Sjkim ASN1_OCTET_STRING **pos, *os; 474280304Sjkim BIO *rct_cont = NULL; 475280304Sjkim int r = 0; 476183234Ssimon 477280304Sjkim flags &= ~(CMS_STREAM | CMS_TEXT); 478280304Sjkim /* Not really detached but avoids content being allocated */ 479280304Sjkim flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED; 480280304Sjkim if (!pkey || !signcert) { 481280304Sjkim CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT); 482280304Sjkim return NULL; 483280304Sjkim } 484183234Ssimon 485280304Sjkim /* Initialize signed data */ 486183234Ssimon 487280304Sjkim cms = CMS_sign(NULL, NULL, certs, NULL, flags); 488280304Sjkim if (!cms) 489280304Sjkim goto err; 490183234Ssimon 491280304Sjkim /* Set inner content type to signed receipt */ 492280304Sjkim if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt))) 493280304Sjkim goto err; 494183234Ssimon 495280304Sjkim rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags); 496280304Sjkim if (!rct_si) { 497280304Sjkim CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR); 498280304Sjkim goto err; 499280304Sjkim } 500183234Ssimon 501280304Sjkim os = cms_encode_Receipt(si); 502183234Ssimon 503280304Sjkim if (!os) 504280304Sjkim goto err; 505183234Ssimon 506280304Sjkim /* Set content to digest */ 507280304Sjkim rct_cont = BIO_new_mem_buf(os->data, os->length); 508280304Sjkim if (!rct_cont) 509280304Sjkim goto err; 510183234Ssimon 511280304Sjkim /* Add msgSigDigest attribute */ 512183234Ssimon 513280304Sjkim if (!cms_msgSigDigest_add1(rct_si, si)) 514280304Sjkim goto err; 515183234Ssimon 516280304Sjkim /* Finalize structure */ 517280304Sjkim if (!CMS_final(cms, rct_cont, NULL, flags)) 518280304Sjkim goto err; 519183234Ssimon 520280304Sjkim /* Set embedded content */ 521280304Sjkim pos = CMS_get0_content(cms); 522280304Sjkim *pos = os; 523183234Ssimon 524280304Sjkim r = 1; 525183234Ssimon 526280304Sjkim err: 527280304Sjkim if (rct_cont) 528280304Sjkim BIO_free(rct_cont); 529280304Sjkim if (r) 530280304Sjkim return cms; 531280304Sjkim CMS_ContentInfo_free(cms); 532280304Sjkim return NULL; 533183234Ssimon 534280304Sjkim} 535183234Ssimon 536183234SsimonCMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, 537280304Sjkim const EVP_CIPHER *cipher, unsigned int flags) 538280304Sjkim{ 539280304Sjkim CMS_ContentInfo *cms; 540280304Sjkim int i; 541280304Sjkim X509 *recip; 542280304Sjkim cms = CMS_EnvelopedData_create(cipher); 543280304Sjkim if (!cms) 544280304Sjkim goto merr; 545280304Sjkim for (i = 0; i < sk_X509_num(certs); i++) { 546280304Sjkim recip = sk_X509_value(certs, i); 547280304Sjkim if (!CMS_add1_recipient_cert(cms, recip, flags)) { 548280304Sjkim CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR); 549280304Sjkim goto err; 550280304Sjkim } 551280304Sjkim } 552183234Ssimon 553280304Sjkim if (!(flags & CMS_DETACHED)) 554280304Sjkim CMS_set_detached(cms, 0); 555183234Ssimon 556280304Sjkim if ((flags & (CMS_STREAM | CMS_PARTIAL)) 557280304Sjkim || CMS_final(cms, data, NULL, flags)) 558280304Sjkim return cms; 559280304Sjkim else 560280304Sjkim goto err; 561183234Ssimon 562280304Sjkim merr: 563280304Sjkim CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE); 564280304Sjkim err: 565280304Sjkim if (cms) 566280304Sjkim CMS_ContentInfo_free(cms); 567280304Sjkim return NULL; 568280304Sjkim} 569183234Ssimon 570183234Ssimonint CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) 571280304Sjkim{ 572280304Sjkim STACK_OF(CMS_RecipientInfo) *ris; 573280304Sjkim CMS_RecipientInfo *ri; 574280304Sjkim int i, r; 575280304Sjkim int debug = 0, ri_match = 0; 576280304Sjkim ris = CMS_get0_RecipientInfos(cms); 577280304Sjkim if (ris) 578280304Sjkim debug = cms->d.envelopedData->encryptedContentInfo->debug; 579280304Sjkim for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { 580280304Sjkim ri = sk_CMS_RecipientInfo_value(ris, i); 581280304Sjkim if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS) 582280304Sjkim continue; 583280304Sjkim ri_match = 1; 584280304Sjkim /* 585280304Sjkim * If we have a cert try matching RecipientInfo otherwise try them 586280304Sjkim * all. 587280304Sjkim */ 588280304Sjkim if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) { 589280304Sjkim CMS_RecipientInfo_set0_pkey(ri, pk); 590280304Sjkim r = CMS_RecipientInfo_decrypt(cms, ri); 591280304Sjkim CMS_RecipientInfo_set0_pkey(ri, NULL); 592280304Sjkim if (cert) { 593280304Sjkim /* 594280304Sjkim * If not debugging clear any error and return success to 595280304Sjkim * avoid leaking of information useful to MMA 596280304Sjkim */ 597280304Sjkim if (!debug) { 598280304Sjkim ERR_clear_error(); 599280304Sjkim return 1; 600280304Sjkim } 601280304Sjkim if (r > 0) 602280304Sjkim return 1; 603280304Sjkim CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR); 604280304Sjkim return 0; 605280304Sjkim } 606280304Sjkim /* 607280304Sjkim * If no cert and not debugging don't leave loop after first 608280304Sjkim * successful decrypt. Always attempt to decrypt all recipients 609280304Sjkim * to avoid leaking timing of a successful decrypt. 610280304Sjkim */ 611280304Sjkim else if (r > 0 && debug) 612280304Sjkim return 1; 613280304Sjkim } 614280304Sjkim } 615280304Sjkim /* If no cert and not debugging always return success */ 616280304Sjkim if (ri_match && !cert && !debug) { 617280304Sjkim ERR_clear_error(); 618280304Sjkim return 1; 619280304Sjkim } 620183234Ssimon 621280304Sjkim CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT); 622280304Sjkim return 0; 623183234Ssimon 624280304Sjkim} 625183234Ssimon 626280304Sjkimint CMS_decrypt_set1_key(CMS_ContentInfo *cms, 627280304Sjkim unsigned char *key, size_t keylen, 628280304Sjkim unsigned char *id, size_t idlen) 629280304Sjkim{ 630280304Sjkim STACK_OF(CMS_RecipientInfo) *ris; 631280304Sjkim CMS_RecipientInfo *ri; 632280304Sjkim int i, r; 633280304Sjkim ris = CMS_get0_RecipientInfos(cms); 634280304Sjkim for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { 635280304Sjkim ri = sk_CMS_RecipientInfo_value(ris, i); 636280304Sjkim if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK) 637280304Sjkim continue; 638183234Ssimon 639280304Sjkim /* 640280304Sjkim * If we have an id try matching RecipientInfo otherwise try them 641280304Sjkim * all. 642280304Sjkim */ 643280304Sjkim if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) { 644280304Sjkim CMS_RecipientInfo_set0_key(ri, key, keylen); 645280304Sjkim r = CMS_RecipientInfo_decrypt(cms, ri); 646280304Sjkim CMS_RecipientInfo_set0_key(ri, NULL, 0); 647280304Sjkim if (r > 0) 648280304Sjkim return 1; 649280304Sjkim if (id) { 650280304Sjkim CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_DECRYPT_ERROR); 651280304Sjkim return 0; 652280304Sjkim } 653280304Sjkim ERR_clear_error(); 654280304Sjkim } 655280304Sjkim } 656183234Ssimon 657280304Sjkim CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT); 658280304Sjkim return 0; 659183234Ssimon 660280304Sjkim} 661238405Sjkim 662280304Sjkimint CMS_decrypt_set1_password(CMS_ContentInfo *cms, 663280304Sjkim unsigned char *pass, ossl_ssize_t passlen) 664280304Sjkim{ 665280304Sjkim STACK_OF(CMS_RecipientInfo) *ris; 666280304Sjkim CMS_RecipientInfo *ri; 667280304Sjkim int i, r; 668280304Sjkim ris = CMS_get0_RecipientInfos(cms); 669280304Sjkim for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { 670280304Sjkim ri = sk_CMS_RecipientInfo_value(ris, i); 671280304Sjkim if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS) 672280304Sjkim continue; 673280304Sjkim CMS_RecipientInfo_set0_password(ri, pass, passlen); 674280304Sjkim r = CMS_RecipientInfo_decrypt(cms, ri); 675280304Sjkim CMS_RecipientInfo_set0_password(ri, NULL, 0); 676280304Sjkim if (r > 0) 677280304Sjkim return 1; 678280304Sjkim } 679238405Sjkim 680280304Sjkim CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT); 681280304Sjkim return 0; 682238405Sjkim 683280304Sjkim} 684280304Sjkim 685183234Ssimonint CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, 686280304Sjkim BIO *dcont, BIO *out, unsigned int flags) 687280304Sjkim{ 688280304Sjkim int r; 689280304Sjkim BIO *cont; 690280304Sjkim if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) { 691280304Sjkim CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA); 692280304Sjkim return 0; 693280304Sjkim } 694280304Sjkim if (!dcont && !check_content(cms)) 695280304Sjkim return 0; 696280304Sjkim if (flags & CMS_DEBUG_DECRYPT) 697280304Sjkim cms->d.envelopedData->encryptedContentInfo->debug = 1; 698280304Sjkim else 699280304Sjkim cms->d.envelopedData->encryptedContentInfo->debug = 0; 700280304Sjkim if (!pk && !cert && !dcont && !out) 701280304Sjkim return 1; 702280304Sjkim if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert)) 703280304Sjkim return 0; 704280304Sjkim cont = CMS_dataInit(cms, dcont); 705280304Sjkim if (!cont) 706280304Sjkim return 0; 707280304Sjkim r = cms_copy_content(out, cont, flags); 708280304Sjkim do_free_upto(cont, dcont); 709280304Sjkim return r; 710280304Sjkim} 711183234Ssimon 712183234Ssimonint CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags) 713280304Sjkim{ 714280304Sjkim BIO *cmsbio; 715280304Sjkim int ret = 0; 716280304Sjkim if (!(cmsbio = CMS_dataInit(cms, dcont))) { 717291721Sjkim CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_LIB); 718280304Sjkim return 0; 719280304Sjkim } 720183234Ssimon 721280304Sjkim SMIME_crlf_copy(data, cmsbio, flags); 722183234Ssimon 723280304Sjkim (void)BIO_flush(cmsbio); 724183234Ssimon 725280304Sjkim if (!CMS_dataFinal(cms, cmsbio)) { 726280304Sjkim CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_DATAFINAL_ERROR); 727280304Sjkim goto err; 728280304Sjkim } 729183234Ssimon 730280304Sjkim ret = 1; 731183234Ssimon 732280304Sjkim err: 733280304Sjkim do_free_upto(cmsbio, dcont); 734183234Ssimon 735280304Sjkim return ret; 736183234Ssimon 737280304Sjkim} 738183234Ssimon 739183234Ssimon#ifdef ZLIB 740183234Ssimon 741183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 742280304Sjkim unsigned int flags) 743280304Sjkim{ 744280304Sjkim BIO *cont; 745280304Sjkim int r; 746280304Sjkim if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) { 747280304Sjkim CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_TYPE_NOT_COMPRESSED_DATA); 748280304Sjkim return 0; 749280304Sjkim } 750183234Ssimon 751280304Sjkim if (!dcont && !check_content(cms)) 752280304Sjkim return 0; 753183234Ssimon 754280304Sjkim cont = CMS_dataInit(cms, dcont); 755280304Sjkim if (!cont) 756280304Sjkim return 0; 757280304Sjkim r = cms_copy_content(out, cont, flags); 758280304Sjkim do_free_upto(cont, dcont); 759280304Sjkim return r; 760280304Sjkim} 761183234Ssimon 762183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) 763280304Sjkim{ 764280304Sjkim CMS_ContentInfo *cms; 765280304Sjkim if (comp_nid <= 0) 766280304Sjkim comp_nid = NID_zlib_compression; 767280304Sjkim cms = cms_CompressedData_create(comp_nid); 768280304Sjkim if (!cms) 769280304Sjkim return NULL; 770183234Ssimon 771280304Sjkim if (!(flags & CMS_DETACHED)) 772280304Sjkim CMS_set_detached(cms, 0); 773183234Ssimon 774280304Sjkim if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) 775280304Sjkim return cms; 776183234Ssimon 777280304Sjkim CMS_ContentInfo_free(cms); 778280304Sjkim return NULL; 779280304Sjkim} 780183234Ssimon 781183234Ssimon#else 782183234Ssimon 783183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 784280304Sjkim unsigned int flags) 785280304Sjkim{ 786280304Sjkim CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); 787280304Sjkim return 0; 788280304Sjkim} 789183234Ssimon 790183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) 791280304Sjkim{ 792280304Sjkim CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); 793280304Sjkim return NULL; 794280304Sjkim} 795183234Ssimon 796183234Ssimon#endif 797