cms_smime.c revision 183234
1183234Ssimon/* crypto/cms/cms_smime.c */ 2183234Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3183234Ssimon * project. 4183234Ssimon */ 5183234Ssimon/* ==================================================================== 6183234Ssimon * Copyright (c) 2008 The OpenSSL Project. All rights reserved. 7183234Ssimon * 8183234Ssimon * Redistribution and use in source and binary forms, with or without 9183234Ssimon * modification, are permitted provided that the following conditions 10183234Ssimon * are met: 11183234Ssimon * 12183234Ssimon * 1. Redistributions of source code must retain the above copyright 13183234Ssimon * notice, this list of conditions and the following disclaimer. 14183234Ssimon * 15183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright 16183234Ssimon * notice, this list of conditions and the following disclaimer in 17183234Ssimon * the documentation and/or other materials provided with the 18183234Ssimon * distribution. 19183234Ssimon * 20183234Ssimon * 3. All advertising materials mentioning features or use of this 21183234Ssimon * software must display the following acknowledgment: 22183234Ssimon * "This product includes software developed by the OpenSSL Project 23183234Ssimon * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24183234Ssimon * 25183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26183234Ssimon * endorse or promote products derived from this software without 27183234Ssimon * prior written permission. For written permission, please contact 28183234Ssimon * licensing@OpenSSL.org. 29183234Ssimon * 30183234Ssimon * 5. Products derived from this software may not be called "OpenSSL" 31183234Ssimon * nor may "OpenSSL" appear in their names without prior written 32183234Ssimon * permission of the OpenSSL Project. 33183234Ssimon * 34183234Ssimon * 6. Redistributions of any form whatsoever must retain the following 35183234Ssimon * acknowledgment: 36183234Ssimon * "This product includes software developed by the OpenSSL Project 37183234Ssimon * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38183234Ssimon * 39183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42183234Ssimon * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE. 51183234Ssimon * ==================================================================== 52183234Ssimon */ 53183234Ssimon 54183234Ssimon#include "cryptlib.h" 55183234Ssimon#include <openssl/asn1t.h> 56183234Ssimon#include <openssl/x509.h> 57183234Ssimon#include <openssl/x509v3.h> 58183234Ssimon#include <openssl/err.h> 59183234Ssimon#include <openssl/cms.h> 60183234Ssimon#include "cms_lcl.h" 61183234Ssimon 62183234Ssimonstatic int cms_copy_content(BIO *out, BIO *in, unsigned int flags) 63183234Ssimon { 64183234Ssimon unsigned char buf[4096]; 65183234Ssimon int r = 0, i; 66183234Ssimon BIO *tmpout = NULL; 67183234Ssimon 68183234Ssimon if (out == NULL) 69183234Ssimon tmpout = BIO_new(BIO_s_null()); 70183234Ssimon else if (flags & CMS_TEXT) 71183234Ssimon tmpout = BIO_new(BIO_s_mem()); 72183234Ssimon else 73183234Ssimon tmpout = out; 74183234Ssimon 75183234Ssimon if(!tmpout) 76183234Ssimon { 77183234Ssimon CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE); 78183234Ssimon goto err; 79183234Ssimon } 80183234Ssimon 81183234Ssimon /* Read all content through chain to process digest, decrypt etc */ 82183234Ssimon for (;;) 83183234Ssimon { 84183234Ssimon i=BIO_read(in,buf,sizeof(buf)); 85183234Ssimon if (i <= 0) 86183234Ssimon { 87183234Ssimon if (BIO_method_type(in) == BIO_TYPE_CIPHER) 88183234Ssimon { 89183234Ssimon if (!BIO_get_cipher_status(in)) 90183234Ssimon goto err; 91183234Ssimon } 92183234Ssimon if (i < 0) 93183234Ssimon goto err; 94183234Ssimon break; 95183234Ssimon } 96183234Ssimon 97183234Ssimon if (tmpout && (BIO_write(tmpout, buf, i) != i)) 98183234Ssimon goto err; 99183234Ssimon } 100183234Ssimon 101183234Ssimon if(flags & CMS_TEXT) 102183234Ssimon { 103183234Ssimon if(!SMIME_text(tmpout, out)) 104183234Ssimon { 105183234Ssimon CMSerr(CMS_F_CMS_COPY_CONTENT,CMS_R_SMIME_TEXT_ERROR); 106183234Ssimon goto err; 107183234Ssimon } 108183234Ssimon } 109183234Ssimon 110183234Ssimon r = 1; 111183234Ssimon 112183234Ssimon err: 113183234Ssimon if (tmpout && (tmpout != out)) 114183234Ssimon BIO_free(tmpout); 115183234Ssimon return r; 116183234Ssimon 117183234Ssimon } 118183234Ssimon 119183234Ssimonstatic int check_content(CMS_ContentInfo *cms) 120183234Ssimon { 121183234Ssimon ASN1_OCTET_STRING **pos = CMS_get0_content(cms); 122183234Ssimon if (!pos || !*pos) 123183234Ssimon { 124183234Ssimon CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT); 125183234Ssimon return 0; 126183234Ssimon } 127183234Ssimon return 1; 128183234Ssimon } 129183234Ssimon 130183234Ssimonstatic void do_free_upto(BIO *f, BIO *upto) 131183234Ssimon { 132183234Ssimon if (upto) 133183234Ssimon { 134183234Ssimon BIO *tbio; 135183234Ssimon do 136183234Ssimon { 137183234Ssimon tbio = BIO_pop(f); 138183234Ssimon BIO_free(f); 139183234Ssimon f = tbio; 140183234Ssimon } 141183234Ssimon while (f != upto); 142183234Ssimon } 143183234Ssimon else 144183234Ssimon BIO_free_all(f); 145183234Ssimon } 146183234Ssimon 147183234Ssimonint CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags) 148183234Ssimon { 149183234Ssimon BIO *cont; 150183234Ssimon int r; 151183234Ssimon if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) 152183234Ssimon { 153183234Ssimon CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA); 154183234Ssimon return 0; 155183234Ssimon } 156183234Ssimon cont = CMS_dataInit(cms, NULL); 157183234Ssimon if (!cont) 158183234Ssimon return 0; 159183234Ssimon r = cms_copy_content(out, cont, flags); 160183234Ssimon BIO_free_all(cont); 161183234Ssimon return r; 162183234Ssimon } 163183234Ssimon 164183234SsimonCMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags) 165183234Ssimon { 166183234Ssimon CMS_ContentInfo *cms; 167183234Ssimon cms = cms_Data_create(); 168183234Ssimon if (!cms) 169183234Ssimon return NULL; 170183234Ssimon 171183234Ssimon if (CMS_final(cms, in, NULL, flags)) 172183234Ssimon return cms; 173183234Ssimon 174183234Ssimon CMS_ContentInfo_free(cms); 175183234Ssimon 176183234Ssimon return NULL; 177183234Ssimon } 178183234Ssimon 179183234Ssimonint CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 180183234Ssimon unsigned int flags) 181183234Ssimon { 182183234Ssimon BIO *cont; 183183234Ssimon int r; 184183234Ssimon if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) 185183234Ssimon { 186183234Ssimon CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA); 187183234Ssimon return 0; 188183234Ssimon } 189183234Ssimon 190183234Ssimon if (!dcont && !check_content(cms)) 191183234Ssimon return 0; 192183234Ssimon 193183234Ssimon cont = CMS_dataInit(cms, dcont); 194183234Ssimon if (!cont) 195183234Ssimon return 0; 196183234Ssimon r = cms_copy_content(out, cont, flags); 197183234Ssimon if (r) 198183234Ssimon r = cms_DigestedData_do_final(cms, cont, 1); 199183234Ssimon do_free_upto(cont, dcont); 200183234Ssimon return r; 201183234Ssimon } 202183234Ssimon 203183234SsimonCMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, 204183234Ssimon unsigned int flags) 205183234Ssimon { 206183234Ssimon CMS_ContentInfo *cms; 207183234Ssimon if (!md) 208183234Ssimon md = EVP_sha1(); 209183234Ssimon cms = cms_DigestedData_create(md); 210183234Ssimon if (!cms) 211183234Ssimon return NULL; 212183234Ssimon 213183234Ssimon if(!(flags & CMS_DETACHED)) 214183234Ssimon { 215183234Ssimon flags &= ~CMS_STREAM; 216183234Ssimon CMS_set_detached(cms, 0); 217183234Ssimon } 218183234Ssimon 219183234Ssimon if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) 220183234Ssimon return cms; 221183234Ssimon 222183234Ssimon CMS_ContentInfo_free(cms); 223183234Ssimon return NULL; 224183234Ssimon } 225183234Ssimon 226183234Ssimonint CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, 227183234Ssimon const unsigned char *key, size_t keylen, 228183234Ssimon BIO *dcont, BIO *out, unsigned int flags) 229183234Ssimon { 230183234Ssimon BIO *cont; 231183234Ssimon int r; 232183234Ssimon if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) 233183234Ssimon { 234183234Ssimon CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT, 235183234Ssimon CMS_R_TYPE_NOT_ENCRYPTED_DATA); 236183234Ssimon return 0; 237183234Ssimon } 238183234Ssimon 239183234Ssimon if (!dcont && !check_content(cms)) 240183234Ssimon return 0; 241183234Ssimon 242183234Ssimon if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0) 243183234Ssimon return 0; 244183234Ssimon cont = CMS_dataInit(cms, dcont); 245183234Ssimon if (!cont) 246183234Ssimon return 0; 247183234Ssimon r = cms_copy_content(out, cont, flags); 248183234Ssimon do_free_upto(cont, dcont); 249183234Ssimon return r; 250183234Ssimon } 251183234Ssimon 252183234SsimonCMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, 253183234Ssimon const unsigned char *key, size_t keylen, 254183234Ssimon unsigned int flags) 255183234Ssimon { 256183234Ssimon CMS_ContentInfo *cms; 257183234Ssimon if (!cipher) 258183234Ssimon { 259183234Ssimon CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER); 260183234Ssimon return NULL; 261183234Ssimon } 262183234Ssimon cms = CMS_ContentInfo_new(); 263183234Ssimon if (!cms) 264183234Ssimon return NULL; 265183234Ssimon if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) 266183234Ssimon return NULL; 267183234Ssimon 268183234Ssimon if(!(flags & CMS_DETACHED)) 269183234Ssimon { 270183234Ssimon flags &= ~CMS_STREAM; 271183234Ssimon CMS_set_detached(cms, 0); 272183234Ssimon } 273183234Ssimon 274183234Ssimon if ((flags & (CMS_STREAM|CMS_PARTIAL)) 275183234Ssimon || CMS_final(cms, in, NULL, flags)) 276183234Ssimon return cms; 277183234Ssimon 278183234Ssimon CMS_ContentInfo_free(cms); 279183234Ssimon return NULL; 280183234Ssimon } 281183234Ssimon 282183234Ssimonstatic int cms_signerinfo_verify_cert(CMS_SignerInfo *si, 283183234Ssimon X509_STORE *store, 284183234Ssimon STACK_OF(X509) *certs, 285183234Ssimon STACK_OF(X509_CRL) *crls, 286183234Ssimon unsigned int flags) 287183234Ssimon { 288183234Ssimon X509_STORE_CTX ctx; 289183234Ssimon X509 *signer; 290183234Ssimon int i, j, r = 0; 291183234Ssimon CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); 292183234Ssimon if (!X509_STORE_CTX_init(&ctx, store, signer, certs)) 293183234Ssimon { 294183234Ssimon CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, 295183234Ssimon CMS_R_STORE_INIT_ERROR); 296183234Ssimon goto err; 297183234Ssimon } 298183234Ssimon X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_SMIME_SIGN); 299183234Ssimon if (crls) 300183234Ssimon X509_STORE_CTX_set0_crls(&ctx, crls); 301183234Ssimon 302183234Ssimon i = X509_verify_cert(&ctx); 303183234Ssimon if (i <= 0) 304183234Ssimon { 305183234Ssimon j = X509_STORE_CTX_get_error(&ctx); 306183234Ssimon CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, 307183234Ssimon CMS_R_CERTIFICATE_VERIFY_ERROR); 308183234Ssimon ERR_add_error_data(2, "Verify error:", 309183234Ssimon X509_verify_cert_error_string(j)); 310183234Ssimon goto err; 311183234Ssimon } 312183234Ssimon r = 1; 313183234Ssimon err: 314183234Ssimon X509_STORE_CTX_cleanup(&ctx); 315183234Ssimon return r; 316183234Ssimon 317183234Ssimon } 318183234Ssimon 319183234Ssimonint CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, 320183234Ssimon X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags) 321183234Ssimon { 322183234Ssimon CMS_SignerInfo *si; 323183234Ssimon STACK_OF(CMS_SignerInfo) *sinfos; 324183234Ssimon STACK_OF(X509) *cms_certs = NULL; 325183234Ssimon STACK_OF(X509_CRL) *crls = NULL; 326183234Ssimon X509 *signer; 327183234Ssimon int i, scount = 0, ret = 0; 328183234Ssimon BIO *cmsbio = NULL, *tmpin = NULL; 329183234Ssimon 330183234Ssimon if (!dcont && !check_content(cms)) 331183234Ssimon return 0; 332183234Ssimon 333183234Ssimon /* Attempt to find all signer certificates */ 334183234Ssimon 335183234Ssimon sinfos = CMS_get0_SignerInfos(cms); 336183234Ssimon 337183234Ssimon if (sk_CMS_SignerInfo_num(sinfos) <= 0) 338183234Ssimon { 339183234Ssimon CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS); 340183234Ssimon goto err; 341183234Ssimon } 342183234Ssimon 343183234Ssimon for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) 344183234Ssimon { 345183234Ssimon si = sk_CMS_SignerInfo_value(sinfos, i); 346183234Ssimon CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); 347183234Ssimon if (signer) 348183234Ssimon scount++; 349183234Ssimon } 350183234Ssimon 351183234Ssimon if (scount != sk_CMS_SignerInfo_num(sinfos)) 352183234Ssimon scount += CMS_set1_signers_certs(cms, certs, flags); 353183234Ssimon 354183234Ssimon if (scount != sk_CMS_SignerInfo_num(sinfos)) 355183234Ssimon { 356183234Ssimon CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND); 357183234Ssimon goto err; 358183234Ssimon } 359183234Ssimon 360183234Ssimon /* Attempt to verify all signers certs */ 361183234Ssimon 362183234Ssimon if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) 363183234Ssimon { 364183234Ssimon cms_certs = CMS_get1_certs(cms); 365183234Ssimon if (!(flags & CMS_NOCRL)) 366183234Ssimon crls = CMS_get1_crls(cms); 367183234Ssimon for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) 368183234Ssimon { 369183234Ssimon si = sk_CMS_SignerInfo_value(sinfos, i); 370183234Ssimon if (!cms_signerinfo_verify_cert(si, store, 371183234Ssimon cms_certs, crls, flags)) 372183234Ssimon goto err; 373183234Ssimon } 374183234Ssimon } 375183234Ssimon 376183234Ssimon /* Attempt to verify all SignerInfo signed attribute signatures */ 377183234Ssimon 378183234Ssimon if (!(flags & CMS_NO_ATTR_VERIFY)) 379183234Ssimon { 380183234Ssimon for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) 381183234Ssimon { 382183234Ssimon si = sk_CMS_SignerInfo_value(sinfos, i); 383183234Ssimon if (CMS_signed_get_attr_count(si) < 0) 384183234Ssimon continue; 385183234Ssimon if (CMS_SignerInfo_verify(si) <= 0) 386183234Ssimon goto err; 387183234Ssimon } 388183234Ssimon } 389183234Ssimon 390183234Ssimon /* Performance optimization: if the content is a memory BIO then 391183234Ssimon * store its contents in a temporary read only memory BIO. This 392183234Ssimon * avoids potentially large numbers of slow copies of data which will 393183234Ssimon * occur when reading from a read write memory BIO when signatures 394183234Ssimon * are calculated. 395183234Ssimon */ 396183234Ssimon 397183234Ssimon if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) 398183234Ssimon { 399183234Ssimon char *ptr; 400183234Ssimon long len; 401183234Ssimon len = BIO_get_mem_data(dcont, &ptr); 402183234Ssimon tmpin = BIO_new_mem_buf(ptr, len); 403183234Ssimon if (tmpin == NULL) 404183234Ssimon { 405183234Ssimon CMSerr(CMS_F_CMS_VERIFY,ERR_R_MALLOC_FAILURE); 406183234Ssimon return 0; 407183234Ssimon } 408183234Ssimon } 409183234Ssimon else 410183234Ssimon tmpin = dcont; 411183234Ssimon 412183234Ssimon 413183234Ssimon cmsbio=CMS_dataInit(cms, tmpin); 414183234Ssimon if (!cmsbio) 415183234Ssimon goto err; 416183234Ssimon 417183234Ssimon if (!cms_copy_content(out, cmsbio, flags)) 418183234Ssimon goto err; 419183234Ssimon 420183234Ssimon if (!(flags & CMS_NO_CONTENT_VERIFY)) 421183234Ssimon { 422183234Ssimon for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) 423183234Ssimon { 424183234Ssimon si = sk_CMS_SignerInfo_value(sinfos, i); 425183234Ssimon if (!CMS_SignerInfo_verify_content(si, cmsbio)) 426183234Ssimon { 427183234Ssimon CMSerr(CMS_F_CMS_VERIFY, 428183234Ssimon CMS_R_CONTENT_VERIFY_ERROR); 429183234Ssimon goto err; 430183234Ssimon } 431183234Ssimon } 432183234Ssimon } 433183234Ssimon 434183234Ssimon ret = 1; 435183234Ssimon 436183234Ssimon err: 437183234Ssimon 438183234Ssimon if (dcont && (tmpin == dcont)) 439183234Ssimon do_free_upto(cmsbio, dcont); 440183234Ssimon else 441183234Ssimon BIO_free_all(cmsbio); 442183234Ssimon 443183234Ssimon if (cms_certs) 444183234Ssimon sk_X509_pop_free(cms_certs, X509_free); 445183234Ssimon if (crls) 446183234Ssimon sk_X509_CRL_pop_free(crls, X509_CRL_free); 447183234Ssimon 448183234Ssimon return ret; 449183234Ssimon } 450183234Ssimon 451183234Ssimonint CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, 452183234Ssimon STACK_OF(X509) *certs, 453183234Ssimon X509_STORE *store, unsigned int flags) 454183234Ssimon { 455183234Ssimon int r; 456183234Ssimon r = CMS_verify(rcms, certs, store, NULL, NULL, flags); 457183234Ssimon if (r <= 0) 458183234Ssimon return r; 459183234Ssimon return cms_Receipt_verify(rcms, ocms); 460183234Ssimon } 461183234Ssimon 462183234SsimonCMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, 463183234Ssimon BIO *data, unsigned int flags) 464183234Ssimon { 465183234Ssimon CMS_ContentInfo *cms; 466183234Ssimon int i; 467183234Ssimon 468183234Ssimon cms = CMS_ContentInfo_new(); 469183234Ssimon if (!cms || !CMS_SignedData_init(cms)) 470183234Ssimon goto merr; 471183234Ssimon 472183234Ssimon if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) 473183234Ssimon { 474183234Ssimon CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR); 475183234Ssimon goto err; 476183234Ssimon } 477183234Ssimon 478183234Ssimon for (i = 0; i < sk_X509_num(certs); i++) 479183234Ssimon { 480183234Ssimon X509 *x = sk_X509_value(certs, i); 481183234Ssimon if (!CMS_add1_cert(cms, x)) 482183234Ssimon goto merr; 483183234Ssimon } 484183234Ssimon 485183234Ssimon if(!(flags & CMS_DETACHED)) 486183234Ssimon { 487183234Ssimon flags &= ~CMS_STREAM; 488183234Ssimon CMS_set_detached(cms, 0); 489183234Ssimon } 490183234Ssimon 491183234Ssimon if ((flags & (CMS_STREAM|CMS_PARTIAL)) 492183234Ssimon || CMS_final(cms, data, NULL, flags)) 493183234Ssimon return cms; 494183234Ssimon else 495183234Ssimon goto err; 496183234Ssimon 497183234Ssimon merr: 498183234Ssimon CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE); 499183234Ssimon 500183234Ssimon err: 501183234Ssimon if (cms) 502183234Ssimon CMS_ContentInfo_free(cms); 503183234Ssimon return NULL; 504183234Ssimon } 505183234Ssimon 506183234SsimonCMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, 507183234Ssimon X509 *signcert, EVP_PKEY *pkey, 508183234Ssimon STACK_OF(X509) *certs, 509183234Ssimon unsigned int flags) 510183234Ssimon { 511183234Ssimon CMS_SignerInfo *rct_si; 512183234Ssimon CMS_ContentInfo *cms = NULL; 513183234Ssimon ASN1_OCTET_STRING **pos, *os; 514183234Ssimon BIO *rct_cont = NULL; 515183234Ssimon int r = 0; 516183234Ssimon 517183234Ssimon flags &= ~CMS_STREAM; 518183234Ssimon /* Not really detached but avoids content being allocated */ 519183234Ssimon flags |= CMS_PARTIAL|CMS_BINARY|CMS_DETACHED; 520183234Ssimon if (!pkey || !signcert) 521183234Ssimon { 522183234Ssimon CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT); 523183234Ssimon return NULL; 524183234Ssimon } 525183234Ssimon 526183234Ssimon /* Initialize signed data */ 527183234Ssimon 528183234Ssimon cms = CMS_sign(NULL, NULL, certs, NULL, flags); 529183234Ssimon if (!cms) 530183234Ssimon goto err; 531183234Ssimon 532183234Ssimon /* Set inner content type to signed receipt */ 533183234Ssimon if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt))) 534183234Ssimon goto err; 535183234Ssimon 536183234Ssimon rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags); 537183234Ssimon if (!rct_si) 538183234Ssimon { 539183234Ssimon CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR); 540183234Ssimon goto err; 541183234Ssimon } 542183234Ssimon 543183234Ssimon os = cms_encode_Receipt(si); 544183234Ssimon 545183234Ssimon if (!os) 546183234Ssimon goto err; 547183234Ssimon 548183234Ssimon /* Set content to digest */ 549183234Ssimon rct_cont = BIO_new_mem_buf(os->data, os->length); 550183234Ssimon if (!rct_cont) 551183234Ssimon goto err; 552183234Ssimon 553183234Ssimon /* Add msgSigDigest attribute */ 554183234Ssimon 555183234Ssimon if (!cms_msgSigDigest_add1(rct_si, si)) 556183234Ssimon goto err; 557183234Ssimon 558183234Ssimon /* Finalize structure */ 559183234Ssimon if (!CMS_final(cms, rct_cont, NULL, flags)) 560183234Ssimon goto err; 561183234Ssimon 562183234Ssimon /* Set embedded content */ 563183234Ssimon pos = CMS_get0_content(cms); 564183234Ssimon *pos = os; 565183234Ssimon 566183234Ssimon r = 1; 567183234Ssimon 568183234Ssimon err: 569183234Ssimon if (rct_cont) 570183234Ssimon BIO_free(rct_cont); 571183234Ssimon if (r) 572183234Ssimon return cms; 573183234Ssimon CMS_ContentInfo_free(cms); 574183234Ssimon return NULL; 575183234Ssimon 576183234Ssimon } 577183234Ssimon 578183234SsimonCMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, 579183234Ssimon const EVP_CIPHER *cipher, unsigned int flags) 580183234Ssimon { 581183234Ssimon CMS_ContentInfo *cms; 582183234Ssimon int i; 583183234Ssimon X509 *recip; 584183234Ssimon cms = CMS_EnvelopedData_create(cipher); 585183234Ssimon if (!cms) 586183234Ssimon goto merr; 587183234Ssimon for (i = 0; i < sk_X509_num(certs); i++) 588183234Ssimon { 589183234Ssimon recip = sk_X509_value(certs, i); 590183234Ssimon if (!CMS_add1_recipient_cert(cms, recip, flags)) 591183234Ssimon { 592183234Ssimon CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR); 593183234Ssimon goto err; 594183234Ssimon } 595183234Ssimon } 596183234Ssimon 597183234Ssimon if(!(flags & CMS_DETACHED)) 598183234Ssimon { 599183234Ssimon flags &= ~CMS_STREAM; 600183234Ssimon CMS_set_detached(cms, 0); 601183234Ssimon } 602183234Ssimon 603183234Ssimon if ((flags & (CMS_STREAM|CMS_PARTIAL)) 604183234Ssimon || CMS_final(cms, data, NULL, flags)) 605183234Ssimon return cms; 606183234Ssimon else 607183234Ssimon goto err; 608183234Ssimon 609183234Ssimon merr: 610183234Ssimon CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE); 611183234Ssimon err: 612183234Ssimon if (cms) 613183234Ssimon CMS_ContentInfo_free(cms); 614183234Ssimon return NULL; 615183234Ssimon } 616183234Ssimon 617183234Ssimonint CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) 618183234Ssimon { 619183234Ssimon STACK_OF(CMS_RecipientInfo) *ris; 620183234Ssimon CMS_RecipientInfo *ri; 621183234Ssimon int i, r; 622183234Ssimon ris = CMS_get0_RecipientInfos(cms); 623183234Ssimon for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) 624183234Ssimon { 625183234Ssimon ri = sk_CMS_RecipientInfo_value(ris, i); 626183234Ssimon if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS) 627183234Ssimon continue; 628183234Ssimon /* If we have a cert try matching RecipientInfo 629183234Ssimon * otherwise try them all. 630183234Ssimon */ 631183234Ssimon if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) 632183234Ssimon { 633183234Ssimon CMS_RecipientInfo_set0_pkey(ri, pk); 634183234Ssimon r = CMS_RecipientInfo_decrypt(cms, ri); 635183234Ssimon CMS_RecipientInfo_set0_pkey(ri, NULL); 636183234Ssimon if (r > 0) 637183234Ssimon return 1; 638183234Ssimon if (cert) 639183234Ssimon { 640183234Ssimon CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, 641183234Ssimon CMS_R_DECRYPT_ERROR); 642183234Ssimon return 0; 643183234Ssimon } 644183234Ssimon ERR_clear_error(); 645183234Ssimon } 646183234Ssimon } 647183234Ssimon 648183234Ssimon CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT); 649183234Ssimon return 0; 650183234Ssimon 651183234Ssimon } 652183234Ssimon 653183234Ssimonint CMS_decrypt_set1_key(CMS_ContentInfo *cms, 654183234Ssimon unsigned char *key, size_t keylen, 655183234Ssimon unsigned char *id, size_t idlen) 656183234Ssimon { 657183234Ssimon STACK_OF(CMS_RecipientInfo) *ris; 658183234Ssimon CMS_RecipientInfo *ri; 659183234Ssimon int i, r; 660183234Ssimon ris = CMS_get0_RecipientInfos(cms); 661183234Ssimon for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) 662183234Ssimon { 663183234Ssimon ri = sk_CMS_RecipientInfo_value(ris, i); 664183234Ssimon if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK) 665183234Ssimon continue; 666183234Ssimon 667183234Ssimon /* If we have an id try matching RecipientInfo 668183234Ssimon * otherwise try them all. 669183234Ssimon */ 670183234Ssimon if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) 671183234Ssimon { 672183234Ssimon CMS_RecipientInfo_set0_key(ri, key, keylen); 673183234Ssimon r = CMS_RecipientInfo_decrypt(cms, ri); 674183234Ssimon CMS_RecipientInfo_set0_key(ri, NULL, 0); 675183234Ssimon if (r > 0) 676183234Ssimon return 1; 677183234Ssimon if (id) 678183234Ssimon { 679183234Ssimon CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, 680183234Ssimon CMS_R_DECRYPT_ERROR); 681183234Ssimon return 0; 682183234Ssimon } 683183234Ssimon ERR_clear_error(); 684183234Ssimon } 685183234Ssimon } 686183234Ssimon 687183234Ssimon CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT); 688183234Ssimon return 0; 689183234Ssimon 690183234Ssimon } 691183234Ssimon 692183234Ssimonint CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, 693183234Ssimon BIO *dcont, BIO *out, 694183234Ssimon unsigned int flags) 695183234Ssimon { 696183234Ssimon int r; 697183234Ssimon BIO *cont; 698183234Ssimon if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) 699183234Ssimon { 700183234Ssimon CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA); 701183234Ssimon return 0; 702183234Ssimon } 703183234Ssimon if (!dcont && !check_content(cms)) 704183234Ssimon return 0; 705183234Ssimon if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert)) 706183234Ssimon return 0; 707183234Ssimon 708183234Ssimon cont = CMS_dataInit(cms, dcont); 709183234Ssimon if (!cont) 710183234Ssimon return 0; 711183234Ssimon r = cms_copy_content(out, cont, flags); 712183234Ssimon do_free_upto(cont, dcont); 713183234Ssimon return r; 714183234Ssimon } 715183234Ssimon 716183234Ssimonint CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags) 717183234Ssimon { 718183234Ssimon BIO *cmsbio; 719183234Ssimon int ret = 0; 720183234Ssimon if (!(cmsbio = CMS_dataInit(cms, dcont))) 721183234Ssimon { 722183234Ssimon CMSerr(CMS_F_CMS_FINAL,ERR_R_MALLOC_FAILURE); 723183234Ssimon return 0; 724183234Ssimon } 725183234Ssimon 726183234Ssimon SMIME_crlf_copy(data, cmsbio, flags); 727183234Ssimon 728183234Ssimon (void)BIO_flush(cmsbio); 729183234Ssimon 730183234Ssimon 731183234Ssimon if (!CMS_dataFinal(cms, cmsbio)) 732183234Ssimon { 733183234Ssimon CMSerr(CMS_F_CMS_FINAL,CMS_R_CMS_DATAFINAL_ERROR); 734183234Ssimon goto err; 735183234Ssimon } 736183234Ssimon 737183234Ssimon ret = 1; 738183234Ssimon 739183234Ssimon err: 740183234Ssimon do_free_upto(cmsbio, dcont); 741183234Ssimon 742183234Ssimon return ret; 743183234Ssimon 744183234Ssimon } 745183234Ssimon 746183234Ssimon#ifdef ZLIB 747183234Ssimon 748183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 749183234Ssimon unsigned int flags) 750183234Ssimon { 751183234Ssimon BIO *cont; 752183234Ssimon int r; 753183234Ssimon if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) 754183234Ssimon { 755183234Ssimon CMSerr(CMS_F_CMS_UNCOMPRESS, 756183234Ssimon CMS_R_TYPE_NOT_COMPRESSED_DATA); 757183234Ssimon return 0; 758183234Ssimon } 759183234Ssimon 760183234Ssimon if (!dcont && !check_content(cms)) 761183234Ssimon return 0; 762183234Ssimon 763183234Ssimon cont = CMS_dataInit(cms, dcont); 764183234Ssimon if (!cont) 765183234Ssimon return 0; 766183234Ssimon r = cms_copy_content(out, cont, flags); 767183234Ssimon do_free_upto(cont, dcont); 768183234Ssimon return r; 769183234Ssimon } 770183234Ssimon 771183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) 772183234Ssimon { 773183234Ssimon CMS_ContentInfo *cms; 774183234Ssimon if (comp_nid <= 0) 775183234Ssimon comp_nid = NID_zlib_compression; 776183234Ssimon cms = cms_CompressedData_create(comp_nid); 777183234Ssimon if (!cms) 778183234Ssimon return NULL; 779183234Ssimon 780183234Ssimon if(!(flags & CMS_DETACHED)) 781183234Ssimon { 782183234Ssimon flags &= ~CMS_STREAM; 783183234Ssimon CMS_set_detached(cms, 0); 784183234Ssimon } 785183234Ssimon 786183234Ssimon if (CMS_final(cms, in, NULL, flags)) 787183234Ssimon return cms; 788183234Ssimon 789183234Ssimon CMS_ContentInfo_free(cms); 790183234Ssimon return NULL; 791183234Ssimon } 792183234Ssimon 793183234Ssimon#else 794183234Ssimon 795183234Ssimonint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 796183234Ssimon unsigned int flags) 797183234Ssimon { 798183234Ssimon CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); 799183234Ssimon return 0; 800183234Ssimon } 801183234Ssimon 802183234SsimonCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) 803183234Ssimon { 804183234Ssimon CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); 805183234Ssimon return NULL; 806183234Ssimon } 807183234Ssimon 808183234Ssimon#endif 809