1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2009-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 <openssl/aes.h>
18e1051a39Sopenharmony_ci#include "internal/sizes.h"
19e1051a39Sopenharmony_ci#include "crypto/asn1.h"
20e1051a39Sopenharmony_ci#include "cms_local.h"
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ciint CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
23e1051a39Sopenharmony_ci                                    unsigned char *pass, ossl_ssize_t passlen)
24e1051a39Sopenharmony_ci{
25e1051a39Sopenharmony_ci    CMS_PasswordRecipientInfo *pwri;
26e1051a39Sopenharmony_ci    if (ri->type != CMS_RECIPINFO_PASS) {
27e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_NOT_PWRI);
28e1051a39Sopenharmony_ci        return 0;
29e1051a39Sopenharmony_ci    }
30e1051a39Sopenharmony_ci
31e1051a39Sopenharmony_ci    pwri = ri->d.pwri;
32e1051a39Sopenharmony_ci    pwri->pass = pass;
33e1051a39Sopenharmony_ci    if (pass && passlen < 0)
34e1051a39Sopenharmony_ci        passlen = strlen((char *)pass);
35e1051a39Sopenharmony_ci    pwri->passlen = passlen;
36e1051a39Sopenharmony_ci    return 1;
37e1051a39Sopenharmony_ci}
38e1051a39Sopenharmony_ci
39e1051a39Sopenharmony_ciCMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
40e1051a39Sopenharmony_ci                                               int iter, int wrap_nid,
41e1051a39Sopenharmony_ci                                               int pbe_nid,
42e1051a39Sopenharmony_ci                                               unsigned char *pass,
43e1051a39Sopenharmony_ci                                               ossl_ssize_t passlen,
44e1051a39Sopenharmony_ci                                               const EVP_CIPHER *kekciph)
45e1051a39Sopenharmony_ci{
46e1051a39Sopenharmony_ci    STACK_OF(CMS_RecipientInfo) *ris;
47e1051a39Sopenharmony_ci    CMS_RecipientInfo *ri = NULL;
48e1051a39Sopenharmony_ci    CMS_EncryptedContentInfo *ec;
49e1051a39Sopenharmony_ci    CMS_PasswordRecipientInfo *pwri;
50e1051a39Sopenharmony_ci    EVP_CIPHER_CTX *ctx = NULL;
51e1051a39Sopenharmony_ci    X509_ALGOR *encalg = NULL;
52e1051a39Sopenharmony_ci    unsigned char iv[EVP_MAX_IV_LENGTH];
53e1051a39Sopenharmony_ci    int ivlen;
54e1051a39Sopenharmony_ci    const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms);
55e1051a39Sopenharmony_ci
56e1051a39Sopenharmony_ci    ec = ossl_cms_get0_env_enc_content(cms);
57e1051a39Sopenharmony_ci    if (ec == NULL)
58e1051a39Sopenharmony_ci        return NULL;
59e1051a39Sopenharmony_ci    ris = CMS_get0_RecipientInfos(cms);
60e1051a39Sopenharmony_ci    if (ris == NULL)
61e1051a39Sopenharmony_ci        return NULL;
62e1051a39Sopenharmony_ci
63e1051a39Sopenharmony_ci    if (wrap_nid <= 0)
64e1051a39Sopenharmony_ci        wrap_nid = NID_id_alg_PWRI_KEK;
65e1051a39Sopenharmony_ci
66e1051a39Sopenharmony_ci    if (pbe_nid <= 0)
67e1051a39Sopenharmony_ci        pbe_nid = NID_id_pbkdf2;
68e1051a39Sopenharmony_ci
69e1051a39Sopenharmony_ci    /* Get from enveloped data */
70e1051a39Sopenharmony_ci    if (kekciph == NULL)
71e1051a39Sopenharmony_ci        kekciph = ec->cipher;
72e1051a39Sopenharmony_ci
73e1051a39Sopenharmony_ci    if (kekciph == NULL) {
74e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_NO_CIPHER);
75e1051a39Sopenharmony_ci        return NULL;
76e1051a39Sopenharmony_ci    }
77e1051a39Sopenharmony_ci    if (wrap_nid != NID_id_alg_PWRI_KEK) {
78e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
79e1051a39Sopenharmony_ci        return NULL;
80e1051a39Sopenharmony_ci    }
81e1051a39Sopenharmony_ci
82e1051a39Sopenharmony_ci    /* Setup algorithm identifier for cipher */
83e1051a39Sopenharmony_ci    encalg = X509_ALGOR_new();
84e1051a39Sopenharmony_ci    if (encalg == NULL) {
85e1051a39Sopenharmony_ci        goto merr;
86e1051a39Sopenharmony_ci    }
87e1051a39Sopenharmony_ci    ctx = EVP_CIPHER_CTX_new();
88e1051a39Sopenharmony_ci    if (ctx == NULL) {
89e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
90e1051a39Sopenharmony_ci        goto err;
91e1051a39Sopenharmony_ci    }
92e1051a39Sopenharmony_ci
93e1051a39Sopenharmony_ci    if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) {
94e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
95e1051a39Sopenharmony_ci        goto err;
96e1051a39Sopenharmony_ci    }
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci    ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);
99e1051a39Sopenharmony_ci    if (ivlen < 0) {
100e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
101e1051a39Sopenharmony_ci        goto err;
102e1051a39Sopenharmony_ci    }
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_ci    if (ivlen > 0) {
105e1051a39Sopenharmony_ci        if (RAND_bytes_ex(ossl_cms_ctx_get0_libctx(cms_ctx), iv, ivlen, 0) <= 0)
106e1051a39Sopenharmony_ci            goto err;
107e1051a39Sopenharmony_ci        if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) {
108e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
109e1051a39Sopenharmony_ci            goto err;
110e1051a39Sopenharmony_ci        }
111e1051a39Sopenharmony_ci        encalg->parameter = ASN1_TYPE_new();
112e1051a39Sopenharmony_ci        if (!encalg->parameter) {
113e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
114e1051a39Sopenharmony_ci            goto err;
115e1051a39Sopenharmony_ci        }
116e1051a39Sopenharmony_ci        if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) {
117e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
118e1051a39Sopenharmony_ci            goto err;
119e1051a39Sopenharmony_ci        }
120e1051a39Sopenharmony_ci    }
121e1051a39Sopenharmony_ci
122e1051a39Sopenharmony_ci    encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_get_type(ctx));
123e1051a39Sopenharmony_ci
124e1051a39Sopenharmony_ci    EVP_CIPHER_CTX_free(ctx);
125e1051a39Sopenharmony_ci    ctx = NULL;
126e1051a39Sopenharmony_ci
127e1051a39Sopenharmony_ci    /* Initialize recipient info */
128e1051a39Sopenharmony_ci    ri = M_ASN1_new_of(CMS_RecipientInfo);
129e1051a39Sopenharmony_ci    if (ri == NULL)
130e1051a39Sopenharmony_ci        goto merr;
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ci    ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo);
133e1051a39Sopenharmony_ci    if (ri->d.pwri == NULL)
134e1051a39Sopenharmony_ci        goto merr;
135e1051a39Sopenharmony_ci    ri->type = CMS_RECIPINFO_PASS;
136e1051a39Sopenharmony_ci
137e1051a39Sopenharmony_ci    pwri = ri->d.pwri;
138e1051a39Sopenharmony_ci    pwri->cms_ctx = cms_ctx;
139e1051a39Sopenharmony_ci    /* Since this is overwritten, free up empty structure already there */
140e1051a39Sopenharmony_ci    X509_ALGOR_free(pwri->keyEncryptionAlgorithm);
141e1051a39Sopenharmony_ci    pwri->keyEncryptionAlgorithm = X509_ALGOR_new();
142e1051a39Sopenharmony_ci    if (pwri->keyEncryptionAlgorithm == NULL)
143e1051a39Sopenharmony_ci        goto merr;
144e1051a39Sopenharmony_ci    pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
145e1051a39Sopenharmony_ci    pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
146e1051a39Sopenharmony_ci    if (pwri->keyEncryptionAlgorithm->parameter == NULL)
147e1051a39Sopenharmony_ci        goto merr;
148e1051a39Sopenharmony_ci
149e1051a39Sopenharmony_ci    if (!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR),
150e1051a39Sopenharmony_ci                        &pwri->keyEncryptionAlgorithm->parameter->
151e1051a39Sopenharmony_ci                        value.sequence))
152e1051a39Sopenharmony_ci         goto merr;
153e1051a39Sopenharmony_ci    pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;
154e1051a39Sopenharmony_ci
155e1051a39Sopenharmony_ci    X509_ALGOR_free(encalg);
156e1051a39Sopenharmony_ci    encalg = NULL;
157e1051a39Sopenharmony_ci
158e1051a39Sopenharmony_ci    /* Setup PBE algorithm */
159e1051a39Sopenharmony_ci
160e1051a39Sopenharmony_ci    pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1);
161e1051a39Sopenharmony_ci
162e1051a39Sopenharmony_ci    if (pwri->keyDerivationAlgorithm == NULL)
163e1051a39Sopenharmony_ci        goto err;
164e1051a39Sopenharmony_ci
165e1051a39Sopenharmony_ci    CMS_RecipientInfo_set0_password(ri, pass, passlen);
166e1051a39Sopenharmony_ci    pwri->version = 0;
167e1051a39Sopenharmony_ci
168e1051a39Sopenharmony_ci    if (!sk_CMS_RecipientInfo_push(ris, ri))
169e1051a39Sopenharmony_ci        goto merr;
170e1051a39Sopenharmony_ci
171e1051a39Sopenharmony_ci    return ri;
172e1051a39Sopenharmony_ci
173e1051a39Sopenharmony_ci merr:
174e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
175e1051a39Sopenharmony_ci err:
176e1051a39Sopenharmony_ci    EVP_CIPHER_CTX_free(ctx);
177e1051a39Sopenharmony_ci    if (ri)
178e1051a39Sopenharmony_ci        M_ASN1_free_of(ri, CMS_RecipientInfo);
179e1051a39Sopenharmony_ci    X509_ALGOR_free(encalg);
180e1051a39Sopenharmony_ci    return NULL;
181e1051a39Sopenharmony_ci
182e1051a39Sopenharmony_ci}
183e1051a39Sopenharmony_ci
184e1051a39Sopenharmony_ci/*
185e1051a39Sopenharmony_ci * This is an implementation of the key wrapping mechanism in RFC3211, at
186e1051a39Sopenharmony_ci * some point this should go into EVP.
187e1051a39Sopenharmony_ci */
188e1051a39Sopenharmony_ci
189e1051a39Sopenharmony_cistatic int kek_unwrap_key(unsigned char *out, size_t *outlen,
190e1051a39Sopenharmony_ci                          const unsigned char *in, size_t inlen,
191e1051a39Sopenharmony_ci                          EVP_CIPHER_CTX *ctx)
192e1051a39Sopenharmony_ci{
193e1051a39Sopenharmony_ci    size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx);
194e1051a39Sopenharmony_ci    unsigned char *tmp;
195e1051a39Sopenharmony_ci    int outl, rv = 0;
196e1051a39Sopenharmony_ci    if (inlen < 2 * blocklen) {
197e1051a39Sopenharmony_ci        /* too small */
198e1051a39Sopenharmony_ci        return 0;
199e1051a39Sopenharmony_ci    }
200e1051a39Sopenharmony_ci    if (inlen % blocklen) {
201e1051a39Sopenharmony_ci        /* Invalid size */
202e1051a39Sopenharmony_ci        return 0;
203e1051a39Sopenharmony_ci    }
204e1051a39Sopenharmony_ci    if ((tmp = OPENSSL_malloc(inlen)) == NULL) {
205e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
206e1051a39Sopenharmony_ci        return 0;
207e1051a39Sopenharmony_ci    }
208e1051a39Sopenharmony_ci    /* setup IV by decrypting last two blocks */
209e1051a39Sopenharmony_ci    if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
210e1051a39Sopenharmony_ci                           in + inlen - 2 * blocklen, blocklen * 2)
211e1051a39Sopenharmony_ci        /*
212e1051a39Sopenharmony_ci         * Do a decrypt of last decrypted block to set IV to correct value
213e1051a39Sopenharmony_ci         * output it to start of buffer so we don't corrupt decrypted block
214e1051a39Sopenharmony_ci         * this works because buffer is at least two block lengths long.
215e1051a39Sopenharmony_ci         */
216e1051a39Sopenharmony_ci        || !EVP_DecryptUpdate(ctx, tmp, &outl,
217e1051a39Sopenharmony_ci                              tmp + inlen - blocklen, blocklen)
218e1051a39Sopenharmony_ci        /* Can now decrypt first n - 1 blocks */
219e1051a39Sopenharmony_ci        || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen)
220e1051a39Sopenharmony_ci
221e1051a39Sopenharmony_ci        /* Reset IV to original value */
222e1051a39Sopenharmony_ci        || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL)
223e1051a39Sopenharmony_ci        /* Decrypt again */
224e1051a39Sopenharmony_ci        || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen))
225e1051a39Sopenharmony_ci        goto err;
226e1051a39Sopenharmony_ci    /* Check check bytes */
227e1051a39Sopenharmony_ci    if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) {
228e1051a39Sopenharmony_ci        /* Check byte failure */
229e1051a39Sopenharmony_ci        goto err;
230e1051a39Sopenharmony_ci    }
231e1051a39Sopenharmony_ci    if (inlen < (size_t)(tmp[0] - 4)) {
232e1051a39Sopenharmony_ci        /* Invalid length value */
233e1051a39Sopenharmony_ci        goto err;
234e1051a39Sopenharmony_ci    }
235e1051a39Sopenharmony_ci    *outlen = (size_t)tmp[0];
236e1051a39Sopenharmony_ci    memcpy(out, tmp + 4, *outlen);
237e1051a39Sopenharmony_ci    rv = 1;
238e1051a39Sopenharmony_ci err:
239e1051a39Sopenharmony_ci    OPENSSL_clear_free(tmp, inlen);
240e1051a39Sopenharmony_ci    return rv;
241e1051a39Sopenharmony_ci
242e1051a39Sopenharmony_ci}
243e1051a39Sopenharmony_ci
244e1051a39Sopenharmony_cistatic int kek_wrap_key(unsigned char *out, size_t *outlen,
245e1051a39Sopenharmony_ci                        const unsigned char *in, size_t inlen,
246e1051a39Sopenharmony_ci                        EVP_CIPHER_CTX *ctx, const CMS_CTX *cms_ctx)
247e1051a39Sopenharmony_ci{
248e1051a39Sopenharmony_ci    size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx);
249e1051a39Sopenharmony_ci    size_t olen;
250e1051a39Sopenharmony_ci    int dummy;
251e1051a39Sopenharmony_ci    /*
252e1051a39Sopenharmony_ci     * First decide length of output buffer: need header and round up to
253e1051a39Sopenharmony_ci     * multiple of block length.
254e1051a39Sopenharmony_ci     */
255e1051a39Sopenharmony_ci    olen = (inlen + 4 + blocklen - 1) / blocklen;
256e1051a39Sopenharmony_ci    olen *= blocklen;
257e1051a39Sopenharmony_ci    if (olen < 2 * blocklen) {
258e1051a39Sopenharmony_ci        /* Key too small */
259e1051a39Sopenharmony_ci        return 0;
260e1051a39Sopenharmony_ci    }
261e1051a39Sopenharmony_ci    if (inlen > 0xFF) {
262e1051a39Sopenharmony_ci        /* Key too large */
263e1051a39Sopenharmony_ci        return 0;
264e1051a39Sopenharmony_ci    }
265e1051a39Sopenharmony_ci    if (out) {
266e1051a39Sopenharmony_ci        /* Set header */
267e1051a39Sopenharmony_ci        out[0] = (unsigned char)inlen;
268e1051a39Sopenharmony_ci        out[1] = in[0] ^ 0xFF;
269e1051a39Sopenharmony_ci        out[2] = in[1] ^ 0xFF;
270e1051a39Sopenharmony_ci        out[3] = in[2] ^ 0xFF;
271e1051a39Sopenharmony_ci        memcpy(out + 4, in, inlen);
272e1051a39Sopenharmony_ci        /* Add random padding to end */
273e1051a39Sopenharmony_ci        if (olen > inlen + 4
274e1051a39Sopenharmony_ci            && RAND_bytes_ex(ossl_cms_ctx_get0_libctx(cms_ctx), out + 4 + inlen,
275e1051a39Sopenharmony_ci                             olen - 4 - inlen, 0) <= 0)
276e1051a39Sopenharmony_ci            return 0;
277e1051a39Sopenharmony_ci        /* Encrypt twice */
278e1051a39Sopenharmony_ci        if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen)
279e1051a39Sopenharmony_ci            || !EVP_EncryptUpdate(ctx, out, &dummy, out, olen))
280e1051a39Sopenharmony_ci            return 0;
281e1051a39Sopenharmony_ci    }
282e1051a39Sopenharmony_ci
283e1051a39Sopenharmony_ci    *outlen = olen;
284e1051a39Sopenharmony_ci
285e1051a39Sopenharmony_ci    return 1;
286e1051a39Sopenharmony_ci}
287e1051a39Sopenharmony_ci
288e1051a39Sopenharmony_ci/* Encrypt/Decrypt content key in PWRI recipient info */
289e1051a39Sopenharmony_ci
290e1051a39Sopenharmony_ciint ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms,
291e1051a39Sopenharmony_ci                                      CMS_RecipientInfo *ri, int en_de)
292e1051a39Sopenharmony_ci{
293e1051a39Sopenharmony_ci    CMS_EncryptedContentInfo *ec;
294e1051a39Sopenharmony_ci    CMS_PasswordRecipientInfo *pwri;
295e1051a39Sopenharmony_ci    int r = 0;
296e1051a39Sopenharmony_ci    X509_ALGOR *algtmp, *kekalg = NULL;
297e1051a39Sopenharmony_ci    EVP_CIPHER_CTX *kekctx = NULL;
298e1051a39Sopenharmony_ci    char name[OSSL_MAX_NAME_SIZE];
299e1051a39Sopenharmony_ci    EVP_CIPHER *kekcipher;
300e1051a39Sopenharmony_ci    unsigned char *key = NULL;
301e1051a39Sopenharmony_ci    size_t keylen;
302e1051a39Sopenharmony_ci    const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms);
303e1051a39Sopenharmony_ci
304e1051a39Sopenharmony_ci    ec = ossl_cms_get0_env_enc_content(cms);
305e1051a39Sopenharmony_ci
306e1051a39Sopenharmony_ci    pwri = ri->d.pwri;
307e1051a39Sopenharmony_ci
308e1051a39Sopenharmony_ci    if (pwri->pass == NULL) {
309e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_NO_PASSWORD);
310e1051a39Sopenharmony_ci        return 0;
311e1051a39Sopenharmony_ci    }
312e1051a39Sopenharmony_ci    algtmp = pwri->keyEncryptionAlgorithm;
313e1051a39Sopenharmony_ci
314e1051a39Sopenharmony_ci    if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) {
315e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
316e1051a39Sopenharmony_ci        return 0;
317e1051a39Sopenharmony_ci    }
318e1051a39Sopenharmony_ci
319e1051a39Sopenharmony_ci    kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),
320e1051a39Sopenharmony_ci                                       algtmp->parameter);
321e1051a39Sopenharmony_ci
322e1051a39Sopenharmony_ci    if (kekalg == NULL) {
323e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);
324e1051a39Sopenharmony_ci        return 0;
325e1051a39Sopenharmony_ci    }
326e1051a39Sopenharmony_ci
327e1051a39Sopenharmony_ci    OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0);
328e1051a39Sopenharmony_ci    kekcipher = EVP_CIPHER_fetch(ossl_cms_ctx_get0_libctx(cms_ctx), name,
329e1051a39Sopenharmony_ci                                 ossl_cms_ctx_get0_propq(cms_ctx));
330e1051a39Sopenharmony_ci
331e1051a39Sopenharmony_ci    if (kekcipher == NULL) {
332e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER);
333e1051a39Sopenharmony_ci        goto err;
334e1051a39Sopenharmony_ci    }
335e1051a39Sopenharmony_ci
336e1051a39Sopenharmony_ci    kekctx = EVP_CIPHER_CTX_new();
337e1051a39Sopenharmony_ci    if (kekctx == NULL) {
338e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
339e1051a39Sopenharmony_ci        goto err;
340e1051a39Sopenharmony_ci    }
341e1051a39Sopenharmony_ci    /* Fixup cipher based on AlgorithmIdentifier to set IV etc */
342e1051a39Sopenharmony_ci    if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de))
343e1051a39Sopenharmony_ci        goto err;
344e1051a39Sopenharmony_ci    EVP_CIPHER_CTX_set_padding(kekctx, 0);
345e1051a39Sopenharmony_ci    if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) {
346e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
347e1051a39Sopenharmony_ci        goto err;
348e1051a39Sopenharmony_ci    }
349e1051a39Sopenharmony_ci
350e1051a39Sopenharmony_ci    algtmp = pwri->keyDerivationAlgorithm;
351e1051a39Sopenharmony_ci
352e1051a39Sopenharmony_ci    /* Finish password based key derivation to setup key in "ctx" */
353e1051a39Sopenharmony_ci
354e1051a39Sopenharmony_ci    if (EVP_PBE_CipherInit(algtmp->algorithm,
355e1051a39Sopenharmony_ci                           (char *)pwri->pass, pwri->passlen,
356e1051a39Sopenharmony_ci                           algtmp->parameter, kekctx, en_de) < 0) {
357e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
358e1051a39Sopenharmony_ci        goto err;
359e1051a39Sopenharmony_ci    }
360e1051a39Sopenharmony_ci
361e1051a39Sopenharmony_ci    /* Finally wrap/unwrap the key */
362e1051a39Sopenharmony_ci
363e1051a39Sopenharmony_ci    if (en_de) {
364e1051a39Sopenharmony_ci
365e1051a39Sopenharmony_ci        if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx, cms_ctx))
366e1051a39Sopenharmony_ci            goto err;
367e1051a39Sopenharmony_ci
368e1051a39Sopenharmony_ci        key = OPENSSL_malloc(keylen);
369e1051a39Sopenharmony_ci
370e1051a39Sopenharmony_ci        if (key == NULL)
371e1051a39Sopenharmony_ci            goto err;
372e1051a39Sopenharmony_ci
373e1051a39Sopenharmony_ci        if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx, cms_ctx))
374e1051a39Sopenharmony_ci            goto err;
375e1051a39Sopenharmony_ci        pwri->encryptedKey->data = key;
376e1051a39Sopenharmony_ci        pwri->encryptedKey->length = keylen;
377e1051a39Sopenharmony_ci    } else {
378e1051a39Sopenharmony_ci        key = OPENSSL_malloc(pwri->encryptedKey->length);
379e1051a39Sopenharmony_ci
380e1051a39Sopenharmony_ci        if (key == NULL) {
381e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
382e1051a39Sopenharmony_ci            goto err;
383e1051a39Sopenharmony_ci        }
384e1051a39Sopenharmony_ci        if (!kek_unwrap_key(key, &keylen,
385e1051a39Sopenharmony_ci                            pwri->encryptedKey->data,
386e1051a39Sopenharmony_ci                            pwri->encryptedKey->length, kekctx)) {
387e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_UNWRAP_FAILURE);
388e1051a39Sopenharmony_ci            goto err;
389e1051a39Sopenharmony_ci        }
390e1051a39Sopenharmony_ci
391e1051a39Sopenharmony_ci        OPENSSL_clear_free(ec->key, ec->keylen);
392e1051a39Sopenharmony_ci        ec->key = key;
393e1051a39Sopenharmony_ci        ec->keylen = keylen;
394e1051a39Sopenharmony_ci
395e1051a39Sopenharmony_ci    }
396e1051a39Sopenharmony_ci
397e1051a39Sopenharmony_ci    r = 1;
398e1051a39Sopenharmony_ci
399e1051a39Sopenharmony_ci err:
400e1051a39Sopenharmony_ci    EVP_CIPHER_free(kekcipher);
401e1051a39Sopenharmony_ci    EVP_CIPHER_CTX_free(kekctx);
402e1051a39Sopenharmony_ci
403e1051a39Sopenharmony_ci    if (!r)
404e1051a39Sopenharmony_ci        OPENSSL_free(key);
405e1051a39Sopenharmony_ci    X509_ALGOR_free(kekalg);
406e1051a39Sopenharmony_ci
407e1051a39Sopenharmony_ci    return r;
408e1051a39Sopenharmony_ci
409e1051a39Sopenharmony_ci}
410