1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-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 <stdio.h>
11e1051a39Sopenharmony_ci#include <openssl/rand.h>
12e1051a39Sopenharmony_ci#include <openssl/objects.h>
13e1051a39Sopenharmony_ci#include <openssl/x509.h>
14e1051a39Sopenharmony_ci#include <openssl/x509v3.h>
15e1051a39Sopenharmony_ci#include <openssl/err.h>
16e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
17e1051a39Sopenharmony_ci#include "internal/sizes.h"
18e1051a39Sopenharmony_ci#include "pk7_local.h"
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_cistatic int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
21e1051a39Sopenharmony_ci                         void *value);
22e1051a39Sopenharmony_cistatic ASN1_TYPE *get_attribute(const STACK_OF(X509_ATTRIBUTE) *sk, int nid);
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ciint PKCS7_type_is_other(PKCS7 *p7)
25e1051a39Sopenharmony_ci{
26e1051a39Sopenharmony_ci    int isOther = 1;
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_ci    int nid = OBJ_obj2nid(p7->type);
29e1051a39Sopenharmony_ci
30e1051a39Sopenharmony_ci    switch (nid) {
31e1051a39Sopenharmony_ci    case NID_pkcs7_data:
32e1051a39Sopenharmony_ci    case NID_pkcs7_signed:
33e1051a39Sopenharmony_ci    case NID_pkcs7_enveloped:
34e1051a39Sopenharmony_ci    case NID_pkcs7_signedAndEnveloped:
35e1051a39Sopenharmony_ci    case NID_pkcs7_digest:
36e1051a39Sopenharmony_ci    case NID_pkcs7_encrypted:
37e1051a39Sopenharmony_ci        isOther = 0;
38e1051a39Sopenharmony_ci        break;
39e1051a39Sopenharmony_ci    default:
40e1051a39Sopenharmony_ci        isOther = 1;
41e1051a39Sopenharmony_ci    }
42e1051a39Sopenharmony_ci
43e1051a39Sopenharmony_ci    return isOther;
44e1051a39Sopenharmony_ci
45e1051a39Sopenharmony_ci}
46e1051a39Sopenharmony_ci
47e1051a39Sopenharmony_ciASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7)
48e1051a39Sopenharmony_ci{
49e1051a39Sopenharmony_ci    if (PKCS7_type_is_data(p7))
50e1051a39Sopenharmony_ci        return p7->d.data;
51e1051a39Sopenharmony_ci    if (PKCS7_type_is_other(p7) && p7->d.other
52e1051a39Sopenharmony_ci        && (p7->d.other->type == V_ASN1_OCTET_STRING))
53e1051a39Sopenharmony_ci        return p7->d.other->value.octet_string;
54e1051a39Sopenharmony_ci    return NULL;
55e1051a39Sopenharmony_ci}
56e1051a39Sopenharmony_ci
57e1051a39Sopenharmony_cistatic int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg,
58e1051a39Sopenharmony_ci                                const PKCS7_CTX *ctx)
59e1051a39Sopenharmony_ci{
60e1051a39Sopenharmony_ci    BIO *btmp;
61e1051a39Sopenharmony_ci    char name[OSSL_MAX_NAME_SIZE];
62e1051a39Sopenharmony_ci    EVP_MD *fetched = NULL;
63e1051a39Sopenharmony_ci    const EVP_MD *md;
64e1051a39Sopenharmony_ci
65e1051a39Sopenharmony_ci    if ((btmp = BIO_new(BIO_f_md())) == NULL) {
66e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB);
67e1051a39Sopenharmony_ci        goto err;
68e1051a39Sopenharmony_ci    }
69e1051a39Sopenharmony_ci
70e1051a39Sopenharmony_ci    OBJ_obj2txt(name, sizeof(name), alg->algorithm, 0);
71e1051a39Sopenharmony_ci
72e1051a39Sopenharmony_ci    (void)ERR_set_mark();
73e1051a39Sopenharmony_ci    fetched = EVP_MD_fetch(ossl_pkcs7_ctx_get0_libctx(ctx), name,
74e1051a39Sopenharmony_ci                           ossl_pkcs7_ctx_get0_propq(ctx));
75e1051a39Sopenharmony_ci    if (fetched != NULL)
76e1051a39Sopenharmony_ci        md = fetched;
77e1051a39Sopenharmony_ci    else
78e1051a39Sopenharmony_ci        md = EVP_get_digestbyname(name);
79e1051a39Sopenharmony_ci
80e1051a39Sopenharmony_ci    if (md == NULL) {
81e1051a39Sopenharmony_ci        (void)ERR_clear_last_mark();
82e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE);
83e1051a39Sopenharmony_ci        goto err;
84e1051a39Sopenharmony_ci    }
85e1051a39Sopenharmony_ci    (void)ERR_pop_to_mark();
86e1051a39Sopenharmony_ci
87e1051a39Sopenharmony_ci    if (BIO_set_md(btmp, md) <= 0) {
88e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB);
89e1051a39Sopenharmony_ci        EVP_MD_free(fetched);
90e1051a39Sopenharmony_ci        goto err;
91e1051a39Sopenharmony_ci    }
92e1051a39Sopenharmony_ci    EVP_MD_free(fetched);
93e1051a39Sopenharmony_ci    if (*pbio == NULL)
94e1051a39Sopenharmony_ci        *pbio = btmp;
95e1051a39Sopenharmony_ci    else if (!BIO_push(*pbio, btmp)) {
96e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB);
97e1051a39Sopenharmony_ci        goto err;
98e1051a39Sopenharmony_ci    }
99e1051a39Sopenharmony_ci    btmp = NULL;
100e1051a39Sopenharmony_ci
101e1051a39Sopenharmony_ci    return 1;
102e1051a39Sopenharmony_ci
103e1051a39Sopenharmony_ci err:
104e1051a39Sopenharmony_ci    BIO_free(btmp);
105e1051a39Sopenharmony_ci    return 0;
106e1051a39Sopenharmony_ci}
107e1051a39Sopenharmony_ci
108e1051a39Sopenharmony_cistatic int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri,
109e1051a39Sopenharmony_ci                              unsigned char *key, int keylen)
110e1051a39Sopenharmony_ci{
111e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pctx = NULL;
112e1051a39Sopenharmony_ci    EVP_PKEY *pkey = NULL;
113e1051a39Sopenharmony_ci    unsigned char *ek = NULL;
114e1051a39Sopenharmony_ci    int ret = 0;
115e1051a39Sopenharmony_ci    size_t eklen;
116e1051a39Sopenharmony_ci    const PKCS7_CTX *ctx = ri->ctx;
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_ci    pkey = X509_get0_pubkey(ri->cert);
119e1051a39Sopenharmony_ci    if (pkey == NULL)
120e1051a39Sopenharmony_ci        return 0;
121e1051a39Sopenharmony_ci
122e1051a39Sopenharmony_ci    pctx = EVP_PKEY_CTX_new_from_pkey(ossl_pkcs7_ctx_get0_libctx(ctx), pkey,
123e1051a39Sopenharmony_ci                                      ossl_pkcs7_ctx_get0_propq(ctx));
124e1051a39Sopenharmony_ci    if (pctx == NULL)
125e1051a39Sopenharmony_ci        return 0;
126e1051a39Sopenharmony_ci
127e1051a39Sopenharmony_ci    if (EVP_PKEY_encrypt_init(pctx) <= 0)
128e1051a39Sopenharmony_ci        goto err;
129e1051a39Sopenharmony_ci
130e1051a39Sopenharmony_ci    if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0)
131e1051a39Sopenharmony_ci        goto err;
132e1051a39Sopenharmony_ci
133e1051a39Sopenharmony_ci    ek = OPENSSL_malloc(eklen);
134e1051a39Sopenharmony_ci
135e1051a39Sopenharmony_ci    if (ek == NULL) {
136e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
137e1051a39Sopenharmony_ci        goto err;
138e1051a39Sopenharmony_ci    }
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci    if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0)
141e1051a39Sopenharmony_ci        goto err;
142e1051a39Sopenharmony_ci
143e1051a39Sopenharmony_ci    ASN1_STRING_set0(ri->enc_key, ek, eklen);
144e1051a39Sopenharmony_ci    ek = NULL;
145e1051a39Sopenharmony_ci
146e1051a39Sopenharmony_ci    ret = 1;
147e1051a39Sopenharmony_ci
148e1051a39Sopenharmony_ci err:
149e1051a39Sopenharmony_ci    EVP_PKEY_CTX_free(pctx);
150e1051a39Sopenharmony_ci    OPENSSL_free(ek);
151e1051a39Sopenharmony_ci    return ret;
152e1051a39Sopenharmony_ci
153e1051a39Sopenharmony_ci}
154e1051a39Sopenharmony_ci
155e1051a39Sopenharmony_cistatic int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
156e1051a39Sopenharmony_ci                               PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey,
157e1051a39Sopenharmony_ci                               size_t fixlen)
158e1051a39Sopenharmony_ci{
159e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pctx = NULL;
160e1051a39Sopenharmony_ci    unsigned char *ek = NULL;
161e1051a39Sopenharmony_ci    size_t eklen;
162e1051a39Sopenharmony_ci    int ret = -1;
163e1051a39Sopenharmony_ci    const PKCS7_CTX *ctx = ri->ctx;
164e1051a39Sopenharmony_ci
165e1051a39Sopenharmony_ci    pctx = EVP_PKEY_CTX_new_from_pkey(ossl_pkcs7_ctx_get0_libctx(ctx), pkey,
166e1051a39Sopenharmony_ci                                      ossl_pkcs7_ctx_get0_propq(ctx));
167e1051a39Sopenharmony_ci    if (pctx == NULL)
168e1051a39Sopenharmony_ci        return -1;
169e1051a39Sopenharmony_ci
170e1051a39Sopenharmony_ci    if (EVP_PKEY_decrypt_init(pctx) <= 0)
171e1051a39Sopenharmony_ci        goto err;
172e1051a39Sopenharmony_ci
173e1051a39Sopenharmony_ci    if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
174e1051a39Sopenharmony_ci                         ri->enc_key->data, ri->enc_key->length) <= 0)
175e1051a39Sopenharmony_ci        goto err;
176e1051a39Sopenharmony_ci
177e1051a39Sopenharmony_ci    ek = OPENSSL_malloc(eklen);
178e1051a39Sopenharmony_ci
179e1051a39Sopenharmony_ci    if (ek == NULL) {
180e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
181e1051a39Sopenharmony_ci        goto err;
182e1051a39Sopenharmony_ci    }
183e1051a39Sopenharmony_ci
184e1051a39Sopenharmony_ci    if (EVP_PKEY_decrypt(pctx, ek, &eklen,
185e1051a39Sopenharmony_ci                         ri->enc_key->data, ri->enc_key->length) <= 0
186e1051a39Sopenharmony_ci            || eklen == 0
187e1051a39Sopenharmony_ci            || (fixlen != 0 && eklen != fixlen)) {
188e1051a39Sopenharmony_ci        ret = 0;
189e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_EVP_LIB);
190e1051a39Sopenharmony_ci        goto err;
191e1051a39Sopenharmony_ci    }
192e1051a39Sopenharmony_ci
193e1051a39Sopenharmony_ci    ret = 1;
194e1051a39Sopenharmony_ci
195e1051a39Sopenharmony_ci    OPENSSL_clear_free(*pek, *peklen);
196e1051a39Sopenharmony_ci    *pek = ek;
197e1051a39Sopenharmony_ci    *peklen = eklen;
198e1051a39Sopenharmony_ci
199e1051a39Sopenharmony_ci err:
200e1051a39Sopenharmony_ci    EVP_PKEY_CTX_free(pctx);
201e1051a39Sopenharmony_ci    if (!ret)
202e1051a39Sopenharmony_ci        OPENSSL_free(ek);
203e1051a39Sopenharmony_ci
204e1051a39Sopenharmony_ci    return ret;
205e1051a39Sopenharmony_ci}
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ciBIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
208e1051a39Sopenharmony_ci{
209e1051a39Sopenharmony_ci    int i;
210e1051a39Sopenharmony_ci    BIO *out = NULL, *btmp = NULL;
211e1051a39Sopenharmony_ci    X509_ALGOR *xa = NULL;
212e1051a39Sopenharmony_ci    EVP_CIPHER *fetched_cipher = NULL;
213e1051a39Sopenharmony_ci    const EVP_CIPHER *cipher;
214e1051a39Sopenharmony_ci    const EVP_CIPHER *evp_cipher = NULL;
215e1051a39Sopenharmony_ci    STACK_OF(X509_ALGOR) *md_sk = NULL;
216e1051a39Sopenharmony_ci    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
217e1051a39Sopenharmony_ci    X509_ALGOR *xalg = NULL;
218e1051a39Sopenharmony_ci    PKCS7_RECIP_INFO *ri = NULL;
219e1051a39Sopenharmony_ci    ASN1_OCTET_STRING *os = NULL;
220e1051a39Sopenharmony_ci    const PKCS7_CTX *p7_ctx;
221e1051a39Sopenharmony_ci    OSSL_LIB_CTX *libctx;
222e1051a39Sopenharmony_ci    const char *propq;
223e1051a39Sopenharmony_ci
224e1051a39Sopenharmony_ci    if (p7 == NULL) {
225e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER);
226e1051a39Sopenharmony_ci        return NULL;
227e1051a39Sopenharmony_ci    }
228e1051a39Sopenharmony_ci    p7_ctx = ossl_pkcs7_get0_ctx(p7);
229e1051a39Sopenharmony_ci    libctx = ossl_pkcs7_ctx_get0_libctx(p7_ctx);
230e1051a39Sopenharmony_ci    propq = ossl_pkcs7_ctx_get0_propq(p7_ctx);
231e1051a39Sopenharmony_ci
232e1051a39Sopenharmony_ci    /*
233e1051a39Sopenharmony_ci     * The content field in the PKCS7 ContentInfo is optional, but that really
234e1051a39Sopenharmony_ci     * only applies to inner content (precisely, detached signatures).
235e1051a39Sopenharmony_ci     *
236e1051a39Sopenharmony_ci     * When reading content, missing outer content is therefore treated as an
237e1051a39Sopenharmony_ci     * error.
238e1051a39Sopenharmony_ci     *
239e1051a39Sopenharmony_ci     * When creating content, PKCS7_content_new() must be called before
240e1051a39Sopenharmony_ci     * calling this method, so a NULL p7->d is always an error.
241e1051a39Sopenharmony_ci     */
242e1051a39Sopenharmony_ci    if (p7->d.ptr == NULL) {
243e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT);
244e1051a39Sopenharmony_ci        return NULL;
245e1051a39Sopenharmony_ci    }
246e1051a39Sopenharmony_ci
247e1051a39Sopenharmony_ci    i = OBJ_obj2nid(p7->type);
248e1051a39Sopenharmony_ci    p7->state = PKCS7_S_HEADER;
249e1051a39Sopenharmony_ci
250e1051a39Sopenharmony_ci    switch (i) {
251e1051a39Sopenharmony_ci    case NID_pkcs7_signed:
252e1051a39Sopenharmony_ci        md_sk = p7->d.sign->md_algs;
253e1051a39Sopenharmony_ci        os = PKCS7_get_octet_string(p7->d.sign->contents);
254e1051a39Sopenharmony_ci        break;
255e1051a39Sopenharmony_ci    case NID_pkcs7_signedAndEnveloped:
256e1051a39Sopenharmony_ci        rsk = p7->d.signed_and_enveloped->recipientinfo;
257e1051a39Sopenharmony_ci        md_sk = p7->d.signed_and_enveloped->md_algs;
258e1051a39Sopenharmony_ci        xalg = p7->d.signed_and_enveloped->enc_data->algorithm;
259e1051a39Sopenharmony_ci        evp_cipher = p7->d.signed_and_enveloped->enc_data->cipher;
260e1051a39Sopenharmony_ci        if (evp_cipher == NULL) {
261e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED);
262e1051a39Sopenharmony_ci            goto err;
263e1051a39Sopenharmony_ci        }
264e1051a39Sopenharmony_ci        break;
265e1051a39Sopenharmony_ci    case NID_pkcs7_enveloped:
266e1051a39Sopenharmony_ci        rsk = p7->d.enveloped->recipientinfo;
267e1051a39Sopenharmony_ci        xalg = p7->d.enveloped->enc_data->algorithm;
268e1051a39Sopenharmony_ci        evp_cipher = p7->d.enveloped->enc_data->cipher;
269e1051a39Sopenharmony_ci        if (evp_cipher == NULL) {
270e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED);
271e1051a39Sopenharmony_ci            goto err;
272e1051a39Sopenharmony_ci        }
273e1051a39Sopenharmony_ci        break;
274e1051a39Sopenharmony_ci    case NID_pkcs7_digest:
275e1051a39Sopenharmony_ci        xa = p7->d.digest->md;
276e1051a39Sopenharmony_ci        os = PKCS7_get_octet_string(p7->d.digest->contents);
277e1051a39Sopenharmony_ci        break;
278e1051a39Sopenharmony_ci    case NID_pkcs7_data:
279e1051a39Sopenharmony_ci        break;
280e1051a39Sopenharmony_ci    default:
281e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
282e1051a39Sopenharmony_ci        goto err;
283e1051a39Sopenharmony_ci    }
284e1051a39Sopenharmony_ci
285e1051a39Sopenharmony_ci    for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++)
286e1051a39Sopenharmony_ci        if (!pkcs7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i), p7_ctx))
287e1051a39Sopenharmony_ci            goto err;
288e1051a39Sopenharmony_ci
289e1051a39Sopenharmony_ci    if (xa && !pkcs7_bio_add_digest(&out, xa, p7_ctx))
290e1051a39Sopenharmony_ci        goto err;
291e1051a39Sopenharmony_ci
292e1051a39Sopenharmony_ci    if (evp_cipher != NULL) {
293e1051a39Sopenharmony_ci        unsigned char key[EVP_MAX_KEY_LENGTH];
294e1051a39Sopenharmony_ci        unsigned char iv[EVP_MAX_IV_LENGTH];
295e1051a39Sopenharmony_ci        int keylen, ivlen;
296e1051a39Sopenharmony_ci        EVP_CIPHER_CTX *ctx;
297e1051a39Sopenharmony_ci
298e1051a39Sopenharmony_ci        if ((btmp = BIO_new(BIO_f_cipher())) == NULL) {
299e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB);
300e1051a39Sopenharmony_ci            goto err;
301e1051a39Sopenharmony_ci        }
302e1051a39Sopenharmony_ci        BIO_get_cipher_ctx(btmp, &ctx);
303e1051a39Sopenharmony_ci        keylen = EVP_CIPHER_get_key_length(evp_cipher);
304e1051a39Sopenharmony_ci        ivlen = EVP_CIPHER_get_iv_length(evp_cipher);
305e1051a39Sopenharmony_ci        xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_get_type(evp_cipher));
306e1051a39Sopenharmony_ci        if (ivlen > 0)
307e1051a39Sopenharmony_ci            if (RAND_bytes_ex(libctx, iv, ivlen, 0) <= 0)
308e1051a39Sopenharmony_ci                goto err;
309e1051a39Sopenharmony_ci
310e1051a39Sopenharmony_ci        (void)ERR_set_mark();
311e1051a39Sopenharmony_ci        fetched_cipher = EVP_CIPHER_fetch(libctx,
312e1051a39Sopenharmony_ci                                          EVP_CIPHER_get0_name(evp_cipher),
313e1051a39Sopenharmony_ci                                          propq);
314e1051a39Sopenharmony_ci        (void)ERR_pop_to_mark();
315e1051a39Sopenharmony_ci        if (fetched_cipher != NULL)
316e1051a39Sopenharmony_ci            cipher = fetched_cipher;
317e1051a39Sopenharmony_ci        else
318e1051a39Sopenharmony_ci            cipher = evp_cipher;
319e1051a39Sopenharmony_ci
320e1051a39Sopenharmony_ci        if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, 1) <= 0)
321e1051a39Sopenharmony_ci            goto err;
322e1051a39Sopenharmony_ci
323e1051a39Sopenharmony_ci        EVP_CIPHER_free(fetched_cipher);
324e1051a39Sopenharmony_ci        fetched_cipher = NULL;
325e1051a39Sopenharmony_ci
326e1051a39Sopenharmony_ci        if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
327e1051a39Sopenharmony_ci            goto err;
328e1051a39Sopenharmony_ci        if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0)
329e1051a39Sopenharmony_ci            goto err;
330e1051a39Sopenharmony_ci
331e1051a39Sopenharmony_ci        if (ivlen > 0) {
332e1051a39Sopenharmony_ci            if (xalg->parameter == NULL) {
333e1051a39Sopenharmony_ci                xalg->parameter = ASN1_TYPE_new();
334e1051a39Sopenharmony_ci                if (xalg->parameter == NULL)
335e1051a39Sopenharmony_ci                    goto err;
336e1051a39Sopenharmony_ci            }
337e1051a39Sopenharmony_ci            if (EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) <= 0)
338e1051a39Sopenharmony_ci                goto err;
339e1051a39Sopenharmony_ci        }
340e1051a39Sopenharmony_ci
341e1051a39Sopenharmony_ci        /* Lets do the pub key stuff :-) */
342e1051a39Sopenharmony_ci        for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
343e1051a39Sopenharmony_ci            ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
344e1051a39Sopenharmony_ci            if (pkcs7_encode_rinfo(ri, key, keylen) <= 0)
345e1051a39Sopenharmony_ci                goto err;
346e1051a39Sopenharmony_ci        }
347e1051a39Sopenharmony_ci        OPENSSL_cleanse(key, keylen);
348e1051a39Sopenharmony_ci
349e1051a39Sopenharmony_ci        if (out == NULL)
350e1051a39Sopenharmony_ci            out = btmp;
351e1051a39Sopenharmony_ci        else
352e1051a39Sopenharmony_ci            BIO_push(out, btmp);
353e1051a39Sopenharmony_ci        btmp = NULL;
354e1051a39Sopenharmony_ci    }
355e1051a39Sopenharmony_ci
356e1051a39Sopenharmony_ci    if (bio == NULL) {
357e1051a39Sopenharmony_ci        if (PKCS7_is_detached(p7)) {
358e1051a39Sopenharmony_ci            bio = BIO_new(BIO_s_null());
359e1051a39Sopenharmony_ci        } else if (os && os->length > 0) {
360e1051a39Sopenharmony_ci            bio = BIO_new_mem_buf(os->data, os->length);
361e1051a39Sopenharmony_ci        } else {
362e1051a39Sopenharmony_ci            bio = BIO_new(BIO_s_mem());
363e1051a39Sopenharmony_ci            if (bio == NULL)
364e1051a39Sopenharmony_ci                goto err;
365e1051a39Sopenharmony_ci            BIO_set_mem_eof_return(bio, 0);
366e1051a39Sopenharmony_ci        }
367e1051a39Sopenharmony_ci        if (bio == NULL)
368e1051a39Sopenharmony_ci            goto err;
369e1051a39Sopenharmony_ci    }
370e1051a39Sopenharmony_ci    if (out)
371e1051a39Sopenharmony_ci        BIO_push(out, bio);
372e1051a39Sopenharmony_ci    else
373e1051a39Sopenharmony_ci        out = bio;
374e1051a39Sopenharmony_ci    return out;
375e1051a39Sopenharmony_ci
376e1051a39Sopenharmony_ci err:
377e1051a39Sopenharmony_ci    EVP_CIPHER_free(fetched_cipher);
378e1051a39Sopenharmony_ci    BIO_free_all(out);
379e1051a39Sopenharmony_ci    BIO_free_all(btmp);
380e1051a39Sopenharmony_ci    return NULL;
381e1051a39Sopenharmony_ci}
382e1051a39Sopenharmony_ci
383e1051a39Sopenharmony_cistatic int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert)
384e1051a39Sopenharmony_ci{
385e1051a39Sopenharmony_ci    int ret;
386e1051a39Sopenharmony_ci    ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
387e1051a39Sopenharmony_ci                        X509_get_issuer_name(pcert));
388e1051a39Sopenharmony_ci    if (ret)
389e1051a39Sopenharmony_ci        return ret;
390e1051a39Sopenharmony_ci    return ASN1_INTEGER_cmp(X509_get0_serialNumber(pcert),
391e1051a39Sopenharmony_ci                            ri->issuer_and_serial->serial);
392e1051a39Sopenharmony_ci}
393e1051a39Sopenharmony_ci
394e1051a39Sopenharmony_ci/* int */
395e1051a39Sopenharmony_ciBIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
396e1051a39Sopenharmony_ci{
397e1051a39Sopenharmony_ci    int i, len;
398e1051a39Sopenharmony_ci    BIO *out = NULL, *btmp = NULL, *etmp = NULL, *bio = NULL;
399e1051a39Sopenharmony_ci    X509_ALGOR *xa;
400e1051a39Sopenharmony_ci    ASN1_OCTET_STRING *data_body = NULL;
401e1051a39Sopenharmony_ci    EVP_MD *evp_md = NULL;
402e1051a39Sopenharmony_ci    const EVP_MD *md;
403e1051a39Sopenharmony_ci    EVP_CIPHER *evp_cipher = NULL;
404e1051a39Sopenharmony_ci    const EVP_CIPHER *cipher = NULL;
405e1051a39Sopenharmony_ci    EVP_CIPHER_CTX *evp_ctx = NULL;
406e1051a39Sopenharmony_ci    X509_ALGOR *enc_alg = NULL;
407e1051a39Sopenharmony_ci    STACK_OF(X509_ALGOR) *md_sk = NULL;
408e1051a39Sopenharmony_ci    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
409e1051a39Sopenharmony_ci    PKCS7_RECIP_INFO *ri = NULL;
410e1051a39Sopenharmony_ci    unsigned char *ek = NULL, *tkey = NULL;
411e1051a39Sopenharmony_ci    int eklen = 0, tkeylen = 0;
412e1051a39Sopenharmony_ci    char name[OSSL_MAX_NAME_SIZE];
413e1051a39Sopenharmony_ci    const PKCS7_CTX *p7_ctx;
414e1051a39Sopenharmony_ci    OSSL_LIB_CTX *libctx;
415e1051a39Sopenharmony_ci    const char *propq;
416e1051a39Sopenharmony_ci
417e1051a39Sopenharmony_ci    if (p7 == NULL) {
418e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER);
419e1051a39Sopenharmony_ci        return NULL;
420e1051a39Sopenharmony_ci    }
421e1051a39Sopenharmony_ci
422e1051a39Sopenharmony_ci    p7_ctx = ossl_pkcs7_get0_ctx(p7);
423e1051a39Sopenharmony_ci    libctx = ossl_pkcs7_ctx_get0_libctx(p7_ctx);
424e1051a39Sopenharmony_ci    propq = ossl_pkcs7_ctx_get0_propq(p7_ctx);
425e1051a39Sopenharmony_ci
426e1051a39Sopenharmony_ci    if (p7->d.ptr == NULL) {
427e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT);
428e1051a39Sopenharmony_ci        return NULL;
429e1051a39Sopenharmony_ci    }
430e1051a39Sopenharmony_ci
431e1051a39Sopenharmony_ci    i = OBJ_obj2nid(p7->type);
432e1051a39Sopenharmony_ci    p7->state = PKCS7_S_HEADER;
433e1051a39Sopenharmony_ci
434e1051a39Sopenharmony_ci    switch (i) {
435e1051a39Sopenharmony_ci    case NID_pkcs7_signed:
436e1051a39Sopenharmony_ci        /*
437e1051a39Sopenharmony_ci         * p7->d.sign->contents is a PKCS7 structure consisting of a contentType
438e1051a39Sopenharmony_ci         * field and optional content.
439e1051a39Sopenharmony_ci         * data_body is NULL if that structure has no (=detached) content
440e1051a39Sopenharmony_ci         * or if the contentType is wrong (i.e., not "data").
441e1051a39Sopenharmony_ci         */
442e1051a39Sopenharmony_ci        data_body = PKCS7_get_octet_string(p7->d.sign->contents);
443e1051a39Sopenharmony_ci        if (!PKCS7_is_detached(p7) && data_body == NULL) {
444e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_INVALID_SIGNED_DATA_TYPE);
445e1051a39Sopenharmony_ci            goto err;
446e1051a39Sopenharmony_ci        }
447e1051a39Sopenharmony_ci        md_sk = p7->d.sign->md_algs;
448e1051a39Sopenharmony_ci        break;
449e1051a39Sopenharmony_ci    case NID_pkcs7_signedAndEnveloped:
450e1051a39Sopenharmony_ci        rsk = p7->d.signed_and_enveloped->recipientinfo;
451e1051a39Sopenharmony_ci        md_sk = p7->d.signed_and_enveloped->md_algs;
452e1051a39Sopenharmony_ci        /* data_body is NULL if the optional EncryptedContent is missing. */
453e1051a39Sopenharmony_ci        data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
454e1051a39Sopenharmony_ci        enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm;
455e1051a39Sopenharmony_ci
456e1051a39Sopenharmony_ci        OBJ_obj2txt(name, sizeof(name), enc_alg->algorithm, 0);
457e1051a39Sopenharmony_ci
458e1051a39Sopenharmony_ci        (void)ERR_set_mark();
459e1051a39Sopenharmony_ci        evp_cipher = EVP_CIPHER_fetch(libctx, name, propq);
460e1051a39Sopenharmony_ci        if (evp_cipher != NULL)
461e1051a39Sopenharmony_ci            cipher = evp_cipher;
462e1051a39Sopenharmony_ci        else
463e1051a39Sopenharmony_ci            cipher = EVP_get_cipherbyname(name);
464e1051a39Sopenharmony_ci
465e1051a39Sopenharmony_ci        if (cipher == NULL) {
466e1051a39Sopenharmony_ci            (void)ERR_clear_last_mark();
467e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
468e1051a39Sopenharmony_ci            goto err;
469e1051a39Sopenharmony_ci        }
470e1051a39Sopenharmony_ci        (void)ERR_pop_to_mark();
471e1051a39Sopenharmony_ci        break;
472e1051a39Sopenharmony_ci    case NID_pkcs7_enveloped:
473e1051a39Sopenharmony_ci        rsk = p7->d.enveloped->recipientinfo;
474e1051a39Sopenharmony_ci        enc_alg = p7->d.enveloped->enc_data->algorithm;
475e1051a39Sopenharmony_ci        /* data_body is NULL if the optional EncryptedContent is missing. */
476e1051a39Sopenharmony_ci        data_body = p7->d.enveloped->enc_data->enc_data;
477e1051a39Sopenharmony_ci        OBJ_obj2txt(name, sizeof(name), enc_alg->algorithm, 0);
478e1051a39Sopenharmony_ci
479e1051a39Sopenharmony_ci        (void)ERR_set_mark();
480e1051a39Sopenharmony_ci        evp_cipher = EVP_CIPHER_fetch(libctx, name, propq);
481e1051a39Sopenharmony_ci        if (evp_cipher != NULL)
482e1051a39Sopenharmony_ci            cipher = evp_cipher;
483e1051a39Sopenharmony_ci        else
484e1051a39Sopenharmony_ci            cipher = EVP_get_cipherbyname(name);
485e1051a39Sopenharmony_ci
486e1051a39Sopenharmony_ci        if (cipher == NULL) {
487e1051a39Sopenharmony_ci            (void)ERR_clear_last_mark();
488e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
489e1051a39Sopenharmony_ci            goto err;
490e1051a39Sopenharmony_ci        }
491e1051a39Sopenharmony_ci        (void)ERR_pop_to_mark();
492e1051a39Sopenharmony_ci        break;
493e1051a39Sopenharmony_ci    default:
494e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
495e1051a39Sopenharmony_ci        goto err;
496e1051a39Sopenharmony_ci    }
497e1051a39Sopenharmony_ci
498e1051a39Sopenharmony_ci    /* Detached content must be supplied via in_bio instead. */
499e1051a39Sopenharmony_ci    if (data_body == NULL && in_bio == NULL) {
500e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT);
501e1051a39Sopenharmony_ci        goto err;
502e1051a39Sopenharmony_ci    }
503e1051a39Sopenharmony_ci
504e1051a39Sopenharmony_ci    /* We will be checking the signature */
505e1051a39Sopenharmony_ci    if (md_sk != NULL) {
506e1051a39Sopenharmony_ci        for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) {
507e1051a39Sopenharmony_ci            xa = sk_X509_ALGOR_value(md_sk, i);
508e1051a39Sopenharmony_ci            if ((btmp = BIO_new(BIO_f_md())) == NULL) {
509e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB);
510e1051a39Sopenharmony_ci                goto err;
511e1051a39Sopenharmony_ci            }
512e1051a39Sopenharmony_ci
513e1051a39Sopenharmony_ci            OBJ_obj2txt(name, sizeof(name), xa->algorithm, 0);
514e1051a39Sopenharmony_ci
515e1051a39Sopenharmony_ci            (void)ERR_set_mark();
516e1051a39Sopenharmony_ci            evp_md = EVP_MD_fetch(libctx, name, propq);
517e1051a39Sopenharmony_ci            if (evp_md != NULL)
518e1051a39Sopenharmony_ci                md = evp_md;
519e1051a39Sopenharmony_ci            else
520e1051a39Sopenharmony_ci                md = EVP_get_digestbyname(name);
521e1051a39Sopenharmony_ci
522e1051a39Sopenharmony_ci            if (md == NULL) {
523e1051a39Sopenharmony_ci                (void)ERR_clear_last_mark();
524e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE);
525e1051a39Sopenharmony_ci                goto err;
526e1051a39Sopenharmony_ci            }
527e1051a39Sopenharmony_ci            (void)ERR_pop_to_mark();
528e1051a39Sopenharmony_ci
529e1051a39Sopenharmony_ci            if (BIO_set_md(btmp, md) <= 0) {
530e1051a39Sopenharmony_ci                EVP_MD_free(evp_md);
531e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB);
532e1051a39Sopenharmony_ci                goto err;
533e1051a39Sopenharmony_ci            }
534e1051a39Sopenharmony_ci            EVP_MD_free(evp_md);
535e1051a39Sopenharmony_ci            if (out == NULL)
536e1051a39Sopenharmony_ci                out = btmp;
537e1051a39Sopenharmony_ci            else
538e1051a39Sopenharmony_ci                BIO_push(out, btmp);
539e1051a39Sopenharmony_ci            btmp = NULL;
540e1051a39Sopenharmony_ci        }
541e1051a39Sopenharmony_ci    }
542e1051a39Sopenharmony_ci
543e1051a39Sopenharmony_ci    if (cipher != NULL) {
544e1051a39Sopenharmony_ci        if ((etmp = BIO_new(BIO_f_cipher())) == NULL) {
545e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB);
546e1051a39Sopenharmony_ci            goto err;
547e1051a39Sopenharmony_ci        }
548e1051a39Sopenharmony_ci
549e1051a39Sopenharmony_ci        /*
550e1051a39Sopenharmony_ci         * It was encrypted, we need to decrypt the secret key with the
551e1051a39Sopenharmony_ci         * private key
552e1051a39Sopenharmony_ci         */
553e1051a39Sopenharmony_ci
554e1051a39Sopenharmony_ci        /*
555e1051a39Sopenharmony_ci         * Find the recipientInfo which matches the passed certificate (if
556e1051a39Sopenharmony_ci         * any)
557e1051a39Sopenharmony_ci         */
558e1051a39Sopenharmony_ci
559e1051a39Sopenharmony_ci        if (pcert) {
560e1051a39Sopenharmony_ci            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
561e1051a39Sopenharmony_ci                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
562e1051a39Sopenharmony_ci                if (!pkcs7_cmp_ri(ri, pcert))
563e1051a39Sopenharmony_ci                    break;
564e1051a39Sopenharmony_ci                ri = NULL;
565e1051a39Sopenharmony_ci            }
566e1051a39Sopenharmony_ci            if (ri == NULL) {
567e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_PKCS7,
568e1051a39Sopenharmony_ci                          PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
569e1051a39Sopenharmony_ci                goto err;
570e1051a39Sopenharmony_ci            }
571e1051a39Sopenharmony_ci        }
572e1051a39Sopenharmony_ci
573e1051a39Sopenharmony_ci        /* If we haven't got a certificate try each ri in turn */
574e1051a39Sopenharmony_ci        if (pcert == NULL) {
575e1051a39Sopenharmony_ci            /*
576e1051a39Sopenharmony_ci             * Always attempt to decrypt all rinfo even after success as a
577e1051a39Sopenharmony_ci             * defence against MMA timing attacks.
578e1051a39Sopenharmony_ci             */
579e1051a39Sopenharmony_ci            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
580e1051a39Sopenharmony_ci                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
581e1051a39Sopenharmony_ci                ri->ctx = p7_ctx;
582e1051a39Sopenharmony_ci                if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey,
583e1051a39Sopenharmony_ci                        EVP_CIPHER_get_key_length(cipher)) < 0)
584e1051a39Sopenharmony_ci                    goto err;
585e1051a39Sopenharmony_ci                ERR_clear_error();
586e1051a39Sopenharmony_ci            }
587e1051a39Sopenharmony_ci        } else {
588e1051a39Sopenharmony_ci            ri->ctx = p7_ctx;
589e1051a39Sopenharmony_ci            /* Only exit on fatal errors, not decrypt failure */
590e1051a39Sopenharmony_ci            if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey, 0) < 0)
591e1051a39Sopenharmony_ci                goto err;
592e1051a39Sopenharmony_ci            ERR_clear_error();
593e1051a39Sopenharmony_ci        }
594e1051a39Sopenharmony_ci
595e1051a39Sopenharmony_ci        evp_ctx = NULL;
596e1051a39Sopenharmony_ci        BIO_get_cipher_ctx(etmp, &evp_ctx);
597e1051a39Sopenharmony_ci        if (EVP_CipherInit_ex(evp_ctx, cipher, NULL, NULL, NULL, 0) <= 0)
598e1051a39Sopenharmony_ci            goto err;
599e1051a39Sopenharmony_ci        if (EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) <= 0)
600e1051a39Sopenharmony_ci            goto err;
601e1051a39Sopenharmony_ci        /* Generate random key as MMA defence */
602e1051a39Sopenharmony_ci        len = EVP_CIPHER_CTX_get_key_length(evp_ctx);
603e1051a39Sopenharmony_ci        if (len <= 0)
604e1051a39Sopenharmony_ci            goto err;
605e1051a39Sopenharmony_ci        tkeylen = (size_t)len;
606e1051a39Sopenharmony_ci        tkey = OPENSSL_malloc(tkeylen);
607e1051a39Sopenharmony_ci        if (tkey == NULL)
608e1051a39Sopenharmony_ci            goto err;
609e1051a39Sopenharmony_ci        if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
610e1051a39Sopenharmony_ci            goto err;
611e1051a39Sopenharmony_ci        if (ek == NULL) {
612e1051a39Sopenharmony_ci            ek = tkey;
613e1051a39Sopenharmony_ci            eklen = tkeylen;
614e1051a39Sopenharmony_ci            tkey = NULL;
615e1051a39Sopenharmony_ci        }
616e1051a39Sopenharmony_ci
617e1051a39Sopenharmony_ci        if (eklen != EVP_CIPHER_CTX_get_key_length(evp_ctx)) {
618e1051a39Sopenharmony_ci            /*
619e1051a39Sopenharmony_ci             * Some S/MIME clients don't use the same key and effective key
620e1051a39Sopenharmony_ci             * length. The key length is determined by the size of the
621e1051a39Sopenharmony_ci             * decrypted RSA key.
622e1051a39Sopenharmony_ci             */
623e1051a39Sopenharmony_ci            if (EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen) <= 0) {
624e1051a39Sopenharmony_ci                /* Use random key as MMA defence */
625e1051a39Sopenharmony_ci                OPENSSL_clear_free(ek, eklen);
626e1051a39Sopenharmony_ci                ek = tkey;
627e1051a39Sopenharmony_ci                eklen = tkeylen;
628e1051a39Sopenharmony_ci                tkey = NULL;
629e1051a39Sopenharmony_ci            }
630e1051a39Sopenharmony_ci        }
631e1051a39Sopenharmony_ci        /* Clear errors so we don't leak information useful in MMA */
632e1051a39Sopenharmony_ci        ERR_clear_error();
633e1051a39Sopenharmony_ci        if (EVP_CipherInit_ex(evp_ctx, NULL, NULL, ek, NULL, 0) <= 0)
634e1051a39Sopenharmony_ci            goto err;
635e1051a39Sopenharmony_ci
636e1051a39Sopenharmony_ci        OPENSSL_clear_free(ek, eklen);
637e1051a39Sopenharmony_ci        ek = NULL;
638e1051a39Sopenharmony_ci        OPENSSL_clear_free(tkey, tkeylen);
639e1051a39Sopenharmony_ci        tkey = NULL;
640e1051a39Sopenharmony_ci
641e1051a39Sopenharmony_ci        if (out == NULL)
642e1051a39Sopenharmony_ci            out = etmp;
643e1051a39Sopenharmony_ci        else
644e1051a39Sopenharmony_ci            BIO_push(out, etmp);
645e1051a39Sopenharmony_ci        etmp = NULL;
646e1051a39Sopenharmony_ci    }
647e1051a39Sopenharmony_ci    if (in_bio != NULL) {
648e1051a39Sopenharmony_ci        bio = in_bio;
649e1051a39Sopenharmony_ci    } else {
650e1051a39Sopenharmony_ci        if (data_body->length > 0)
651e1051a39Sopenharmony_ci            bio = BIO_new_mem_buf(data_body->data, data_body->length);
652e1051a39Sopenharmony_ci        else {
653e1051a39Sopenharmony_ci            bio = BIO_new(BIO_s_mem());
654e1051a39Sopenharmony_ci            if (bio == NULL)
655e1051a39Sopenharmony_ci                goto err;
656e1051a39Sopenharmony_ci            BIO_set_mem_eof_return(bio, 0);
657e1051a39Sopenharmony_ci        }
658e1051a39Sopenharmony_ci        if (bio == NULL)
659e1051a39Sopenharmony_ci            goto err;
660e1051a39Sopenharmony_ci    }
661e1051a39Sopenharmony_ci    BIO_push(out, bio);
662e1051a39Sopenharmony_ci    bio = NULL;
663e1051a39Sopenharmony_ci    EVP_CIPHER_free(evp_cipher);
664e1051a39Sopenharmony_ci    return out;
665e1051a39Sopenharmony_ci
666e1051a39Sopenharmony_ci err:
667e1051a39Sopenharmony_ci    EVP_CIPHER_free(evp_cipher);
668e1051a39Sopenharmony_ci    OPENSSL_clear_free(ek, eklen);
669e1051a39Sopenharmony_ci    OPENSSL_clear_free(tkey, tkeylen);
670e1051a39Sopenharmony_ci    BIO_free_all(out);
671e1051a39Sopenharmony_ci    BIO_free_all(btmp);
672e1051a39Sopenharmony_ci    BIO_free_all(etmp);
673e1051a39Sopenharmony_ci    BIO_free_all(bio);
674e1051a39Sopenharmony_ci    return NULL;
675e1051a39Sopenharmony_ci}
676e1051a39Sopenharmony_ci
677e1051a39Sopenharmony_cistatic BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid)
678e1051a39Sopenharmony_ci{
679e1051a39Sopenharmony_ci    for (;;) {
680e1051a39Sopenharmony_ci        bio = BIO_find_type(bio, BIO_TYPE_MD);
681e1051a39Sopenharmony_ci        if (bio == NULL) {
682e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
683e1051a39Sopenharmony_ci            return NULL;
684e1051a39Sopenharmony_ci        }
685e1051a39Sopenharmony_ci        BIO_get_md_ctx(bio, pmd);
686e1051a39Sopenharmony_ci        if (*pmd == NULL) {
687e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, ERR_R_INTERNAL_ERROR);
688e1051a39Sopenharmony_ci            return NULL;
689e1051a39Sopenharmony_ci        }
690e1051a39Sopenharmony_ci        if (EVP_MD_CTX_get_type(*pmd) == nid)
691e1051a39Sopenharmony_ci            return bio;
692e1051a39Sopenharmony_ci        bio = BIO_next(bio);
693e1051a39Sopenharmony_ci    }
694e1051a39Sopenharmony_ci    return NULL;
695e1051a39Sopenharmony_ci}
696e1051a39Sopenharmony_ci
697e1051a39Sopenharmony_cistatic int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx)
698e1051a39Sopenharmony_ci{
699e1051a39Sopenharmony_ci    unsigned char md_data[EVP_MAX_MD_SIZE];
700e1051a39Sopenharmony_ci    unsigned int md_len;
701e1051a39Sopenharmony_ci
702e1051a39Sopenharmony_ci    /* Add signing time if not already present */
703e1051a39Sopenharmony_ci    if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) {
704e1051a39Sopenharmony_ci        if (!PKCS7_add0_attrib_signing_time(si, NULL)) {
705e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
706e1051a39Sopenharmony_ci            return 0;
707e1051a39Sopenharmony_ci        }
708e1051a39Sopenharmony_ci    }
709e1051a39Sopenharmony_ci
710e1051a39Sopenharmony_ci    /* Add digest */
711e1051a39Sopenharmony_ci    if (!EVP_DigestFinal_ex(mctx, md_data, &md_len)) {
712e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_EVP_LIB);
713e1051a39Sopenharmony_ci        return 0;
714e1051a39Sopenharmony_ci    }
715e1051a39Sopenharmony_ci    if (!PKCS7_add1_attrib_digest(si, md_data, md_len)) {
716e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
717e1051a39Sopenharmony_ci        return 0;
718e1051a39Sopenharmony_ci    }
719e1051a39Sopenharmony_ci
720e1051a39Sopenharmony_ci    /* Now sign the attributes */
721e1051a39Sopenharmony_ci    if (!PKCS7_SIGNER_INFO_sign(si))
722e1051a39Sopenharmony_ci        return 0;
723e1051a39Sopenharmony_ci
724e1051a39Sopenharmony_ci    return 1;
725e1051a39Sopenharmony_ci}
726e1051a39Sopenharmony_ci
727e1051a39Sopenharmony_ciint PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
728e1051a39Sopenharmony_ci{
729e1051a39Sopenharmony_ci    int ret = 0;
730e1051a39Sopenharmony_ci    int i, j;
731e1051a39Sopenharmony_ci    BIO *btmp;
732e1051a39Sopenharmony_ci    PKCS7_SIGNER_INFO *si;
733e1051a39Sopenharmony_ci    EVP_MD_CTX *mdc, *ctx_tmp;
734e1051a39Sopenharmony_ci    STACK_OF(X509_ATTRIBUTE) *sk;
735e1051a39Sopenharmony_ci    STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
736e1051a39Sopenharmony_ci    ASN1_OCTET_STRING *os = NULL;
737e1051a39Sopenharmony_ci    const PKCS7_CTX *p7_ctx;
738e1051a39Sopenharmony_ci
739e1051a39Sopenharmony_ci    if (p7 == NULL) {
740e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER);
741e1051a39Sopenharmony_ci        return 0;
742e1051a39Sopenharmony_ci    }
743e1051a39Sopenharmony_ci
744e1051a39Sopenharmony_ci    p7_ctx = ossl_pkcs7_get0_ctx(p7);
745e1051a39Sopenharmony_ci
746e1051a39Sopenharmony_ci    if (p7->d.ptr == NULL) {
747e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT);
748e1051a39Sopenharmony_ci        return 0;
749e1051a39Sopenharmony_ci    }
750e1051a39Sopenharmony_ci
751e1051a39Sopenharmony_ci    ctx_tmp = EVP_MD_CTX_new();
752e1051a39Sopenharmony_ci    if (ctx_tmp == NULL) {
753e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
754e1051a39Sopenharmony_ci        return 0;
755e1051a39Sopenharmony_ci    }
756e1051a39Sopenharmony_ci
757e1051a39Sopenharmony_ci    i = OBJ_obj2nid(p7->type);
758e1051a39Sopenharmony_ci    p7->state = PKCS7_S_HEADER;
759e1051a39Sopenharmony_ci
760e1051a39Sopenharmony_ci    switch (i) {
761e1051a39Sopenharmony_ci    case NID_pkcs7_data:
762e1051a39Sopenharmony_ci        os = p7->d.data;
763e1051a39Sopenharmony_ci        break;
764e1051a39Sopenharmony_ci    case NID_pkcs7_signedAndEnveloped:
765e1051a39Sopenharmony_ci        /* XXXXXXXXXXXXXXXX */
766e1051a39Sopenharmony_ci        si_sk = p7->d.signed_and_enveloped->signer_info;
767e1051a39Sopenharmony_ci        os = p7->d.signed_and_enveloped->enc_data->enc_data;
768e1051a39Sopenharmony_ci        if (os == NULL) {
769e1051a39Sopenharmony_ci            os = ASN1_OCTET_STRING_new();
770e1051a39Sopenharmony_ci            if (os == NULL) {
771e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
772e1051a39Sopenharmony_ci                goto err;
773e1051a39Sopenharmony_ci            }
774e1051a39Sopenharmony_ci            p7->d.signed_and_enveloped->enc_data->enc_data = os;
775e1051a39Sopenharmony_ci        }
776e1051a39Sopenharmony_ci        break;
777e1051a39Sopenharmony_ci    case NID_pkcs7_enveloped:
778e1051a39Sopenharmony_ci        /* XXXXXXXXXXXXXXXX */
779e1051a39Sopenharmony_ci        os = p7->d.enveloped->enc_data->enc_data;
780e1051a39Sopenharmony_ci        if (os == NULL) {
781e1051a39Sopenharmony_ci            os = ASN1_OCTET_STRING_new();
782e1051a39Sopenharmony_ci            if (os == NULL) {
783e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
784e1051a39Sopenharmony_ci                goto err;
785e1051a39Sopenharmony_ci            }
786e1051a39Sopenharmony_ci            p7->d.enveloped->enc_data->enc_data = os;
787e1051a39Sopenharmony_ci        }
788e1051a39Sopenharmony_ci        break;
789e1051a39Sopenharmony_ci    case NID_pkcs7_signed:
790e1051a39Sopenharmony_ci        si_sk = p7->d.sign->signer_info;
791e1051a39Sopenharmony_ci        os = PKCS7_get_octet_string(p7->d.sign->contents);
792e1051a39Sopenharmony_ci        /* If detached data then the content is excluded */
793e1051a39Sopenharmony_ci        if (PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) {
794e1051a39Sopenharmony_ci            ASN1_OCTET_STRING_free(os);
795e1051a39Sopenharmony_ci            os = NULL;
796e1051a39Sopenharmony_ci            p7->d.sign->contents->d.data = NULL;
797e1051a39Sopenharmony_ci        }
798e1051a39Sopenharmony_ci        break;
799e1051a39Sopenharmony_ci
800e1051a39Sopenharmony_ci    case NID_pkcs7_digest:
801e1051a39Sopenharmony_ci        os = PKCS7_get_octet_string(p7->d.digest->contents);
802e1051a39Sopenharmony_ci        /* If detached data then the content is excluded */
803e1051a39Sopenharmony_ci        if (PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) {
804e1051a39Sopenharmony_ci            ASN1_OCTET_STRING_free(os);
805e1051a39Sopenharmony_ci            os = NULL;
806e1051a39Sopenharmony_ci            p7->d.digest->contents->d.data = NULL;
807e1051a39Sopenharmony_ci        }
808e1051a39Sopenharmony_ci        break;
809e1051a39Sopenharmony_ci
810e1051a39Sopenharmony_ci    default:
811e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
812e1051a39Sopenharmony_ci        goto err;
813e1051a39Sopenharmony_ci    }
814e1051a39Sopenharmony_ci
815e1051a39Sopenharmony_ci    if (si_sk != NULL) {
816e1051a39Sopenharmony_ci        for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(si_sk); i++) {
817e1051a39Sopenharmony_ci            si = sk_PKCS7_SIGNER_INFO_value(si_sk, i);
818e1051a39Sopenharmony_ci            if (si->pkey == NULL)
819e1051a39Sopenharmony_ci                continue;
820e1051a39Sopenharmony_ci
821e1051a39Sopenharmony_ci            j = OBJ_obj2nid(si->digest_alg->algorithm);
822e1051a39Sopenharmony_ci
823e1051a39Sopenharmony_ci            btmp = bio;
824e1051a39Sopenharmony_ci
825e1051a39Sopenharmony_ci            btmp = PKCS7_find_digest(&mdc, btmp, j);
826e1051a39Sopenharmony_ci
827e1051a39Sopenharmony_ci            if (btmp == NULL)
828e1051a39Sopenharmony_ci                goto err;
829e1051a39Sopenharmony_ci
830e1051a39Sopenharmony_ci            /*
831e1051a39Sopenharmony_ci             * We now have the EVP_MD_CTX, lets do the signing.
832e1051a39Sopenharmony_ci             */
833e1051a39Sopenharmony_ci            if (!EVP_MD_CTX_copy_ex(ctx_tmp, mdc))
834e1051a39Sopenharmony_ci                goto err;
835e1051a39Sopenharmony_ci
836e1051a39Sopenharmony_ci            sk = si->auth_attr;
837e1051a39Sopenharmony_ci
838e1051a39Sopenharmony_ci            /*
839e1051a39Sopenharmony_ci             * If there are attributes, we add the digest attribute and only
840e1051a39Sopenharmony_ci             * sign the attributes
841e1051a39Sopenharmony_ci             */
842e1051a39Sopenharmony_ci            if (sk_X509_ATTRIBUTE_num(sk) > 0) {
843e1051a39Sopenharmony_ci                if (!do_pkcs7_signed_attrib(si, ctx_tmp))
844e1051a39Sopenharmony_ci                    goto err;
845e1051a39Sopenharmony_ci            } else {
846e1051a39Sopenharmony_ci                unsigned char *abuf = NULL;
847e1051a39Sopenharmony_ci                unsigned int abuflen;
848e1051a39Sopenharmony_ci                abuflen = EVP_PKEY_get_size(si->pkey);
849e1051a39Sopenharmony_ci                abuf = OPENSSL_malloc(abuflen);
850e1051a39Sopenharmony_ci                if (abuf == NULL)
851e1051a39Sopenharmony_ci                    goto err;
852e1051a39Sopenharmony_ci
853e1051a39Sopenharmony_ci                if (!EVP_SignFinal_ex(ctx_tmp, abuf, &abuflen, si->pkey,
854e1051a39Sopenharmony_ci                                      ossl_pkcs7_ctx_get0_libctx(p7_ctx),
855e1051a39Sopenharmony_ci                                      ossl_pkcs7_ctx_get0_propq(p7_ctx))) {
856e1051a39Sopenharmony_ci                    OPENSSL_free(abuf);
857e1051a39Sopenharmony_ci                    ERR_raise(ERR_LIB_PKCS7, ERR_R_EVP_LIB);
858e1051a39Sopenharmony_ci                    goto err;
859e1051a39Sopenharmony_ci                }
860e1051a39Sopenharmony_ci                ASN1_STRING_set0(si->enc_digest, abuf, abuflen);
861e1051a39Sopenharmony_ci            }
862e1051a39Sopenharmony_ci        }
863e1051a39Sopenharmony_ci    } else if (i == NID_pkcs7_digest) {
864e1051a39Sopenharmony_ci        unsigned char md_data[EVP_MAX_MD_SIZE];
865e1051a39Sopenharmony_ci        unsigned int md_len;
866e1051a39Sopenharmony_ci        if (!PKCS7_find_digest(&mdc, bio,
867e1051a39Sopenharmony_ci                               OBJ_obj2nid(p7->d.digest->md->algorithm)))
868e1051a39Sopenharmony_ci            goto err;
869e1051a39Sopenharmony_ci        if (!EVP_DigestFinal_ex(mdc, md_data, &md_len))
870e1051a39Sopenharmony_ci            goto err;
871e1051a39Sopenharmony_ci        if (!ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len))
872e1051a39Sopenharmony_ci            goto err;
873e1051a39Sopenharmony_ci    }
874e1051a39Sopenharmony_ci
875e1051a39Sopenharmony_ci    if (!PKCS7_is_detached(p7)) {
876e1051a39Sopenharmony_ci        /*
877e1051a39Sopenharmony_ci         * NOTE(emilia): I think we only reach os == NULL here because detached
878e1051a39Sopenharmony_ci         * digested data support is broken.
879e1051a39Sopenharmony_ci         */
880e1051a39Sopenharmony_ci        if (os == NULL)
881e1051a39Sopenharmony_ci            goto err;
882e1051a39Sopenharmony_ci        if (!(os->flags & ASN1_STRING_FLAG_NDEF)) {
883e1051a39Sopenharmony_ci            char *cont;
884e1051a39Sopenharmony_ci            long contlen;
885e1051a39Sopenharmony_ci            btmp = BIO_find_type(bio, BIO_TYPE_MEM);
886e1051a39Sopenharmony_ci            if (btmp == NULL) {
887e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
888e1051a39Sopenharmony_ci                goto err;
889e1051a39Sopenharmony_ci            }
890e1051a39Sopenharmony_ci            contlen = BIO_get_mem_data(btmp, &cont);
891e1051a39Sopenharmony_ci            /*
892e1051a39Sopenharmony_ci             * Mark the BIO read only then we can use its copy of the data
893e1051a39Sopenharmony_ci             * instead of making an extra copy.
894e1051a39Sopenharmony_ci             */
895e1051a39Sopenharmony_ci            BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
896e1051a39Sopenharmony_ci            BIO_set_mem_eof_return(btmp, 0);
897e1051a39Sopenharmony_ci            ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
898e1051a39Sopenharmony_ci        }
899e1051a39Sopenharmony_ci    }
900e1051a39Sopenharmony_ci    ret = 1;
901e1051a39Sopenharmony_ci err:
902e1051a39Sopenharmony_ci    EVP_MD_CTX_free(ctx_tmp);
903e1051a39Sopenharmony_ci    return ret;
904e1051a39Sopenharmony_ci}
905e1051a39Sopenharmony_ci
906e1051a39Sopenharmony_ciint PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si)
907e1051a39Sopenharmony_ci{
908e1051a39Sopenharmony_ci    EVP_MD_CTX *mctx;
909e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pctx = NULL;
910e1051a39Sopenharmony_ci    unsigned char *abuf = NULL;
911e1051a39Sopenharmony_ci    int alen;
912e1051a39Sopenharmony_ci    size_t siglen;
913e1051a39Sopenharmony_ci    const EVP_MD *md = NULL;
914e1051a39Sopenharmony_ci    const PKCS7_CTX *ctx = si->ctx;
915e1051a39Sopenharmony_ci
916e1051a39Sopenharmony_ci    md = EVP_get_digestbyobj(si->digest_alg->algorithm);
917e1051a39Sopenharmony_ci    if (md == NULL)
918e1051a39Sopenharmony_ci        return 0;
919e1051a39Sopenharmony_ci
920e1051a39Sopenharmony_ci    mctx = EVP_MD_CTX_new();
921e1051a39Sopenharmony_ci    if (mctx == NULL) {
922e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
923e1051a39Sopenharmony_ci        goto err;
924e1051a39Sopenharmony_ci    }
925e1051a39Sopenharmony_ci
926e1051a39Sopenharmony_ci    if (EVP_DigestSignInit_ex(mctx, &pctx, EVP_MD_get0_name(md),
927e1051a39Sopenharmony_ci                              ossl_pkcs7_ctx_get0_libctx(ctx),
928e1051a39Sopenharmony_ci                              ossl_pkcs7_ctx_get0_propq(ctx), si->pkey,
929e1051a39Sopenharmony_ci                              NULL) <= 0)
930e1051a39Sopenharmony_ci        goto err;
931e1051a39Sopenharmony_ci
932e1051a39Sopenharmony_ci    alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr, &abuf,
933e1051a39Sopenharmony_ci                         ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
934e1051a39Sopenharmony_ci    if (!abuf)
935e1051a39Sopenharmony_ci        goto err;
936e1051a39Sopenharmony_ci    if (EVP_DigestSignUpdate(mctx, abuf, alen) <= 0)
937e1051a39Sopenharmony_ci        goto err;
938e1051a39Sopenharmony_ci    OPENSSL_free(abuf);
939e1051a39Sopenharmony_ci    abuf = NULL;
940e1051a39Sopenharmony_ci    if (EVP_DigestSignFinal(mctx, NULL, &siglen) <= 0)
941e1051a39Sopenharmony_ci        goto err;
942e1051a39Sopenharmony_ci    abuf = OPENSSL_malloc(siglen);
943e1051a39Sopenharmony_ci    if (abuf == NULL)
944e1051a39Sopenharmony_ci        goto err;
945e1051a39Sopenharmony_ci    if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0)
946e1051a39Sopenharmony_ci        goto err;
947e1051a39Sopenharmony_ci
948e1051a39Sopenharmony_ci    EVP_MD_CTX_free(mctx);
949e1051a39Sopenharmony_ci
950e1051a39Sopenharmony_ci    ASN1_STRING_set0(si->enc_digest, abuf, siglen);
951e1051a39Sopenharmony_ci
952e1051a39Sopenharmony_ci    return 1;
953e1051a39Sopenharmony_ci
954e1051a39Sopenharmony_ci err:
955e1051a39Sopenharmony_ci    OPENSSL_free(abuf);
956e1051a39Sopenharmony_ci    EVP_MD_CTX_free(mctx);
957e1051a39Sopenharmony_ci    return 0;
958e1051a39Sopenharmony_ci}
959e1051a39Sopenharmony_ci
960e1051a39Sopenharmony_ciint PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
961e1051a39Sopenharmony_ci                     PKCS7 *p7, PKCS7_SIGNER_INFO *si)
962e1051a39Sopenharmony_ci{
963e1051a39Sopenharmony_ci    PKCS7_ISSUER_AND_SERIAL *ias;
964e1051a39Sopenharmony_ci    int ret = 0, i;
965e1051a39Sopenharmony_ci    STACK_OF(X509) *cert;
966e1051a39Sopenharmony_ci    X509 *x509;
967e1051a39Sopenharmony_ci
968e1051a39Sopenharmony_ci    if (p7 == NULL) {
969e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER);
970e1051a39Sopenharmony_ci        return 0;
971e1051a39Sopenharmony_ci    }
972e1051a39Sopenharmony_ci
973e1051a39Sopenharmony_ci    if (p7->d.ptr == NULL) {
974e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT);
975e1051a39Sopenharmony_ci        return 0;
976e1051a39Sopenharmony_ci    }
977e1051a39Sopenharmony_ci
978e1051a39Sopenharmony_ci    if (PKCS7_type_is_signed(p7)) {
979e1051a39Sopenharmony_ci        cert = p7->d.sign->cert;
980e1051a39Sopenharmony_ci    } else if (PKCS7_type_is_signedAndEnveloped(p7)) {
981e1051a39Sopenharmony_ci        cert = p7->d.signed_and_enveloped->cert;
982e1051a39Sopenharmony_ci    } else {
983e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_PKCS7_TYPE);
984e1051a39Sopenharmony_ci        goto err;
985e1051a39Sopenharmony_ci    }
986e1051a39Sopenharmony_ci    /* XXXXXXXXXXXXXXXXXXXXXXX */
987e1051a39Sopenharmony_ci    ias = si->issuer_and_serial;
988e1051a39Sopenharmony_ci
989e1051a39Sopenharmony_ci    x509 = X509_find_by_issuer_and_serial(cert, ias->issuer, ias->serial);
990e1051a39Sopenharmony_ci
991e1051a39Sopenharmony_ci    /* were we able to find the cert in passed to us */
992e1051a39Sopenharmony_ci    if (x509 == NULL) {
993e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_CERTIFICATE);
994e1051a39Sopenharmony_ci        goto err;
995e1051a39Sopenharmony_ci    }
996e1051a39Sopenharmony_ci
997e1051a39Sopenharmony_ci    /* Lets verify */
998e1051a39Sopenharmony_ci    if (!X509_STORE_CTX_init(ctx, cert_store, x509, cert)) {
999e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB);
1000e1051a39Sopenharmony_ci        goto err;
1001e1051a39Sopenharmony_ci    }
1002e1051a39Sopenharmony_ci    X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN);
1003e1051a39Sopenharmony_ci    i = X509_verify_cert(ctx);
1004e1051a39Sopenharmony_ci    if (i <= 0) {
1005e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB);
1006e1051a39Sopenharmony_ci        goto err;
1007e1051a39Sopenharmony_ci    }
1008e1051a39Sopenharmony_ci
1009e1051a39Sopenharmony_ci    return PKCS7_signatureVerify(bio, p7, si, x509);
1010e1051a39Sopenharmony_ci err:
1011e1051a39Sopenharmony_ci    return ret;
1012e1051a39Sopenharmony_ci}
1013e1051a39Sopenharmony_ci
1014e1051a39Sopenharmony_ciint PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
1015e1051a39Sopenharmony_ci                          X509 *x509)
1016e1051a39Sopenharmony_ci{
1017e1051a39Sopenharmony_ci    ASN1_OCTET_STRING *os;
1018e1051a39Sopenharmony_ci    EVP_MD_CTX *mdc_tmp, *mdc;
1019e1051a39Sopenharmony_ci    const EVP_MD *md;
1020e1051a39Sopenharmony_ci    EVP_MD *fetched_md = NULL;
1021e1051a39Sopenharmony_ci    int ret = 0, i;
1022e1051a39Sopenharmony_ci    int md_type;
1023e1051a39Sopenharmony_ci    STACK_OF(X509_ATTRIBUTE) *sk;
1024e1051a39Sopenharmony_ci    BIO *btmp;
1025e1051a39Sopenharmony_ci    EVP_PKEY *pkey;
1026e1051a39Sopenharmony_ci    unsigned char *abuf = NULL;
1027e1051a39Sopenharmony_ci    const PKCS7_CTX *ctx = ossl_pkcs7_get0_ctx(p7);
1028e1051a39Sopenharmony_ci    OSSL_LIB_CTX *libctx = ossl_pkcs7_ctx_get0_libctx(ctx);
1029e1051a39Sopenharmony_ci    const char *propq = ossl_pkcs7_ctx_get0_propq(ctx);
1030e1051a39Sopenharmony_ci
1031e1051a39Sopenharmony_ci    mdc_tmp = EVP_MD_CTX_new();
1032e1051a39Sopenharmony_ci    if (mdc_tmp == NULL) {
1033e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, ERR_R_MALLOC_FAILURE);
1034e1051a39Sopenharmony_ci        goto err;
1035e1051a39Sopenharmony_ci    }
1036e1051a39Sopenharmony_ci
1037e1051a39Sopenharmony_ci    if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) {
1038e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_PKCS7_TYPE);
1039e1051a39Sopenharmony_ci        goto err;
1040e1051a39Sopenharmony_ci    }
1041e1051a39Sopenharmony_ci
1042e1051a39Sopenharmony_ci    md_type = OBJ_obj2nid(si->digest_alg->algorithm);
1043e1051a39Sopenharmony_ci
1044e1051a39Sopenharmony_ci    btmp = bio;
1045e1051a39Sopenharmony_ci    for (;;) {
1046e1051a39Sopenharmony_ci        if ((btmp == NULL) ||
1047e1051a39Sopenharmony_ci            ((btmp = BIO_find_type(btmp, BIO_TYPE_MD)) == NULL)) {
1048e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
1049e1051a39Sopenharmony_ci            goto err;
1050e1051a39Sopenharmony_ci        }
1051e1051a39Sopenharmony_ci        BIO_get_md_ctx(btmp, &mdc);
1052e1051a39Sopenharmony_ci        if (mdc == NULL) {
1053e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, ERR_R_INTERNAL_ERROR);
1054e1051a39Sopenharmony_ci            goto err;
1055e1051a39Sopenharmony_ci        }
1056e1051a39Sopenharmony_ci        if (EVP_MD_CTX_get_type(mdc) == md_type)
1057e1051a39Sopenharmony_ci            break;
1058e1051a39Sopenharmony_ci        /*
1059e1051a39Sopenharmony_ci         * Workaround for some broken clients that put the signature OID
1060e1051a39Sopenharmony_ci         * instead of the digest OID in digest_alg->algorithm
1061e1051a39Sopenharmony_ci         */
1062e1051a39Sopenharmony_ci        if (EVP_MD_get_pkey_type(EVP_MD_CTX_get0_md(mdc)) == md_type)
1063e1051a39Sopenharmony_ci            break;
1064e1051a39Sopenharmony_ci        btmp = BIO_next(btmp);
1065e1051a39Sopenharmony_ci    }
1066e1051a39Sopenharmony_ci
1067e1051a39Sopenharmony_ci    /*
1068e1051a39Sopenharmony_ci     * mdc is the digest ctx that we want, unless there are attributes, in
1069e1051a39Sopenharmony_ci     * which case the digest is the signed attributes
1070e1051a39Sopenharmony_ci     */
1071e1051a39Sopenharmony_ci    if (!EVP_MD_CTX_copy_ex(mdc_tmp, mdc))
1072e1051a39Sopenharmony_ci        goto err;
1073e1051a39Sopenharmony_ci
1074e1051a39Sopenharmony_ci    sk = si->auth_attr;
1075e1051a39Sopenharmony_ci    if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) {
1076e1051a39Sopenharmony_ci        unsigned char md_dat[EVP_MAX_MD_SIZE];
1077e1051a39Sopenharmony_ci        unsigned int md_len;
1078e1051a39Sopenharmony_ci        int alen;
1079e1051a39Sopenharmony_ci        ASN1_OCTET_STRING *message_digest;
1080e1051a39Sopenharmony_ci
1081e1051a39Sopenharmony_ci        if (!EVP_DigestFinal_ex(mdc_tmp, md_dat, &md_len))
1082e1051a39Sopenharmony_ci            goto err;
1083e1051a39Sopenharmony_ci        message_digest = PKCS7_digest_from_attributes(sk);
1084e1051a39Sopenharmony_ci        if (!message_digest) {
1085e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
1086e1051a39Sopenharmony_ci            goto err;
1087e1051a39Sopenharmony_ci        }
1088e1051a39Sopenharmony_ci        if ((message_digest->length != (int)md_len) ||
1089e1051a39Sopenharmony_ci            (memcmp(message_digest->data, md_dat, md_len))) {
1090e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, PKCS7_R_DIGEST_FAILURE);
1091e1051a39Sopenharmony_ci            ret = -1;
1092e1051a39Sopenharmony_ci            goto err;
1093e1051a39Sopenharmony_ci        }
1094e1051a39Sopenharmony_ci
1095e1051a39Sopenharmony_ci        (void)ERR_set_mark();
1096e1051a39Sopenharmony_ci        fetched_md = EVP_MD_fetch(libctx, OBJ_nid2sn(md_type), propq);
1097e1051a39Sopenharmony_ci
1098e1051a39Sopenharmony_ci        if (fetched_md != NULL)
1099e1051a39Sopenharmony_ci            md = fetched_md;
1100e1051a39Sopenharmony_ci        else
1101e1051a39Sopenharmony_ci            md = EVP_get_digestbynid(md_type);
1102e1051a39Sopenharmony_ci
1103e1051a39Sopenharmony_ci        if (md == NULL || !EVP_VerifyInit_ex(mdc_tmp, md, NULL)) {
1104e1051a39Sopenharmony_ci            (void)ERR_clear_last_mark();
1105e1051a39Sopenharmony_ci            goto err;
1106e1051a39Sopenharmony_ci        }
1107e1051a39Sopenharmony_ci        (void)ERR_pop_to_mark();
1108e1051a39Sopenharmony_ci
1109e1051a39Sopenharmony_ci        alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
1110e1051a39Sopenharmony_ci                             ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
1111e1051a39Sopenharmony_ci        if (alen <= 0) {
1112e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PKCS7, ERR_R_ASN1_LIB);
1113e1051a39Sopenharmony_ci            ret = -1;
1114e1051a39Sopenharmony_ci            goto err;
1115e1051a39Sopenharmony_ci        }
1116e1051a39Sopenharmony_ci        if (!EVP_VerifyUpdate(mdc_tmp, abuf, alen))
1117e1051a39Sopenharmony_ci            goto err;
1118e1051a39Sopenharmony_ci    }
1119e1051a39Sopenharmony_ci
1120e1051a39Sopenharmony_ci    os = si->enc_digest;
1121e1051a39Sopenharmony_ci    pkey = X509_get0_pubkey(x509);
1122e1051a39Sopenharmony_ci    if (pkey == NULL) {
1123e1051a39Sopenharmony_ci        ret = -1;
1124e1051a39Sopenharmony_ci        goto err;
1125e1051a39Sopenharmony_ci    }
1126e1051a39Sopenharmony_ci
1127e1051a39Sopenharmony_ci    i = EVP_VerifyFinal_ex(mdc_tmp, os->data, os->length, pkey, libctx, propq);
1128e1051a39Sopenharmony_ci    if (i <= 0) {
1129e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SIGNATURE_FAILURE);
1130e1051a39Sopenharmony_ci        ret = -1;
1131e1051a39Sopenharmony_ci        goto err;
1132e1051a39Sopenharmony_ci    }
1133e1051a39Sopenharmony_ci    ret = 1;
1134e1051a39Sopenharmony_ci err:
1135e1051a39Sopenharmony_ci    OPENSSL_free(abuf);
1136e1051a39Sopenharmony_ci    EVP_MD_CTX_free(mdc_tmp);
1137e1051a39Sopenharmony_ci    EVP_MD_free(fetched_md);
1138e1051a39Sopenharmony_ci    return ret;
1139e1051a39Sopenharmony_ci}
1140e1051a39Sopenharmony_ci
1141e1051a39Sopenharmony_ciPKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx)
1142e1051a39Sopenharmony_ci{
1143e1051a39Sopenharmony_ci    STACK_OF(PKCS7_RECIP_INFO) *rsk;
1144e1051a39Sopenharmony_ci    PKCS7_RECIP_INFO *ri;
1145e1051a39Sopenharmony_ci    int i;
1146e1051a39Sopenharmony_ci
1147e1051a39Sopenharmony_ci    i = OBJ_obj2nid(p7->type);
1148e1051a39Sopenharmony_ci    if (i != NID_pkcs7_signedAndEnveloped)
1149e1051a39Sopenharmony_ci        return NULL;
1150e1051a39Sopenharmony_ci    if (p7->d.signed_and_enveloped == NULL)
1151e1051a39Sopenharmony_ci        return NULL;
1152e1051a39Sopenharmony_ci    rsk = p7->d.signed_and_enveloped->recipientinfo;
1153e1051a39Sopenharmony_ci    if (rsk == NULL)
1154e1051a39Sopenharmony_ci        return NULL;
1155e1051a39Sopenharmony_ci    if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx)
1156e1051a39Sopenharmony_ci        return NULL;
1157e1051a39Sopenharmony_ci    ri = sk_PKCS7_RECIP_INFO_value(rsk, idx);
1158e1051a39Sopenharmony_ci    return ri->issuer_and_serial;
1159e1051a39Sopenharmony_ci}
1160e1051a39Sopenharmony_ci
1161e1051a39Sopenharmony_ciASN1_TYPE *PKCS7_get_signed_attribute(const PKCS7_SIGNER_INFO *si, int nid)
1162e1051a39Sopenharmony_ci{
1163e1051a39Sopenharmony_ci    return get_attribute(si->auth_attr, nid);
1164e1051a39Sopenharmony_ci}
1165e1051a39Sopenharmony_ci
1166e1051a39Sopenharmony_ciASN1_TYPE *PKCS7_get_attribute(const PKCS7_SIGNER_INFO *si, int nid)
1167e1051a39Sopenharmony_ci{
1168e1051a39Sopenharmony_ci    return get_attribute(si->unauth_attr, nid);
1169e1051a39Sopenharmony_ci}
1170e1051a39Sopenharmony_ci
1171e1051a39Sopenharmony_cistatic ASN1_TYPE *get_attribute(const STACK_OF(X509_ATTRIBUTE) *sk, int nid)
1172e1051a39Sopenharmony_ci{
1173e1051a39Sopenharmony_ci    int idx;
1174e1051a39Sopenharmony_ci    X509_ATTRIBUTE *xa;
1175e1051a39Sopenharmony_ci    idx = X509at_get_attr_by_NID(sk, nid, -1);
1176e1051a39Sopenharmony_ci    xa = X509at_get_attr(sk, idx);
1177e1051a39Sopenharmony_ci    return X509_ATTRIBUTE_get0_type(xa, 0);
1178e1051a39Sopenharmony_ci}
1179e1051a39Sopenharmony_ci
1180e1051a39Sopenharmony_ciASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk)
1181e1051a39Sopenharmony_ci{
1182e1051a39Sopenharmony_ci    ASN1_TYPE *astype;
1183e1051a39Sopenharmony_ci    if ((astype = get_attribute(sk, NID_pkcs9_messageDigest)) == NULL)
1184e1051a39Sopenharmony_ci        return NULL;
1185e1051a39Sopenharmony_ci    return astype->value.octet_string;
1186e1051a39Sopenharmony_ci}
1187e1051a39Sopenharmony_ci
1188e1051a39Sopenharmony_ciint PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
1189e1051a39Sopenharmony_ci                                STACK_OF(X509_ATTRIBUTE) *sk)
1190e1051a39Sopenharmony_ci{
1191e1051a39Sopenharmony_ci    int i;
1192e1051a39Sopenharmony_ci
1193e1051a39Sopenharmony_ci    sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr, X509_ATTRIBUTE_free);
1194e1051a39Sopenharmony_ci    p7si->auth_attr = sk_X509_ATTRIBUTE_dup(sk);
1195e1051a39Sopenharmony_ci    if (p7si->auth_attr == NULL)
1196e1051a39Sopenharmony_ci        return 0;
1197e1051a39Sopenharmony_ci    for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
1198e1051a39Sopenharmony_ci        if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr, i,
1199e1051a39Sopenharmony_ci                                   X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value
1200e1051a39Sopenharmony_ci                                                      (sk, i))))
1201e1051a39Sopenharmony_ci            == NULL)
1202e1051a39Sopenharmony_ci            return 0;
1203e1051a39Sopenharmony_ci    }
1204e1051a39Sopenharmony_ci    return 1;
1205e1051a39Sopenharmony_ci}
1206e1051a39Sopenharmony_ci
1207e1051a39Sopenharmony_ciint PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,
1208e1051a39Sopenharmony_ci                         STACK_OF(X509_ATTRIBUTE) *sk)
1209e1051a39Sopenharmony_ci{
1210e1051a39Sopenharmony_ci    int i;
1211e1051a39Sopenharmony_ci
1212e1051a39Sopenharmony_ci    sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, X509_ATTRIBUTE_free);
1213e1051a39Sopenharmony_ci    p7si->unauth_attr = sk_X509_ATTRIBUTE_dup(sk);
1214e1051a39Sopenharmony_ci    if (p7si->unauth_attr == NULL)
1215e1051a39Sopenharmony_ci        return 0;
1216e1051a39Sopenharmony_ci    for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
1217e1051a39Sopenharmony_ci        if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr, i,
1218e1051a39Sopenharmony_ci                                   X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value
1219e1051a39Sopenharmony_ci                                                      (sk, i))))
1220e1051a39Sopenharmony_ci            == NULL)
1221e1051a39Sopenharmony_ci            return 0;
1222e1051a39Sopenharmony_ci    }
1223e1051a39Sopenharmony_ci    return 1;
1224e1051a39Sopenharmony_ci}
1225e1051a39Sopenharmony_ci
1226e1051a39Sopenharmony_ciint PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
1227e1051a39Sopenharmony_ci                               void *value)
1228e1051a39Sopenharmony_ci{
1229e1051a39Sopenharmony_ci    return add_attribute(&(p7si->auth_attr), nid, atrtype, value);
1230e1051a39Sopenharmony_ci}
1231e1051a39Sopenharmony_ci
1232e1051a39Sopenharmony_ciint PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
1233e1051a39Sopenharmony_ci                        void *value)
1234e1051a39Sopenharmony_ci{
1235e1051a39Sopenharmony_ci    return add_attribute(&(p7si->unauth_attr), nid, atrtype, value);
1236e1051a39Sopenharmony_ci}
1237e1051a39Sopenharmony_ci
1238e1051a39Sopenharmony_cistatic int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
1239e1051a39Sopenharmony_ci                         void *value)
1240e1051a39Sopenharmony_ci{
1241e1051a39Sopenharmony_ci    X509_ATTRIBUTE *attr = NULL;
1242e1051a39Sopenharmony_ci
1243e1051a39Sopenharmony_ci    if (*sk == NULL) {
1244e1051a39Sopenharmony_ci        if ((*sk = sk_X509_ATTRIBUTE_new_null()) == NULL)
1245e1051a39Sopenharmony_ci            return 0;
1246e1051a39Sopenharmony_ci new_attrib:
1247e1051a39Sopenharmony_ci        if ((attr = X509_ATTRIBUTE_create(nid, atrtype, value)) == NULL)
1248e1051a39Sopenharmony_ci            return 0;
1249e1051a39Sopenharmony_ci        if (!sk_X509_ATTRIBUTE_push(*sk, attr)) {
1250e1051a39Sopenharmony_ci            X509_ATTRIBUTE_free(attr);
1251e1051a39Sopenharmony_ci            return 0;
1252e1051a39Sopenharmony_ci        }
1253e1051a39Sopenharmony_ci    } else {
1254e1051a39Sopenharmony_ci        int i;
1255e1051a39Sopenharmony_ci
1256e1051a39Sopenharmony_ci        for (i = 0; i < sk_X509_ATTRIBUTE_num(*sk); i++) {
1257e1051a39Sopenharmony_ci            attr = sk_X509_ATTRIBUTE_value(*sk, i);
1258e1051a39Sopenharmony_ci            if (OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)) == nid) {
1259e1051a39Sopenharmony_ci                X509_ATTRIBUTE_free(attr);
1260e1051a39Sopenharmony_ci                attr = X509_ATTRIBUTE_create(nid, atrtype, value);
1261e1051a39Sopenharmony_ci                if (attr == NULL)
1262e1051a39Sopenharmony_ci                    return 0;
1263e1051a39Sopenharmony_ci                if (!sk_X509_ATTRIBUTE_set(*sk, i, attr)) {
1264e1051a39Sopenharmony_ci                    X509_ATTRIBUTE_free(attr);
1265e1051a39Sopenharmony_ci                    return 0;
1266e1051a39Sopenharmony_ci                }
1267e1051a39Sopenharmony_ci                goto end;
1268e1051a39Sopenharmony_ci            }
1269e1051a39Sopenharmony_ci        }
1270e1051a39Sopenharmony_ci        goto new_attrib;
1271e1051a39Sopenharmony_ci    }
1272e1051a39Sopenharmony_ci end:
1273e1051a39Sopenharmony_ci    return 1;
1274e1051a39Sopenharmony_ci}
1275