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