1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2008-2022 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/pem.h>
13e1051a39Sopenharmony_ci#include <openssl/x509v3.h>
14e1051a39Sopenharmony_ci#include <openssl/err.h>
15e1051a39Sopenharmony_ci#include <openssl/cms.h>
16e1051a39Sopenharmony_ci#include <openssl/rand.h>
17e1051a39Sopenharmony_ci#include "crypto/evp.h"
18e1051a39Sopenharmony_ci#include "cms_local.h"
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ci/* CMS EncryptedData Utilities */
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ci/* Return BIO based on EncryptedContentInfo and key */
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ciBIO *ossl_cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
25e1051a39Sopenharmony_ci                                        const CMS_CTX *cms_ctx)
26e1051a39Sopenharmony_ci{
27e1051a39Sopenharmony_ci    BIO *b;
28e1051a39Sopenharmony_ci    EVP_CIPHER_CTX *ctx;
29e1051a39Sopenharmony_ci    EVP_CIPHER *fetched_ciph = NULL;
30e1051a39Sopenharmony_ci    const EVP_CIPHER *cipher = NULL;
31e1051a39Sopenharmony_ci    X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
32e1051a39Sopenharmony_ci    evp_cipher_aead_asn1_params aparams;
33e1051a39Sopenharmony_ci    unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
34e1051a39Sopenharmony_ci    unsigned char *tkey = NULL;
35e1051a39Sopenharmony_ci    int len;
36e1051a39Sopenharmony_ci    int ivlen = 0;
37e1051a39Sopenharmony_ci    size_t tkeylen = 0;
38e1051a39Sopenharmony_ci    int ok = 0;
39e1051a39Sopenharmony_ci    int enc, keep_key = 0;
40e1051a39Sopenharmony_ci    OSSL_LIB_CTX *libctx = ossl_cms_ctx_get0_libctx(cms_ctx);
41e1051a39Sopenharmony_ci    const char *propq = ossl_cms_ctx_get0_propq(cms_ctx);
42e1051a39Sopenharmony_ci
43e1051a39Sopenharmony_ci    enc = ec->cipher ? 1 : 0;
44e1051a39Sopenharmony_ci
45e1051a39Sopenharmony_ci    b = BIO_new(BIO_f_cipher());
46e1051a39Sopenharmony_ci    if (b == NULL) {
47e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
48e1051a39Sopenharmony_ci        return NULL;
49e1051a39Sopenharmony_ci    }
50e1051a39Sopenharmony_ci
51e1051a39Sopenharmony_ci    BIO_get_cipher_ctx(b, &ctx);
52e1051a39Sopenharmony_ci
53e1051a39Sopenharmony_ci    (void)ERR_set_mark();
54e1051a39Sopenharmony_ci    if (enc) {
55e1051a39Sopenharmony_ci        cipher = ec->cipher;
56e1051a39Sopenharmony_ci        /*
57e1051a39Sopenharmony_ci         * If not keeping key set cipher to NULL so subsequent calls decrypt.
58e1051a39Sopenharmony_ci         */
59e1051a39Sopenharmony_ci        if (ec->key != NULL)
60e1051a39Sopenharmony_ci            ec->cipher = NULL;
61e1051a39Sopenharmony_ci    } else {
62e1051a39Sopenharmony_ci        cipher = EVP_get_cipherbyobj(calg->algorithm);
63e1051a39Sopenharmony_ci    }
64e1051a39Sopenharmony_ci    if (cipher != NULL) {
65e1051a39Sopenharmony_ci        fetched_ciph = EVP_CIPHER_fetch(libctx, EVP_CIPHER_get0_name(cipher),
66e1051a39Sopenharmony_ci                                        propq);
67e1051a39Sopenharmony_ci        if (fetched_ciph != NULL)
68e1051a39Sopenharmony_ci            cipher = fetched_ciph;
69e1051a39Sopenharmony_ci    }
70e1051a39Sopenharmony_ci    if (cipher == NULL) {
71e1051a39Sopenharmony_ci        (void)ERR_clear_last_mark();
72e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER);
73e1051a39Sopenharmony_ci        goto err;
74e1051a39Sopenharmony_ci    }
75e1051a39Sopenharmony_ci    (void)ERR_pop_to_mark();
76e1051a39Sopenharmony_ci
77e1051a39Sopenharmony_ci    if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc) <= 0) {
78e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR);
79e1051a39Sopenharmony_ci        goto err;
80e1051a39Sopenharmony_ci    }
81e1051a39Sopenharmony_ci
82e1051a39Sopenharmony_ci    if (enc) {
83e1051a39Sopenharmony_ci        calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_get_type(ctx));
84e1051a39Sopenharmony_ci        if (calg->algorithm == NULL) {
85e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM);
86e1051a39Sopenharmony_ci            goto err;
87e1051a39Sopenharmony_ci        }
88e1051a39Sopenharmony_ci        /* Generate a random IV if we need one */
89e1051a39Sopenharmony_ci        ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);
90e1051a39Sopenharmony_ci        if (ivlen < 0) {
91e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
92e1051a39Sopenharmony_ci            goto err;
93e1051a39Sopenharmony_ci        }
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_ci        if (ivlen > 0) {
96e1051a39Sopenharmony_ci            if (RAND_bytes_ex(libctx, iv, ivlen, 0) <= 0)
97e1051a39Sopenharmony_ci                goto err;
98e1051a39Sopenharmony_ci            piv = iv;
99e1051a39Sopenharmony_ci        }
100e1051a39Sopenharmony_ci    } else {
101e1051a39Sopenharmony_ci        if (evp_cipher_asn1_to_param_ex(ctx, calg->parameter, &aparams) <= 0) {
102e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
103e1051a39Sopenharmony_ci            goto err;
104e1051a39Sopenharmony_ci        }
105e1051a39Sopenharmony_ci        if ((EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) {
106e1051a39Sopenharmony_ci            piv = aparams.iv;
107e1051a39Sopenharmony_ci            if (ec->taglen > 0
108e1051a39Sopenharmony_ci                    && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
109e1051a39Sopenharmony_ci                                           ec->taglen, ec->tag) <= 0) {
110e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_AEAD_SET_TAG_ERROR);
111e1051a39Sopenharmony_ci                goto err;
112e1051a39Sopenharmony_ci            }
113e1051a39Sopenharmony_ci        }
114e1051a39Sopenharmony_ci    }
115e1051a39Sopenharmony_ci    len = EVP_CIPHER_CTX_get_key_length(ctx);
116e1051a39Sopenharmony_ci    if (len <= 0)
117e1051a39Sopenharmony_ci        goto err;
118e1051a39Sopenharmony_ci    tkeylen = (size_t)len;
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_ci    /* Generate random session key */
121e1051a39Sopenharmony_ci    if (!enc || !ec->key) {
122e1051a39Sopenharmony_ci        tkey = OPENSSL_malloc(tkeylen);
123e1051a39Sopenharmony_ci        if (tkey == NULL) {
124e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
125e1051a39Sopenharmony_ci            goto err;
126e1051a39Sopenharmony_ci        }
127e1051a39Sopenharmony_ci        if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
128e1051a39Sopenharmony_ci            goto err;
129e1051a39Sopenharmony_ci    }
130e1051a39Sopenharmony_ci
131e1051a39Sopenharmony_ci    if (!ec->key) {
132e1051a39Sopenharmony_ci        ec->key = tkey;
133e1051a39Sopenharmony_ci        ec->keylen = tkeylen;
134e1051a39Sopenharmony_ci        tkey = NULL;
135e1051a39Sopenharmony_ci        if (enc)
136e1051a39Sopenharmony_ci            keep_key = 1;
137e1051a39Sopenharmony_ci        else
138e1051a39Sopenharmony_ci            ERR_clear_error();
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci    }
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_ci    if (ec->keylen != tkeylen) {
143e1051a39Sopenharmony_ci        /* If necessary set key length */
144e1051a39Sopenharmony_ci        if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) {
145e1051a39Sopenharmony_ci            /*
146e1051a39Sopenharmony_ci             * Only reveal failure if debugging so we don't leak information
147e1051a39Sopenharmony_ci             * which may be useful in MMA.
148e1051a39Sopenharmony_ci             */
149e1051a39Sopenharmony_ci            if (enc || ec->debug) {
150e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH);
151e1051a39Sopenharmony_ci                goto err;
152e1051a39Sopenharmony_ci            } else {
153e1051a39Sopenharmony_ci                /* Use random key */
154e1051a39Sopenharmony_ci                OPENSSL_clear_free(ec->key, ec->keylen);
155e1051a39Sopenharmony_ci                ec->key = tkey;
156e1051a39Sopenharmony_ci                ec->keylen = tkeylen;
157e1051a39Sopenharmony_ci                tkey = NULL;
158e1051a39Sopenharmony_ci                ERR_clear_error();
159e1051a39Sopenharmony_ci            }
160e1051a39Sopenharmony_ci        }
161e1051a39Sopenharmony_ci    }
162e1051a39Sopenharmony_ci
163e1051a39Sopenharmony_ci    if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
164e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR);
165e1051a39Sopenharmony_ci        goto err;
166e1051a39Sopenharmony_ci    }
167e1051a39Sopenharmony_ci    if (enc) {
168e1051a39Sopenharmony_ci        calg->parameter = ASN1_TYPE_new();
169e1051a39Sopenharmony_ci        if (calg->parameter == NULL) {
170e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
171e1051a39Sopenharmony_ci            goto err;
172e1051a39Sopenharmony_ci        }
173e1051a39Sopenharmony_ci        if ((EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) {
174e1051a39Sopenharmony_ci            memcpy(aparams.iv, piv, ivlen);
175e1051a39Sopenharmony_ci            aparams.iv_len = ivlen;
176e1051a39Sopenharmony_ci            aparams.tag_len = EVP_CIPHER_CTX_get_tag_length(ctx);
177e1051a39Sopenharmony_ci            if (aparams.tag_len <= 0)
178e1051a39Sopenharmony_ci                goto err;
179e1051a39Sopenharmony_ci        }
180e1051a39Sopenharmony_ci
181e1051a39Sopenharmony_ci        if (evp_cipher_param_to_asn1_ex(ctx, calg->parameter, &aparams) <= 0) {
182e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
183e1051a39Sopenharmony_ci            goto err;
184e1051a39Sopenharmony_ci        }
185e1051a39Sopenharmony_ci        /* If parameter type not set omit parameter */
186e1051a39Sopenharmony_ci        if (calg->parameter->type == V_ASN1_UNDEF) {
187e1051a39Sopenharmony_ci            ASN1_TYPE_free(calg->parameter);
188e1051a39Sopenharmony_ci            calg->parameter = NULL;
189e1051a39Sopenharmony_ci        }
190e1051a39Sopenharmony_ci    }
191e1051a39Sopenharmony_ci    ok = 1;
192e1051a39Sopenharmony_ci
193e1051a39Sopenharmony_ci err:
194e1051a39Sopenharmony_ci    EVP_CIPHER_free(fetched_ciph);
195e1051a39Sopenharmony_ci    if (!keep_key || !ok) {
196e1051a39Sopenharmony_ci        OPENSSL_clear_free(ec->key, ec->keylen);
197e1051a39Sopenharmony_ci        ec->key = NULL;
198e1051a39Sopenharmony_ci    }
199e1051a39Sopenharmony_ci    OPENSSL_clear_free(tkey, tkeylen);
200e1051a39Sopenharmony_ci    if (ok)
201e1051a39Sopenharmony_ci        return b;
202e1051a39Sopenharmony_ci    BIO_free(b);
203e1051a39Sopenharmony_ci    return NULL;
204e1051a39Sopenharmony_ci}
205e1051a39Sopenharmony_ci
206e1051a39Sopenharmony_ciint ossl_cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
207e1051a39Sopenharmony_ci                                   const EVP_CIPHER *cipher,
208e1051a39Sopenharmony_ci                                   const unsigned char *key, size_t keylen,
209e1051a39Sopenharmony_ci                                   const CMS_CTX *cms_ctx)
210e1051a39Sopenharmony_ci{
211e1051a39Sopenharmony_ci    ec->cipher = cipher;
212e1051a39Sopenharmony_ci    if (key) {
213e1051a39Sopenharmony_ci        if ((ec->key = OPENSSL_malloc(keylen)) == NULL) {
214e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
215e1051a39Sopenharmony_ci            return 0;
216e1051a39Sopenharmony_ci        }
217e1051a39Sopenharmony_ci        memcpy(ec->key, key, keylen);
218e1051a39Sopenharmony_ci    }
219e1051a39Sopenharmony_ci    ec->keylen = keylen;
220e1051a39Sopenharmony_ci    if (cipher != NULL)
221e1051a39Sopenharmony_ci        ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
222e1051a39Sopenharmony_ci    return 1;
223e1051a39Sopenharmony_ci}
224e1051a39Sopenharmony_ci
225e1051a39Sopenharmony_ciint CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
226e1051a39Sopenharmony_ci                               const unsigned char *key, size_t keylen)
227e1051a39Sopenharmony_ci{
228e1051a39Sopenharmony_ci    CMS_EncryptedContentInfo *ec;
229e1051a39Sopenharmony_ci
230e1051a39Sopenharmony_ci    if (!key || !keylen) {
231e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_NO_KEY);
232e1051a39Sopenharmony_ci        return 0;
233e1051a39Sopenharmony_ci    }
234e1051a39Sopenharmony_ci    if (ciph) {
235e1051a39Sopenharmony_ci        cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData);
236e1051a39Sopenharmony_ci        if (!cms->d.encryptedData) {
237e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
238e1051a39Sopenharmony_ci            return 0;
239e1051a39Sopenharmony_ci        }
240e1051a39Sopenharmony_ci        cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
241e1051a39Sopenharmony_ci        cms->d.encryptedData->version = 0;
242e1051a39Sopenharmony_ci    } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
243e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_NOT_ENCRYPTED_DATA);
244e1051a39Sopenharmony_ci        return 0;
245e1051a39Sopenharmony_ci    }
246e1051a39Sopenharmony_ci    ec = cms->d.encryptedData->encryptedContentInfo;
247e1051a39Sopenharmony_ci    return ossl_cms_EncryptedContent_init(ec, ciph, key, keylen,
248e1051a39Sopenharmony_ci                                          ossl_cms_get0_cmsctx(cms));
249e1051a39Sopenharmony_ci}
250e1051a39Sopenharmony_ci
251e1051a39Sopenharmony_ciBIO *ossl_cms_EncryptedData_init_bio(const CMS_ContentInfo *cms)
252e1051a39Sopenharmony_ci{
253e1051a39Sopenharmony_ci    CMS_EncryptedData *enc = cms->d.encryptedData;
254e1051a39Sopenharmony_ci    if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
255e1051a39Sopenharmony_ci        enc->version = 2;
256e1051a39Sopenharmony_ci    return ossl_cms_EncryptedContent_init_bio(enc->encryptedContentInfo,
257e1051a39Sopenharmony_ci                                              ossl_cms_get0_cmsctx(cms));
258e1051a39Sopenharmony_ci}
259