1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2008-2023 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 11e1051a39Sopenharmony_ci#include <openssl/asn1t.h> 12e1051a39Sopenharmony_ci#include <openssl/x509.h> 13e1051a39Sopenharmony_ci#include <openssl/x509v3.h> 14e1051a39Sopenharmony_ci#include <openssl/err.h> 15e1051a39Sopenharmony_ci#include <openssl/cms.h> 16e1051a39Sopenharmony_ci#include "cms_local.h" 17e1051a39Sopenharmony_ci#include "crypto/asn1.h" 18e1051a39Sopenharmony_ci 19e1051a39Sopenharmony_cistatic BIO *cms_get_text_bio(BIO *out, unsigned int flags) 20e1051a39Sopenharmony_ci{ 21e1051a39Sopenharmony_ci BIO *rbio; 22e1051a39Sopenharmony_ci 23e1051a39Sopenharmony_ci if (out == NULL) 24e1051a39Sopenharmony_ci rbio = BIO_new(BIO_s_null()); 25e1051a39Sopenharmony_ci else if (flags & CMS_TEXT) { 26e1051a39Sopenharmony_ci rbio = BIO_new(BIO_s_mem()); 27e1051a39Sopenharmony_ci BIO_set_mem_eof_return(rbio, 0); 28e1051a39Sopenharmony_ci } else 29e1051a39Sopenharmony_ci rbio = out; 30e1051a39Sopenharmony_ci return rbio; 31e1051a39Sopenharmony_ci} 32e1051a39Sopenharmony_ci 33e1051a39Sopenharmony_cistatic int cms_copy_content(BIO *out, BIO *in, unsigned int flags) 34e1051a39Sopenharmony_ci{ 35e1051a39Sopenharmony_ci unsigned char buf[4096]; 36e1051a39Sopenharmony_ci int r = 0, i; 37e1051a39Sopenharmony_ci BIO *tmpout; 38e1051a39Sopenharmony_ci 39e1051a39Sopenharmony_ci tmpout = cms_get_text_bio(out, flags); 40e1051a39Sopenharmony_ci 41e1051a39Sopenharmony_ci if (tmpout == NULL) { 42e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); 43e1051a39Sopenharmony_ci goto err; 44e1051a39Sopenharmony_ci } 45e1051a39Sopenharmony_ci 46e1051a39Sopenharmony_ci /* Read all content through chain to process digest, decrypt etc */ 47e1051a39Sopenharmony_ci for (;;) { 48e1051a39Sopenharmony_ci i = BIO_read(in, buf, sizeof(buf)); 49e1051a39Sopenharmony_ci if (i <= 0) { 50e1051a39Sopenharmony_ci if (BIO_method_type(in) == BIO_TYPE_CIPHER) { 51e1051a39Sopenharmony_ci if (BIO_get_cipher_status(in) <= 0) 52e1051a39Sopenharmony_ci goto err; 53e1051a39Sopenharmony_ci } 54e1051a39Sopenharmony_ci if (i < 0) 55e1051a39Sopenharmony_ci goto err; 56e1051a39Sopenharmony_ci break; 57e1051a39Sopenharmony_ci } 58e1051a39Sopenharmony_ci 59e1051a39Sopenharmony_ci if (tmpout != NULL && (BIO_write(tmpout, buf, i) != i)) 60e1051a39Sopenharmony_ci goto err; 61e1051a39Sopenharmony_ci } 62e1051a39Sopenharmony_ci 63e1051a39Sopenharmony_ci if (flags & CMS_TEXT) { 64e1051a39Sopenharmony_ci if (!SMIME_text(tmpout, out)) { 65e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_SMIME_TEXT_ERROR); 66e1051a39Sopenharmony_ci goto err; 67e1051a39Sopenharmony_ci } 68e1051a39Sopenharmony_ci } 69e1051a39Sopenharmony_ci 70e1051a39Sopenharmony_ci r = 1; 71e1051a39Sopenharmony_ci err: 72e1051a39Sopenharmony_ci if (tmpout != out) 73e1051a39Sopenharmony_ci BIO_free(tmpout); 74e1051a39Sopenharmony_ci return r; 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_ci} 77e1051a39Sopenharmony_ci 78e1051a39Sopenharmony_cistatic int check_content(CMS_ContentInfo *cms) 79e1051a39Sopenharmony_ci{ 80e1051a39Sopenharmony_ci ASN1_OCTET_STRING **pos = CMS_get0_content(cms); 81e1051a39Sopenharmony_ci 82e1051a39Sopenharmony_ci if (pos == NULL || *pos == NULL) { 83e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_NO_CONTENT); 84e1051a39Sopenharmony_ci return 0; 85e1051a39Sopenharmony_ci } 86e1051a39Sopenharmony_ci return 1; 87e1051a39Sopenharmony_ci} 88e1051a39Sopenharmony_ci 89e1051a39Sopenharmony_cistatic void do_free_upto(BIO *f, BIO *upto) 90e1051a39Sopenharmony_ci{ 91e1051a39Sopenharmony_ci if (upto != NULL) { 92e1051a39Sopenharmony_ci BIO *tbio; 93e1051a39Sopenharmony_ci 94e1051a39Sopenharmony_ci do { 95e1051a39Sopenharmony_ci tbio = BIO_pop(f); 96e1051a39Sopenharmony_ci BIO_free(f); 97e1051a39Sopenharmony_ci f = tbio; 98e1051a39Sopenharmony_ci } while (f != NULL && f != upto); 99e1051a39Sopenharmony_ci } else { 100e1051a39Sopenharmony_ci BIO_free_all(f); 101e1051a39Sopenharmony_ci } 102e1051a39Sopenharmony_ci} 103e1051a39Sopenharmony_ci 104e1051a39Sopenharmony_ciint CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags) 105e1051a39Sopenharmony_ci{ 106e1051a39Sopenharmony_ci BIO *cont; 107e1051a39Sopenharmony_ci int r; 108e1051a39Sopenharmony_ci 109e1051a39Sopenharmony_ci if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) { 110e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_DATA); 111e1051a39Sopenharmony_ci return 0; 112e1051a39Sopenharmony_ci } 113e1051a39Sopenharmony_ci cont = CMS_dataInit(cms, NULL); 114e1051a39Sopenharmony_ci if (cont == NULL) 115e1051a39Sopenharmony_ci return 0; 116e1051a39Sopenharmony_ci r = cms_copy_content(out, cont, flags); 117e1051a39Sopenharmony_ci BIO_free_all(cont); 118e1051a39Sopenharmony_ci return r; 119e1051a39Sopenharmony_ci} 120e1051a39Sopenharmony_ci 121e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_data_create_ex(BIO *in, unsigned int flags, 122e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, const char *propq) 123e1051a39Sopenharmony_ci{ 124e1051a39Sopenharmony_ci CMS_ContentInfo *cms = ossl_cms_Data_create(libctx, propq); 125e1051a39Sopenharmony_ci 126e1051a39Sopenharmony_ci if (cms == NULL) 127e1051a39Sopenharmony_ci return NULL; 128e1051a39Sopenharmony_ci 129e1051a39Sopenharmony_ci if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) 130e1051a39Sopenharmony_ci return cms; 131e1051a39Sopenharmony_ci 132e1051a39Sopenharmony_ci CMS_ContentInfo_free(cms); 133e1051a39Sopenharmony_ci return NULL; 134e1051a39Sopenharmony_ci} 135e1051a39Sopenharmony_ci 136e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags) 137e1051a39Sopenharmony_ci{ 138e1051a39Sopenharmony_ci return CMS_data_create_ex(in, flags, NULL, NULL); 139e1051a39Sopenharmony_ci} 140e1051a39Sopenharmony_ci 141e1051a39Sopenharmony_ciint CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 142e1051a39Sopenharmony_ci unsigned int flags) 143e1051a39Sopenharmony_ci{ 144e1051a39Sopenharmony_ci BIO *cont; 145e1051a39Sopenharmony_ci int r; 146e1051a39Sopenharmony_ci 147e1051a39Sopenharmony_ci if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) { 148e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_DIGESTED_DATA); 149e1051a39Sopenharmony_ci return 0; 150e1051a39Sopenharmony_ci } 151e1051a39Sopenharmony_ci 152e1051a39Sopenharmony_ci if (dcont == NULL && !check_content(cms)) 153e1051a39Sopenharmony_ci return 0; 154e1051a39Sopenharmony_ci 155e1051a39Sopenharmony_ci cont = CMS_dataInit(cms, dcont); 156e1051a39Sopenharmony_ci if (cont == NULL) 157e1051a39Sopenharmony_ci return 0; 158e1051a39Sopenharmony_ci 159e1051a39Sopenharmony_ci r = cms_copy_content(out, cont, flags); 160e1051a39Sopenharmony_ci if (r) 161e1051a39Sopenharmony_ci r = ossl_cms_DigestedData_do_final(cms, cont, 1); 162e1051a39Sopenharmony_ci do_free_upto(cont, dcont); 163e1051a39Sopenharmony_ci return r; 164e1051a39Sopenharmony_ci} 165e1051a39Sopenharmony_ci 166e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_digest_create_ex(BIO *in, const EVP_MD *md, 167e1051a39Sopenharmony_ci unsigned int flags, OSSL_LIB_CTX *ctx, 168e1051a39Sopenharmony_ci const char *propq) 169e1051a39Sopenharmony_ci{ 170e1051a39Sopenharmony_ci CMS_ContentInfo *cms; 171e1051a39Sopenharmony_ci 172e1051a39Sopenharmony_ci /* 173e1051a39Sopenharmony_ci * Because the EVP_MD is cached and can be a legacy algorithm, we 174e1051a39Sopenharmony_ci * cannot fetch the algorithm if it isn't supplied. 175e1051a39Sopenharmony_ci */ 176e1051a39Sopenharmony_ci if (md == NULL) 177e1051a39Sopenharmony_ci md = EVP_sha1(); 178e1051a39Sopenharmony_ci cms = ossl_cms_DigestedData_create(md, ctx, propq); 179e1051a39Sopenharmony_ci if (cms == NULL) 180e1051a39Sopenharmony_ci return NULL; 181e1051a39Sopenharmony_ci 182e1051a39Sopenharmony_ci if (!(flags & CMS_DETACHED)) 183e1051a39Sopenharmony_ci CMS_set_detached(cms, 0); 184e1051a39Sopenharmony_ci 185e1051a39Sopenharmony_ci if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) 186e1051a39Sopenharmony_ci return cms; 187e1051a39Sopenharmony_ci 188e1051a39Sopenharmony_ci CMS_ContentInfo_free(cms); 189e1051a39Sopenharmony_ci return NULL; 190e1051a39Sopenharmony_ci} 191e1051a39Sopenharmony_ci 192e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, 193e1051a39Sopenharmony_ci unsigned int flags) 194e1051a39Sopenharmony_ci{ 195e1051a39Sopenharmony_ci return CMS_digest_create_ex(in, md, flags, NULL, NULL); 196e1051a39Sopenharmony_ci} 197e1051a39Sopenharmony_ci 198e1051a39Sopenharmony_ciint CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, 199e1051a39Sopenharmony_ci const unsigned char *key, size_t keylen, 200e1051a39Sopenharmony_ci BIO *dcont, BIO *out, unsigned int flags) 201e1051a39Sopenharmony_ci{ 202e1051a39Sopenharmony_ci BIO *cont; 203e1051a39Sopenharmony_ci int r; 204e1051a39Sopenharmony_ci 205e1051a39Sopenharmony_ci if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) { 206e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_ENCRYPTED_DATA); 207e1051a39Sopenharmony_ci return 0; 208e1051a39Sopenharmony_ci } 209e1051a39Sopenharmony_ci 210e1051a39Sopenharmony_ci if (dcont == NULL && !check_content(cms)) 211e1051a39Sopenharmony_ci return 0; 212e1051a39Sopenharmony_ci 213e1051a39Sopenharmony_ci if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0) 214e1051a39Sopenharmony_ci return 0; 215e1051a39Sopenharmony_ci cont = CMS_dataInit(cms, dcont); 216e1051a39Sopenharmony_ci if (cont == NULL) 217e1051a39Sopenharmony_ci return 0; 218e1051a39Sopenharmony_ci r = cms_copy_content(out, cont, flags); 219e1051a39Sopenharmony_ci do_free_upto(cont, dcont); 220e1051a39Sopenharmony_ci return r; 221e1051a39Sopenharmony_ci} 222e1051a39Sopenharmony_ci 223e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_EncryptedData_encrypt_ex(BIO *in, const EVP_CIPHER *cipher, 224e1051a39Sopenharmony_ci const unsigned char *key, 225e1051a39Sopenharmony_ci size_t keylen, unsigned int flags, 226e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, 227e1051a39Sopenharmony_ci const char *propq) 228e1051a39Sopenharmony_ci{ 229e1051a39Sopenharmony_ci CMS_ContentInfo *cms; 230e1051a39Sopenharmony_ci 231e1051a39Sopenharmony_ci if (cipher == NULL) { 232e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_NO_CIPHER); 233e1051a39Sopenharmony_ci return NULL; 234e1051a39Sopenharmony_ci } 235e1051a39Sopenharmony_ci cms = CMS_ContentInfo_new_ex(libctx, propq); 236e1051a39Sopenharmony_ci if (cms == NULL) 237e1051a39Sopenharmony_ci return NULL; 238e1051a39Sopenharmony_ci if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) 239e1051a39Sopenharmony_ci goto err; 240e1051a39Sopenharmony_ci 241e1051a39Sopenharmony_ci if (!(flags & CMS_DETACHED)) 242e1051a39Sopenharmony_ci CMS_set_detached(cms, 0); 243e1051a39Sopenharmony_ci 244e1051a39Sopenharmony_ci if ((flags & (CMS_STREAM | CMS_PARTIAL)) 245e1051a39Sopenharmony_ci || CMS_final(cms, in, NULL, flags)) 246e1051a39Sopenharmony_ci return cms; 247e1051a39Sopenharmony_ci 248e1051a39Sopenharmony_ci err: 249e1051a39Sopenharmony_ci CMS_ContentInfo_free(cms); 250e1051a39Sopenharmony_ci return NULL; 251e1051a39Sopenharmony_ci} 252e1051a39Sopenharmony_ci 253e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, 254e1051a39Sopenharmony_ci const unsigned char *key, 255e1051a39Sopenharmony_ci size_t keylen, unsigned int flags) 256e1051a39Sopenharmony_ci{ 257e1051a39Sopenharmony_ci return CMS_EncryptedData_encrypt_ex(in, cipher, key, keylen, flags, NULL, 258e1051a39Sopenharmony_ci NULL); 259e1051a39Sopenharmony_ci} 260e1051a39Sopenharmony_ci 261e1051a39Sopenharmony_cistatic int cms_signerinfo_verify_cert(CMS_SignerInfo *si, 262e1051a39Sopenharmony_ci X509_STORE *store, 263e1051a39Sopenharmony_ci STACK_OF(X509) *certs, 264e1051a39Sopenharmony_ci STACK_OF(X509_CRL) *crls, 265e1051a39Sopenharmony_ci STACK_OF(X509) **chain, 266e1051a39Sopenharmony_ci const CMS_CTX *cms_ctx) 267e1051a39Sopenharmony_ci{ 268e1051a39Sopenharmony_ci X509_STORE_CTX *ctx; 269e1051a39Sopenharmony_ci X509 *signer; 270e1051a39Sopenharmony_ci int i, j, r = 0; 271e1051a39Sopenharmony_ci 272e1051a39Sopenharmony_ci ctx = X509_STORE_CTX_new_ex(ossl_cms_ctx_get0_libctx(cms_ctx), 273e1051a39Sopenharmony_ci ossl_cms_ctx_get0_propq(cms_ctx)); 274e1051a39Sopenharmony_ci if (ctx == NULL) { 275e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); 276e1051a39Sopenharmony_ci goto err; 277e1051a39Sopenharmony_ci } 278e1051a39Sopenharmony_ci CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); 279e1051a39Sopenharmony_ci if (!X509_STORE_CTX_init(ctx, store, signer, certs)) { 280e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_STORE_INIT_ERROR); 281e1051a39Sopenharmony_ci goto err; 282e1051a39Sopenharmony_ci } 283e1051a39Sopenharmony_ci X509_STORE_CTX_set_default(ctx, "smime_sign"); 284e1051a39Sopenharmony_ci if (crls != NULL) 285e1051a39Sopenharmony_ci X509_STORE_CTX_set0_crls(ctx, crls); 286e1051a39Sopenharmony_ci 287e1051a39Sopenharmony_ci i = X509_verify_cert(ctx); 288e1051a39Sopenharmony_ci if (i <= 0) { 289e1051a39Sopenharmony_ci j = X509_STORE_CTX_get_error(ctx); 290e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_CMS, CMS_R_CERTIFICATE_VERIFY_ERROR, 291e1051a39Sopenharmony_ci "Verify error: %s", X509_verify_cert_error_string(j)); 292e1051a39Sopenharmony_ci goto err; 293e1051a39Sopenharmony_ci } 294e1051a39Sopenharmony_ci r = 1; 295e1051a39Sopenharmony_ci 296e1051a39Sopenharmony_ci /* also send back the trust chain when required */ 297e1051a39Sopenharmony_ci if (chain != NULL) 298e1051a39Sopenharmony_ci *chain = X509_STORE_CTX_get1_chain(ctx); 299e1051a39Sopenharmony_ci err: 300e1051a39Sopenharmony_ci X509_STORE_CTX_free(ctx); 301e1051a39Sopenharmony_ci return r; 302e1051a39Sopenharmony_ci 303e1051a39Sopenharmony_ci} 304e1051a39Sopenharmony_ci 305e1051a39Sopenharmony_ciint CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, 306e1051a39Sopenharmony_ci X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags) 307e1051a39Sopenharmony_ci{ 308e1051a39Sopenharmony_ci CMS_SignerInfo *si; 309e1051a39Sopenharmony_ci STACK_OF(CMS_SignerInfo) *sinfos; 310e1051a39Sopenharmony_ci STACK_OF(X509) *cms_certs = NULL; 311e1051a39Sopenharmony_ci STACK_OF(X509_CRL) *crls = NULL; 312e1051a39Sopenharmony_ci STACK_OF(X509) **si_chains = NULL; 313e1051a39Sopenharmony_ci X509 *signer; 314e1051a39Sopenharmony_ci int i, scount = 0, ret = 0; 315e1051a39Sopenharmony_ci BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL; 316e1051a39Sopenharmony_ci int cadesVerify = (flags & CMS_CADES) != 0; 317e1051a39Sopenharmony_ci const CMS_CTX *ctx = ossl_cms_get0_cmsctx(cms); 318e1051a39Sopenharmony_ci 319e1051a39Sopenharmony_ci if (dcont == NULL && !check_content(cms)) 320e1051a39Sopenharmony_ci return 0; 321e1051a39Sopenharmony_ci if (dcont != NULL && !(flags & CMS_BINARY)) { 322e1051a39Sopenharmony_ci const ASN1_OBJECT *coid = CMS_get0_eContentType(cms); 323e1051a39Sopenharmony_ci 324e1051a39Sopenharmony_ci if (OBJ_obj2nid(coid) == NID_id_ct_asciiTextWithCRLF) 325e1051a39Sopenharmony_ci flags |= CMS_ASCIICRLF; 326e1051a39Sopenharmony_ci } 327e1051a39Sopenharmony_ci 328e1051a39Sopenharmony_ci /* Attempt to find all signer certificates */ 329e1051a39Sopenharmony_ci 330e1051a39Sopenharmony_ci sinfos = CMS_get0_SignerInfos(cms); 331e1051a39Sopenharmony_ci 332e1051a39Sopenharmony_ci if (sk_CMS_SignerInfo_num(sinfos) <= 0) { 333e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_NO_SIGNERS); 334e1051a39Sopenharmony_ci goto err; 335e1051a39Sopenharmony_ci } 336e1051a39Sopenharmony_ci 337e1051a39Sopenharmony_ci for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 338e1051a39Sopenharmony_ci si = sk_CMS_SignerInfo_value(sinfos, i); 339e1051a39Sopenharmony_ci CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); 340e1051a39Sopenharmony_ci if (signer) 341e1051a39Sopenharmony_ci scount++; 342e1051a39Sopenharmony_ci } 343e1051a39Sopenharmony_ci 344e1051a39Sopenharmony_ci if (scount != sk_CMS_SignerInfo_num(sinfos)) 345e1051a39Sopenharmony_ci scount += CMS_set1_signers_certs(cms, certs, flags); 346e1051a39Sopenharmony_ci 347e1051a39Sopenharmony_ci if (scount != sk_CMS_SignerInfo_num(sinfos)) { 348e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND); 349e1051a39Sopenharmony_ci goto err; 350e1051a39Sopenharmony_ci } 351e1051a39Sopenharmony_ci 352e1051a39Sopenharmony_ci /* Attempt to verify all signers certs */ 353e1051a39Sopenharmony_ci /* at this point scount == sk_CMS_SignerInfo_num(sinfos) */ 354e1051a39Sopenharmony_ci 355e1051a39Sopenharmony_ci if ((flags & CMS_NO_SIGNER_CERT_VERIFY) == 0 || cadesVerify) { 356e1051a39Sopenharmony_ci if (cadesVerify) { 357e1051a39Sopenharmony_ci /* Certificate trust chain is required to check CAdES signature */ 358e1051a39Sopenharmony_ci si_chains = OPENSSL_zalloc(scount * sizeof(si_chains[0])); 359e1051a39Sopenharmony_ci if (si_chains == NULL) { 360e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); 361e1051a39Sopenharmony_ci goto err; 362e1051a39Sopenharmony_ci } 363e1051a39Sopenharmony_ci } 364e1051a39Sopenharmony_ci cms_certs = CMS_get1_certs(cms); 365e1051a39Sopenharmony_ci if (!(flags & CMS_NOCRL)) 366e1051a39Sopenharmony_ci crls = CMS_get1_crls(cms); 367e1051a39Sopenharmony_ci for (i = 0; i < scount; i++) { 368e1051a39Sopenharmony_ci si = sk_CMS_SignerInfo_value(sinfos, i); 369e1051a39Sopenharmony_ci 370e1051a39Sopenharmony_ci if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls, 371e1051a39Sopenharmony_ci si_chains ? &si_chains[i] : NULL, 372e1051a39Sopenharmony_ci ctx)) 373e1051a39Sopenharmony_ci goto err; 374e1051a39Sopenharmony_ci } 375e1051a39Sopenharmony_ci } 376e1051a39Sopenharmony_ci 377e1051a39Sopenharmony_ci /* Attempt to verify all SignerInfo signed attribute signatures */ 378e1051a39Sopenharmony_ci 379e1051a39Sopenharmony_ci if ((flags & CMS_NO_ATTR_VERIFY) == 0 || cadesVerify) { 380e1051a39Sopenharmony_ci for (i = 0; i < scount; i++) { 381e1051a39Sopenharmony_ci si = sk_CMS_SignerInfo_value(sinfos, i); 382e1051a39Sopenharmony_ci if (CMS_signed_get_attr_count(si) < 0) 383e1051a39Sopenharmony_ci continue; 384e1051a39Sopenharmony_ci if (CMS_SignerInfo_verify(si) <= 0) 385e1051a39Sopenharmony_ci goto err; 386e1051a39Sopenharmony_ci if (cadesVerify) { 387e1051a39Sopenharmony_ci STACK_OF(X509) *si_chain = si_chains ? si_chains[i] : NULL; 388e1051a39Sopenharmony_ci 389e1051a39Sopenharmony_ci if (ossl_cms_check_signing_certs(si, si_chain) <= 0) 390e1051a39Sopenharmony_ci goto err; 391e1051a39Sopenharmony_ci } 392e1051a39Sopenharmony_ci } 393e1051a39Sopenharmony_ci } 394e1051a39Sopenharmony_ci 395e1051a39Sopenharmony_ci /* 396e1051a39Sopenharmony_ci * Performance optimization: if the content is a memory BIO then store 397e1051a39Sopenharmony_ci * its contents in a temporary read only memory BIO. This avoids 398e1051a39Sopenharmony_ci * potentially large numbers of slow copies of data which will occur when 399e1051a39Sopenharmony_ci * reading from a read write memory BIO when signatures are calculated. 400e1051a39Sopenharmony_ci */ 401e1051a39Sopenharmony_ci 402e1051a39Sopenharmony_ci if (dcont != NULL && (BIO_method_type(dcont) == BIO_TYPE_MEM)) { 403e1051a39Sopenharmony_ci char *ptr; 404e1051a39Sopenharmony_ci long len; 405e1051a39Sopenharmony_ci 406e1051a39Sopenharmony_ci len = BIO_get_mem_data(dcont, &ptr); 407e1051a39Sopenharmony_ci tmpin = (len == 0) ? dcont : BIO_new_mem_buf(ptr, len); 408e1051a39Sopenharmony_ci if (tmpin == NULL) { 409e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); 410e1051a39Sopenharmony_ci goto err2; 411e1051a39Sopenharmony_ci } 412e1051a39Sopenharmony_ci } else { 413e1051a39Sopenharmony_ci tmpin = dcont; 414e1051a39Sopenharmony_ci } 415e1051a39Sopenharmony_ci /* 416e1051a39Sopenharmony_ci * If not binary mode and detached generate digests by *writing* through 417e1051a39Sopenharmony_ci * the BIO. That makes it possible to canonicalise the input. 418e1051a39Sopenharmony_ci */ 419e1051a39Sopenharmony_ci if (!(flags & SMIME_BINARY) && dcont) { 420e1051a39Sopenharmony_ci /* 421e1051a39Sopenharmony_ci * Create output BIO so we can either handle text or to ensure 422e1051a39Sopenharmony_ci * included content doesn't override detached content. 423e1051a39Sopenharmony_ci */ 424e1051a39Sopenharmony_ci tmpout = cms_get_text_bio(out, flags); 425e1051a39Sopenharmony_ci if (tmpout == NULL) { 426e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); 427e1051a39Sopenharmony_ci goto err; 428e1051a39Sopenharmony_ci } 429e1051a39Sopenharmony_ci cmsbio = CMS_dataInit(cms, tmpout); 430e1051a39Sopenharmony_ci if (cmsbio == NULL) 431e1051a39Sopenharmony_ci goto err; 432e1051a39Sopenharmony_ci /* 433e1051a39Sopenharmony_ci * Don't use SMIME_TEXT for verify: it adds headers and we want to 434e1051a39Sopenharmony_ci * remove them. 435e1051a39Sopenharmony_ci */ 436e1051a39Sopenharmony_ci if (!SMIME_crlf_copy(dcont, cmsbio, flags & ~SMIME_TEXT)) 437e1051a39Sopenharmony_ci goto err; 438e1051a39Sopenharmony_ci 439e1051a39Sopenharmony_ci if (flags & CMS_TEXT) { 440e1051a39Sopenharmony_ci if (!SMIME_text(tmpout, out)) { 441e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_SMIME_TEXT_ERROR); 442e1051a39Sopenharmony_ci goto err; 443e1051a39Sopenharmony_ci } 444e1051a39Sopenharmony_ci } 445e1051a39Sopenharmony_ci } else { 446e1051a39Sopenharmony_ci cmsbio = CMS_dataInit(cms, tmpin); 447e1051a39Sopenharmony_ci if (cmsbio == NULL) 448e1051a39Sopenharmony_ci goto err; 449e1051a39Sopenharmony_ci 450e1051a39Sopenharmony_ci if (!cms_copy_content(out, cmsbio, flags)) 451e1051a39Sopenharmony_ci goto err; 452e1051a39Sopenharmony_ci 453e1051a39Sopenharmony_ci } 454e1051a39Sopenharmony_ci if (!(flags & CMS_NO_CONTENT_VERIFY)) { 455e1051a39Sopenharmony_ci for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { 456e1051a39Sopenharmony_ci si = sk_CMS_SignerInfo_value(sinfos, i); 457e1051a39Sopenharmony_ci if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) { 458e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_CONTENT_VERIFY_ERROR); 459e1051a39Sopenharmony_ci goto err; 460e1051a39Sopenharmony_ci } 461e1051a39Sopenharmony_ci } 462e1051a39Sopenharmony_ci } 463e1051a39Sopenharmony_ci 464e1051a39Sopenharmony_ci ret = 1; 465e1051a39Sopenharmony_ci err: 466e1051a39Sopenharmony_ci if (!(flags & SMIME_BINARY) && dcont) { 467e1051a39Sopenharmony_ci do_free_upto(cmsbio, tmpout); 468e1051a39Sopenharmony_ci if (tmpin != dcont) 469e1051a39Sopenharmony_ci BIO_free(tmpin); 470e1051a39Sopenharmony_ci } else { 471e1051a39Sopenharmony_ci if (dcont && (tmpin == dcont)) 472e1051a39Sopenharmony_ci do_free_upto(cmsbio, dcont); 473e1051a39Sopenharmony_ci else 474e1051a39Sopenharmony_ci BIO_free_all(cmsbio); 475e1051a39Sopenharmony_ci } 476e1051a39Sopenharmony_ci 477e1051a39Sopenharmony_ci if (out != tmpout) 478e1051a39Sopenharmony_ci BIO_free_all(tmpout); 479e1051a39Sopenharmony_ci 480e1051a39Sopenharmony_ci err2: 481e1051a39Sopenharmony_ci if (si_chains != NULL) { 482e1051a39Sopenharmony_ci for (i = 0; i < scount; ++i) 483e1051a39Sopenharmony_ci sk_X509_pop_free(si_chains[i], X509_free); 484e1051a39Sopenharmony_ci OPENSSL_free(si_chains); 485e1051a39Sopenharmony_ci } 486e1051a39Sopenharmony_ci sk_X509_pop_free(cms_certs, X509_free); 487e1051a39Sopenharmony_ci sk_X509_CRL_pop_free(crls, X509_CRL_free); 488e1051a39Sopenharmony_ci 489e1051a39Sopenharmony_ci return ret; 490e1051a39Sopenharmony_ci} 491e1051a39Sopenharmony_ci 492e1051a39Sopenharmony_ciint CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, 493e1051a39Sopenharmony_ci STACK_OF(X509) *certs, 494e1051a39Sopenharmony_ci X509_STORE *store, unsigned int flags) 495e1051a39Sopenharmony_ci{ 496e1051a39Sopenharmony_ci int r; 497e1051a39Sopenharmony_ci 498e1051a39Sopenharmony_ci flags &= ~(CMS_DETACHED | CMS_TEXT); 499e1051a39Sopenharmony_ci r = CMS_verify(rcms, certs, store, NULL, NULL, flags); 500e1051a39Sopenharmony_ci if (r <= 0) 501e1051a39Sopenharmony_ci return r; 502e1051a39Sopenharmony_ci return ossl_cms_Receipt_verify(rcms, ocms); 503e1051a39Sopenharmony_ci} 504e1051a39Sopenharmony_ci 505e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_sign_ex(X509 *signcert, EVP_PKEY *pkey, 506e1051a39Sopenharmony_ci STACK_OF(X509) *certs, BIO *data, 507e1051a39Sopenharmony_ci unsigned int flags, OSSL_LIB_CTX *libctx, 508e1051a39Sopenharmony_ci const char *propq) 509e1051a39Sopenharmony_ci{ 510e1051a39Sopenharmony_ci CMS_ContentInfo *cms; 511e1051a39Sopenharmony_ci int i; 512e1051a39Sopenharmony_ci 513e1051a39Sopenharmony_ci cms = CMS_ContentInfo_new_ex(libctx, propq); 514e1051a39Sopenharmony_ci if (cms == NULL || !CMS_SignedData_init(cms)) 515e1051a39Sopenharmony_ci goto merr; 516e1051a39Sopenharmony_ci if (flags & CMS_ASCIICRLF 517e1051a39Sopenharmony_ci && !CMS_set1_eContentType(cms, 518e1051a39Sopenharmony_ci OBJ_nid2obj(NID_id_ct_asciiTextWithCRLF))) 519e1051a39Sopenharmony_ci goto err; 520e1051a39Sopenharmony_ci 521e1051a39Sopenharmony_ci if (pkey != NULL && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) { 522e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_ADD_SIGNER_ERROR); 523e1051a39Sopenharmony_ci goto err; 524e1051a39Sopenharmony_ci } 525e1051a39Sopenharmony_ci 526e1051a39Sopenharmony_ci for (i = 0; i < sk_X509_num(certs); i++) { 527e1051a39Sopenharmony_ci X509 *x = sk_X509_value(certs, i); 528e1051a39Sopenharmony_ci 529e1051a39Sopenharmony_ci if (!CMS_add1_cert(cms, x)) 530e1051a39Sopenharmony_ci goto merr; 531e1051a39Sopenharmony_ci } 532e1051a39Sopenharmony_ci 533e1051a39Sopenharmony_ci if (!(flags & CMS_DETACHED)) 534e1051a39Sopenharmony_ci CMS_set_detached(cms, 0); 535e1051a39Sopenharmony_ci 536e1051a39Sopenharmony_ci if ((flags & (CMS_STREAM | CMS_PARTIAL)) 537e1051a39Sopenharmony_ci || CMS_final(cms, data, NULL, flags)) 538e1051a39Sopenharmony_ci return cms; 539e1051a39Sopenharmony_ci else 540e1051a39Sopenharmony_ci goto err; 541e1051a39Sopenharmony_ci 542e1051a39Sopenharmony_ci merr: 543e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); 544e1051a39Sopenharmony_ci 545e1051a39Sopenharmony_ci err: 546e1051a39Sopenharmony_ci CMS_ContentInfo_free(cms); 547e1051a39Sopenharmony_ci return NULL; 548e1051a39Sopenharmony_ci} 549e1051a39Sopenharmony_ci 550e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, 551e1051a39Sopenharmony_ci BIO *data, unsigned int flags) 552e1051a39Sopenharmony_ci{ 553e1051a39Sopenharmony_ci return CMS_sign_ex(signcert, pkey, certs, data, flags, NULL, NULL); 554e1051a39Sopenharmony_ci} 555e1051a39Sopenharmony_ci 556e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, 557e1051a39Sopenharmony_ci X509 *signcert, EVP_PKEY *pkey, 558e1051a39Sopenharmony_ci STACK_OF(X509) *certs, unsigned int flags) 559e1051a39Sopenharmony_ci{ 560e1051a39Sopenharmony_ci CMS_SignerInfo *rct_si; 561e1051a39Sopenharmony_ci CMS_ContentInfo *cms = NULL; 562e1051a39Sopenharmony_ci ASN1_OCTET_STRING **pos, *os; 563e1051a39Sopenharmony_ci BIO *rct_cont = NULL; 564e1051a39Sopenharmony_ci int r = 0; 565e1051a39Sopenharmony_ci const CMS_CTX *ctx = si->cms_ctx; 566e1051a39Sopenharmony_ci 567e1051a39Sopenharmony_ci flags &= ~(CMS_STREAM | CMS_TEXT); 568e1051a39Sopenharmony_ci /* Not really detached but avoids content being allocated */ 569e1051a39Sopenharmony_ci flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED; 570e1051a39Sopenharmony_ci if (pkey == NULL || signcert == NULL) { 571e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_NO_KEY_OR_CERT); 572e1051a39Sopenharmony_ci return NULL; 573e1051a39Sopenharmony_ci } 574e1051a39Sopenharmony_ci 575e1051a39Sopenharmony_ci /* Initialize signed data */ 576e1051a39Sopenharmony_ci 577e1051a39Sopenharmony_ci cms = CMS_sign_ex(NULL, NULL, certs, NULL, flags, 578e1051a39Sopenharmony_ci ossl_cms_ctx_get0_libctx(ctx), 579e1051a39Sopenharmony_ci ossl_cms_ctx_get0_propq(ctx)); 580e1051a39Sopenharmony_ci if (cms == NULL) 581e1051a39Sopenharmony_ci goto err; 582e1051a39Sopenharmony_ci 583e1051a39Sopenharmony_ci /* Set inner content type to signed receipt */ 584e1051a39Sopenharmony_ci if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt))) 585e1051a39Sopenharmony_ci goto err; 586e1051a39Sopenharmony_ci 587e1051a39Sopenharmony_ci rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags); 588e1051a39Sopenharmony_ci if (!rct_si) { 589e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_ADD_SIGNER_ERROR); 590e1051a39Sopenharmony_ci goto err; 591e1051a39Sopenharmony_ci } 592e1051a39Sopenharmony_ci 593e1051a39Sopenharmony_ci os = ossl_cms_encode_Receipt(si); 594e1051a39Sopenharmony_ci if (os == NULL) 595e1051a39Sopenharmony_ci goto err; 596e1051a39Sopenharmony_ci 597e1051a39Sopenharmony_ci /* Set content to digest */ 598e1051a39Sopenharmony_ci rct_cont = BIO_new_mem_buf(os->data, os->length); 599e1051a39Sopenharmony_ci if (rct_cont == NULL) 600e1051a39Sopenharmony_ci goto err; 601e1051a39Sopenharmony_ci 602e1051a39Sopenharmony_ci /* Add msgSigDigest attribute */ 603e1051a39Sopenharmony_ci 604e1051a39Sopenharmony_ci if (!ossl_cms_msgSigDigest_add1(rct_si, si)) 605e1051a39Sopenharmony_ci goto err; 606e1051a39Sopenharmony_ci 607e1051a39Sopenharmony_ci /* Finalize structure */ 608e1051a39Sopenharmony_ci if (!CMS_final(cms, rct_cont, NULL, flags)) 609e1051a39Sopenharmony_ci goto err; 610e1051a39Sopenharmony_ci 611e1051a39Sopenharmony_ci /* Set embedded content */ 612e1051a39Sopenharmony_ci pos = CMS_get0_content(cms); 613e1051a39Sopenharmony_ci if (pos == NULL) 614e1051a39Sopenharmony_ci goto err; 615e1051a39Sopenharmony_ci *pos = os; 616e1051a39Sopenharmony_ci 617e1051a39Sopenharmony_ci r = 1; 618e1051a39Sopenharmony_ci 619e1051a39Sopenharmony_ci err: 620e1051a39Sopenharmony_ci BIO_free(rct_cont); 621e1051a39Sopenharmony_ci if (r) 622e1051a39Sopenharmony_ci return cms; 623e1051a39Sopenharmony_ci CMS_ContentInfo_free(cms); 624e1051a39Sopenharmony_ci return NULL; 625e1051a39Sopenharmony_ci 626e1051a39Sopenharmony_ci} 627e1051a39Sopenharmony_ci 628e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_encrypt_ex(STACK_OF(X509) *certs, BIO *data, 629e1051a39Sopenharmony_ci const EVP_CIPHER *cipher, unsigned int flags, 630e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, const char *propq) 631e1051a39Sopenharmony_ci{ 632e1051a39Sopenharmony_ci CMS_ContentInfo *cms; 633e1051a39Sopenharmony_ci int i; 634e1051a39Sopenharmony_ci X509 *recip; 635e1051a39Sopenharmony_ci 636e1051a39Sopenharmony_ci 637e1051a39Sopenharmony_ci cms = (EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) 638e1051a39Sopenharmony_ci ? CMS_AuthEnvelopedData_create_ex(cipher, libctx, propq) 639e1051a39Sopenharmony_ci : CMS_EnvelopedData_create_ex(cipher, libctx, propq); 640e1051a39Sopenharmony_ci if (cms == NULL) 641e1051a39Sopenharmony_ci goto merr; 642e1051a39Sopenharmony_ci for (i = 0; i < sk_X509_num(certs); i++) { 643e1051a39Sopenharmony_ci recip = sk_X509_value(certs, i); 644e1051a39Sopenharmony_ci if (!CMS_add1_recipient_cert(cms, recip, flags)) { 645e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_RECIPIENT_ERROR); 646e1051a39Sopenharmony_ci goto err; 647e1051a39Sopenharmony_ci } 648e1051a39Sopenharmony_ci } 649e1051a39Sopenharmony_ci 650e1051a39Sopenharmony_ci if (!(flags & CMS_DETACHED)) 651e1051a39Sopenharmony_ci CMS_set_detached(cms, 0); 652e1051a39Sopenharmony_ci 653e1051a39Sopenharmony_ci if ((flags & (CMS_STREAM | CMS_PARTIAL)) 654e1051a39Sopenharmony_ci || CMS_final(cms, data, NULL, flags)) 655e1051a39Sopenharmony_ci return cms; 656e1051a39Sopenharmony_ci else 657e1051a39Sopenharmony_ci goto err; 658e1051a39Sopenharmony_ci 659e1051a39Sopenharmony_ci merr: 660e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); 661e1051a39Sopenharmony_ci err: 662e1051a39Sopenharmony_ci CMS_ContentInfo_free(cms); 663e1051a39Sopenharmony_ci return NULL; 664e1051a39Sopenharmony_ci} 665e1051a39Sopenharmony_ci 666e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, 667e1051a39Sopenharmony_ci const EVP_CIPHER *cipher, unsigned int flags) 668e1051a39Sopenharmony_ci{ 669e1051a39Sopenharmony_ci return CMS_encrypt_ex(certs, data, cipher, flags, NULL, NULL); 670e1051a39Sopenharmony_ci} 671e1051a39Sopenharmony_ci 672e1051a39Sopenharmony_cistatic int cms_kari_set1_pkey_and_peer(CMS_ContentInfo *cms, 673e1051a39Sopenharmony_ci CMS_RecipientInfo *ri, 674e1051a39Sopenharmony_ci EVP_PKEY *pk, X509 *cert, X509 *peer) 675e1051a39Sopenharmony_ci{ 676e1051a39Sopenharmony_ci int i; 677e1051a39Sopenharmony_ci STACK_OF(CMS_RecipientEncryptedKey) *reks; 678e1051a39Sopenharmony_ci CMS_RecipientEncryptedKey *rek; 679e1051a39Sopenharmony_ci 680e1051a39Sopenharmony_ci reks = CMS_RecipientInfo_kari_get0_reks(ri); 681e1051a39Sopenharmony_ci for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) { 682e1051a39Sopenharmony_ci int rv; 683e1051a39Sopenharmony_ci 684e1051a39Sopenharmony_ci rek = sk_CMS_RecipientEncryptedKey_value(reks, i); 685e1051a39Sopenharmony_ci if (cert != NULL && CMS_RecipientEncryptedKey_cert_cmp(rek, cert)) 686e1051a39Sopenharmony_ci continue; 687e1051a39Sopenharmony_ci CMS_RecipientInfo_kari_set0_pkey_and_peer(ri, pk, peer); 688e1051a39Sopenharmony_ci rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek); 689e1051a39Sopenharmony_ci CMS_RecipientInfo_kari_set0_pkey(ri, NULL); 690e1051a39Sopenharmony_ci if (rv > 0) 691e1051a39Sopenharmony_ci return 1; 692e1051a39Sopenharmony_ci return cert == NULL ? 0 : -1; 693e1051a39Sopenharmony_ci } 694e1051a39Sopenharmony_ci return 0; 695e1051a39Sopenharmony_ci} 696e1051a39Sopenharmony_ci 697e1051a39Sopenharmony_ciint CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) 698e1051a39Sopenharmony_ci{ 699e1051a39Sopenharmony_ci return CMS_decrypt_set1_pkey_and_peer(cms, pk, cert, NULL); 700e1051a39Sopenharmony_ci} 701e1051a39Sopenharmony_ci 702e1051a39Sopenharmony_ciint CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk, 703e1051a39Sopenharmony_ci X509 *cert, X509 *peer) 704e1051a39Sopenharmony_ci{ 705e1051a39Sopenharmony_ci STACK_OF(CMS_RecipientInfo) *ris = CMS_get0_RecipientInfos(cms); 706e1051a39Sopenharmony_ci CMS_RecipientInfo *ri; 707e1051a39Sopenharmony_ci int i, r, cms_pkey_ri_type; 708e1051a39Sopenharmony_ci int debug = 0, match_ri = 0; 709e1051a39Sopenharmony_ci CMS_EncryptedContentInfo *ec = ossl_cms_get0_env_enc_content(cms); 710e1051a39Sopenharmony_ci 711e1051a39Sopenharmony_ci /* Prevent mem leak on earlier CMS_decrypt_set1_{pkey_and_peer,password} */ 712e1051a39Sopenharmony_ci if (ec != NULL) { 713e1051a39Sopenharmony_ci OPENSSL_clear_free(ec->key, ec->keylen); 714e1051a39Sopenharmony_ci ec->key = NULL; 715e1051a39Sopenharmony_ci ec->keylen = 0; 716e1051a39Sopenharmony_ci } 717e1051a39Sopenharmony_ci 718e1051a39Sopenharmony_ci if (ris != NULL && ec != NULL) 719e1051a39Sopenharmony_ci debug = ec->debug; 720e1051a39Sopenharmony_ci 721e1051a39Sopenharmony_ci cms_pkey_ri_type = ossl_cms_pkey_get_ri_type(pk); 722e1051a39Sopenharmony_ci if (cms_pkey_ri_type == CMS_RECIPINFO_NONE) { 723e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); 724e1051a39Sopenharmony_ci return 0; 725e1051a39Sopenharmony_ci } 726e1051a39Sopenharmony_ci 727e1051a39Sopenharmony_ci for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { 728e1051a39Sopenharmony_ci int ri_type; 729e1051a39Sopenharmony_ci 730e1051a39Sopenharmony_ci ri = sk_CMS_RecipientInfo_value(ris, i); 731e1051a39Sopenharmony_ci ri_type = CMS_RecipientInfo_type(ri); 732e1051a39Sopenharmony_ci if (!ossl_cms_pkey_is_ri_type_supported(pk, ri_type)) 733e1051a39Sopenharmony_ci continue; 734e1051a39Sopenharmony_ci match_ri = 1; 735e1051a39Sopenharmony_ci if (ri_type == CMS_RECIPINFO_AGREE) { 736e1051a39Sopenharmony_ci r = cms_kari_set1_pkey_and_peer(cms, ri, pk, cert, peer); 737e1051a39Sopenharmony_ci if (r > 0) 738e1051a39Sopenharmony_ci return 1; 739e1051a39Sopenharmony_ci if (r < 0) 740e1051a39Sopenharmony_ci return 0; 741e1051a39Sopenharmony_ci } 742e1051a39Sopenharmony_ci /* If we have a cert, try matching RecipientInfo, else try them all */ 743e1051a39Sopenharmony_ci else if (cert == NULL || !CMS_RecipientInfo_ktri_cert_cmp(ri, cert)) { 744e1051a39Sopenharmony_ci EVP_PKEY_up_ref(pk); 745e1051a39Sopenharmony_ci CMS_RecipientInfo_set0_pkey(ri, pk); 746e1051a39Sopenharmony_ci r = CMS_RecipientInfo_decrypt(cms, ri); 747e1051a39Sopenharmony_ci CMS_RecipientInfo_set0_pkey(ri, NULL); 748e1051a39Sopenharmony_ci if (cert != NULL) { 749e1051a39Sopenharmony_ci /* 750e1051a39Sopenharmony_ci * If not debugging clear any error and return success to 751e1051a39Sopenharmony_ci * avoid leaking of information useful to MMA 752e1051a39Sopenharmony_ci */ 753e1051a39Sopenharmony_ci if (!debug) { 754e1051a39Sopenharmony_ci ERR_clear_error(); 755e1051a39Sopenharmony_ci return 1; 756e1051a39Sopenharmony_ci } 757e1051a39Sopenharmony_ci if (r > 0) 758e1051a39Sopenharmony_ci return 1; 759e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_DECRYPT_ERROR); 760e1051a39Sopenharmony_ci return 0; 761e1051a39Sopenharmony_ci } 762e1051a39Sopenharmony_ci /* 763e1051a39Sopenharmony_ci * If no cert and not debugging don't leave loop after first 764e1051a39Sopenharmony_ci * successful decrypt. Always attempt to decrypt all recipients 765e1051a39Sopenharmony_ci * to avoid leaking timing of a successful decrypt. 766e1051a39Sopenharmony_ci */ 767e1051a39Sopenharmony_ci else if (r > 0 && (debug || cms_pkey_ri_type != CMS_RECIPINFO_TRANS)) 768e1051a39Sopenharmony_ci return 1; 769e1051a39Sopenharmony_ci } 770e1051a39Sopenharmony_ci } 771e1051a39Sopenharmony_ci /* If no cert, key transport and not debugging always return success */ 772e1051a39Sopenharmony_ci if (cert == NULL 773e1051a39Sopenharmony_ci && cms_pkey_ri_type == CMS_RECIPINFO_TRANS 774e1051a39Sopenharmony_ci && match_ri 775e1051a39Sopenharmony_ci && !debug) { 776e1051a39Sopenharmony_ci ERR_clear_error(); 777e1051a39Sopenharmony_ci return 1; 778e1051a39Sopenharmony_ci } 779e1051a39Sopenharmony_ci 780e1051a39Sopenharmony_ci if (!match_ri) 781e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT); 782e1051a39Sopenharmony_ci return 0; 783e1051a39Sopenharmony_ci 784e1051a39Sopenharmony_ci} 785e1051a39Sopenharmony_ci 786e1051a39Sopenharmony_ciint CMS_decrypt_set1_key(CMS_ContentInfo *cms, 787e1051a39Sopenharmony_ci unsigned char *key, size_t keylen, 788e1051a39Sopenharmony_ci const unsigned char *id, size_t idlen) 789e1051a39Sopenharmony_ci{ 790e1051a39Sopenharmony_ci STACK_OF(CMS_RecipientInfo) *ris; 791e1051a39Sopenharmony_ci CMS_RecipientInfo *ri; 792e1051a39Sopenharmony_ci int i, r, match_ri = 0; 793e1051a39Sopenharmony_ci 794e1051a39Sopenharmony_ci ris = CMS_get0_RecipientInfos(cms); 795e1051a39Sopenharmony_ci for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { 796e1051a39Sopenharmony_ci ri = sk_CMS_RecipientInfo_value(ris, i); 797e1051a39Sopenharmony_ci if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK) 798e1051a39Sopenharmony_ci continue; 799e1051a39Sopenharmony_ci 800e1051a39Sopenharmony_ci /* If we have an id, try matching RecipientInfo, else try them all */ 801e1051a39Sopenharmony_ci if (id == NULL 802e1051a39Sopenharmony_ci || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) { 803e1051a39Sopenharmony_ci match_ri = 1; 804e1051a39Sopenharmony_ci CMS_RecipientInfo_set0_key(ri, key, keylen); 805e1051a39Sopenharmony_ci r = CMS_RecipientInfo_decrypt(cms, ri); 806e1051a39Sopenharmony_ci CMS_RecipientInfo_set0_key(ri, NULL, 0); 807e1051a39Sopenharmony_ci if (r > 0) 808e1051a39Sopenharmony_ci return 1; 809e1051a39Sopenharmony_ci if (id != NULL) { 810e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_DECRYPT_ERROR); 811e1051a39Sopenharmony_ci return 0; 812e1051a39Sopenharmony_ci } 813e1051a39Sopenharmony_ci ERR_clear_error(); 814e1051a39Sopenharmony_ci } 815e1051a39Sopenharmony_ci } 816e1051a39Sopenharmony_ci 817e1051a39Sopenharmony_ci if (!match_ri) 818e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT); 819e1051a39Sopenharmony_ci return 0; 820e1051a39Sopenharmony_ci 821e1051a39Sopenharmony_ci} 822e1051a39Sopenharmony_ci 823e1051a39Sopenharmony_ciint CMS_decrypt_set1_password(CMS_ContentInfo *cms, 824e1051a39Sopenharmony_ci unsigned char *pass, ossl_ssize_t passlen) 825e1051a39Sopenharmony_ci{ 826e1051a39Sopenharmony_ci STACK_OF(CMS_RecipientInfo) *ris = CMS_get0_RecipientInfos(cms); 827e1051a39Sopenharmony_ci CMS_RecipientInfo *ri; 828e1051a39Sopenharmony_ci int i, r, match_ri = 0; 829e1051a39Sopenharmony_ci CMS_EncryptedContentInfo *ec = ossl_cms_get0_env_enc_content(cms); 830e1051a39Sopenharmony_ci 831e1051a39Sopenharmony_ci /* Prevent mem leak on earlier CMS_decrypt_set1_{pkey_and_peer,password} */ 832e1051a39Sopenharmony_ci if (ec != NULL) { 833e1051a39Sopenharmony_ci OPENSSL_clear_free(ec->key, ec->keylen); 834e1051a39Sopenharmony_ci ec->key = NULL; 835e1051a39Sopenharmony_ci ec->keylen = 0; 836e1051a39Sopenharmony_ci } 837e1051a39Sopenharmony_ci 838e1051a39Sopenharmony_ci for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { 839e1051a39Sopenharmony_ci ri = sk_CMS_RecipientInfo_value(ris, i); 840e1051a39Sopenharmony_ci if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS) 841e1051a39Sopenharmony_ci continue; 842e1051a39Sopenharmony_ci 843e1051a39Sopenharmony_ci /* Must try each PasswordRecipientInfo */ 844e1051a39Sopenharmony_ci match_ri = 1; 845e1051a39Sopenharmony_ci CMS_RecipientInfo_set0_password(ri, pass, passlen); 846e1051a39Sopenharmony_ci r = CMS_RecipientInfo_decrypt(cms, ri); 847e1051a39Sopenharmony_ci CMS_RecipientInfo_set0_password(ri, NULL, 0); 848e1051a39Sopenharmony_ci if (r > 0) 849e1051a39Sopenharmony_ci return 1; 850e1051a39Sopenharmony_ci } 851e1051a39Sopenharmony_ci 852e1051a39Sopenharmony_ci if (!match_ri) 853e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT); 854e1051a39Sopenharmony_ci return 0; 855e1051a39Sopenharmony_ci 856e1051a39Sopenharmony_ci} 857e1051a39Sopenharmony_ci 858e1051a39Sopenharmony_ciint CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, 859e1051a39Sopenharmony_ci BIO *dcont, BIO *out, unsigned int flags) 860e1051a39Sopenharmony_ci{ 861e1051a39Sopenharmony_ci int r; 862e1051a39Sopenharmony_ci BIO *cont; 863e1051a39Sopenharmony_ci CMS_EncryptedContentInfo *ec; 864e1051a39Sopenharmony_ci int nid = OBJ_obj2nid(CMS_get0_type(cms)); 865e1051a39Sopenharmony_ci 866e1051a39Sopenharmony_ci if (nid != NID_pkcs7_enveloped 867e1051a39Sopenharmony_ci && nid != NID_id_smime_ct_authEnvelopedData) { 868e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_ENVELOPED_DATA); 869e1051a39Sopenharmony_ci return 0; 870e1051a39Sopenharmony_ci } 871e1051a39Sopenharmony_ci if (dcont == NULL && !check_content(cms)) 872e1051a39Sopenharmony_ci return 0; 873e1051a39Sopenharmony_ci ec = ossl_cms_get0_env_enc_content(cms); 874e1051a39Sopenharmony_ci ec->debug = (flags & CMS_DEBUG_DECRYPT) != 0; 875e1051a39Sopenharmony_ci ec->havenocert = cert == NULL; 876e1051a39Sopenharmony_ci if (pk == NULL && cert == NULL && dcont == NULL && out == NULL) 877e1051a39Sopenharmony_ci return 1; 878e1051a39Sopenharmony_ci if (pk != NULL && !CMS_decrypt_set1_pkey(cms, pk, cert)) 879e1051a39Sopenharmony_ci return 0; 880e1051a39Sopenharmony_ci cont = CMS_dataInit(cms, dcont); 881e1051a39Sopenharmony_ci if (cont == NULL) 882e1051a39Sopenharmony_ci return 0; 883e1051a39Sopenharmony_ci r = cms_copy_content(out, cont, flags); 884e1051a39Sopenharmony_ci do_free_upto(cont, dcont); 885e1051a39Sopenharmony_ci return r; 886e1051a39Sopenharmony_ci} 887e1051a39Sopenharmony_ci 888e1051a39Sopenharmony_ciint CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags) 889e1051a39Sopenharmony_ci{ 890e1051a39Sopenharmony_ci BIO *cmsbio; 891e1051a39Sopenharmony_ci int ret = 0; 892e1051a39Sopenharmony_ci 893e1051a39Sopenharmony_ci if ((cmsbio = CMS_dataInit(cms, dcont)) == NULL) { 894e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_CMS_LIB); 895e1051a39Sopenharmony_ci return 0; 896e1051a39Sopenharmony_ci } 897e1051a39Sopenharmony_ci 898e1051a39Sopenharmony_ci if (!SMIME_crlf_copy(data, cmsbio, flags)) { 899e1051a39Sopenharmony_ci goto err; 900e1051a39Sopenharmony_ci } 901e1051a39Sopenharmony_ci 902e1051a39Sopenharmony_ci (void)BIO_flush(cmsbio); 903e1051a39Sopenharmony_ci 904e1051a39Sopenharmony_ci if (!CMS_dataFinal(cms, cmsbio)) { 905e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_CMS_DATAFINAL_ERROR); 906e1051a39Sopenharmony_ci goto err; 907e1051a39Sopenharmony_ci } 908e1051a39Sopenharmony_ci 909e1051a39Sopenharmony_ci ret = 1; 910e1051a39Sopenharmony_ci 911e1051a39Sopenharmony_cierr: 912e1051a39Sopenharmony_ci do_free_upto(cmsbio, dcont); 913e1051a39Sopenharmony_ci 914e1051a39Sopenharmony_ci return ret; 915e1051a39Sopenharmony_ci 916e1051a39Sopenharmony_ci} 917e1051a39Sopenharmony_ci 918e1051a39Sopenharmony_ci#ifdef ZLIB 919e1051a39Sopenharmony_ci 920e1051a39Sopenharmony_ciint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 921e1051a39Sopenharmony_ci unsigned int flags) 922e1051a39Sopenharmony_ci{ 923e1051a39Sopenharmony_ci BIO *cont; 924e1051a39Sopenharmony_ci int r; 925e1051a39Sopenharmony_ci 926e1051a39Sopenharmony_ci if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) { 927e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_COMPRESSED_DATA); 928e1051a39Sopenharmony_ci return 0; 929e1051a39Sopenharmony_ci } 930e1051a39Sopenharmony_ci 931e1051a39Sopenharmony_ci if (dcont == NULL && !check_content(cms)) 932e1051a39Sopenharmony_ci return 0; 933e1051a39Sopenharmony_ci 934e1051a39Sopenharmony_ci cont = CMS_dataInit(cms, dcont); 935e1051a39Sopenharmony_ci if (cont == NULL) 936e1051a39Sopenharmony_ci return 0; 937e1051a39Sopenharmony_ci r = cms_copy_content(out, cont, flags); 938e1051a39Sopenharmony_ci do_free_upto(cont, dcont); 939e1051a39Sopenharmony_ci return r; 940e1051a39Sopenharmony_ci} 941e1051a39Sopenharmony_ci 942e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) 943e1051a39Sopenharmony_ci{ 944e1051a39Sopenharmony_ci CMS_ContentInfo *cms; 945e1051a39Sopenharmony_ci 946e1051a39Sopenharmony_ci if (comp_nid <= 0) 947e1051a39Sopenharmony_ci comp_nid = NID_zlib_compression; 948e1051a39Sopenharmony_ci cms = ossl_cms_CompressedData_create(comp_nid, NULL, NULL); 949e1051a39Sopenharmony_ci if (cms == NULL) 950e1051a39Sopenharmony_ci return NULL; 951e1051a39Sopenharmony_ci 952e1051a39Sopenharmony_ci if (!(flags & CMS_DETACHED)) 953e1051a39Sopenharmony_ci CMS_set_detached(cms, 0); 954e1051a39Sopenharmony_ci 955e1051a39Sopenharmony_ci if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) 956e1051a39Sopenharmony_ci return cms; 957e1051a39Sopenharmony_ci 958e1051a39Sopenharmony_ci CMS_ContentInfo_free(cms); 959e1051a39Sopenharmony_ci return NULL; 960e1051a39Sopenharmony_ci} 961e1051a39Sopenharmony_ci 962e1051a39Sopenharmony_ci#else 963e1051a39Sopenharmony_ci 964e1051a39Sopenharmony_ciint CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, 965e1051a39Sopenharmony_ci unsigned int flags) 966e1051a39Sopenharmony_ci{ 967e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); 968e1051a39Sopenharmony_ci return 0; 969e1051a39Sopenharmony_ci} 970e1051a39Sopenharmony_ci 971e1051a39Sopenharmony_ciCMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) 972e1051a39Sopenharmony_ci{ 973e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); 974e1051a39Sopenharmony_ci return NULL; 975e1051a39Sopenharmony_ci} 976e1051a39Sopenharmony_ci 977e1051a39Sopenharmony_ci#endif 978