11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * Copyright 2008-2023 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
51cb0ef41Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
61cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at
71cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html
81cb0ef41Sopenharmony_ci */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include "internal/cryptlib.h"
111cb0ef41Sopenharmony_ci#include <openssl/asn1t.h>
121cb0ef41Sopenharmony_ci#include <openssl/pem.h>
131cb0ef41Sopenharmony_ci#include <openssl/x509v3.h>
141cb0ef41Sopenharmony_ci#include <openssl/err.h>
151cb0ef41Sopenharmony_ci#include <openssl/cms.h>
161cb0ef41Sopenharmony_ci#include <openssl/rand.h>
171cb0ef41Sopenharmony_ci#include "crypto/evp.h"
181cb0ef41Sopenharmony_ci#include "crypto/asn1.h"
191cb0ef41Sopenharmony_ci#include "cms_local.h"
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci/* CMS EncryptedData Utilities */
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci/* Return BIO based on EncryptedContentInfo and key */
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciBIO *ossl_cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
261cb0ef41Sopenharmony_ci                                        const CMS_CTX *cms_ctx)
271cb0ef41Sopenharmony_ci{
281cb0ef41Sopenharmony_ci    BIO *b;
291cb0ef41Sopenharmony_ci    EVP_CIPHER_CTX *ctx;
301cb0ef41Sopenharmony_ci    EVP_CIPHER *fetched_ciph = NULL;
311cb0ef41Sopenharmony_ci    const EVP_CIPHER *cipher = NULL;
321cb0ef41Sopenharmony_ci    X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
331cb0ef41Sopenharmony_ci    evp_cipher_aead_asn1_params aparams;
341cb0ef41Sopenharmony_ci    unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
351cb0ef41Sopenharmony_ci    unsigned char *tkey = NULL;
361cb0ef41Sopenharmony_ci    int len;
371cb0ef41Sopenharmony_ci    int ivlen = 0;
381cb0ef41Sopenharmony_ci    size_t tkeylen = 0;
391cb0ef41Sopenharmony_ci    int ok = 0;
401cb0ef41Sopenharmony_ci    int enc, keep_key = 0;
411cb0ef41Sopenharmony_ci    OSSL_LIB_CTX *libctx = ossl_cms_ctx_get0_libctx(cms_ctx);
421cb0ef41Sopenharmony_ci    const char *propq = ossl_cms_ctx_get0_propq(cms_ctx);
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci    enc = ec->cipher ? 1 : 0;
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci    b = BIO_new(BIO_f_cipher());
471cb0ef41Sopenharmony_ci    if (b == NULL) {
481cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
491cb0ef41Sopenharmony_ci        return NULL;
501cb0ef41Sopenharmony_ci    }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci    BIO_get_cipher_ctx(b, &ctx);
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci    (void)ERR_set_mark();
551cb0ef41Sopenharmony_ci    if (enc) {
561cb0ef41Sopenharmony_ci        cipher = ec->cipher;
571cb0ef41Sopenharmony_ci        /*
581cb0ef41Sopenharmony_ci         * If not keeping key set cipher to NULL so subsequent calls decrypt.
591cb0ef41Sopenharmony_ci         */
601cb0ef41Sopenharmony_ci        if (ec->key != NULL)
611cb0ef41Sopenharmony_ci            ec->cipher = NULL;
621cb0ef41Sopenharmony_ci    } else {
631cb0ef41Sopenharmony_ci        cipher = EVP_get_cipherbyobj(calg->algorithm);
641cb0ef41Sopenharmony_ci    }
651cb0ef41Sopenharmony_ci    if (cipher != NULL) {
661cb0ef41Sopenharmony_ci        fetched_ciph = EVP_CIPHER_fetch(libctx, EVP_CIPHER_get0_name(cipher),
671cb0ef41Sopenharmony_ci                                        propq);
681cb0ef41Sopenharmony_ci        if (fetched_ciph != NULL)
691cb0ef41Sopenharmony_ci            cipher = fetched_ciph;
701cb0ef41Sopenharmony_ci    }
711cb0ef41Sopenharmony_ci    if (cipher == NULL) {
721cb0ef41Sopenharmony_ci        (void)ERR_clear_last_mark();
731cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER);
741cb0ef41Sopenharmony_ci        goto err;
751cb0ef41Sopenharmony_ci    }
761cb0ef41Sopenharmony_ci    (void)ERR_pop_to_mark();
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci    if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc) <= 0) {
791cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR);
801cb0ef41Sopenharmony_ci        goto err;
811cb0ef41Sopenharmony_ci    }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci    if (enc) {
841cb0ef41Sopenharmony_ci        calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_get_type(ctx));
851cb0ef41Sopenharmony_ci        if (calg->algorithm == NULL || calg->algorithm->nid == NID_undef) {
861cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM);
871cb0ef41Sopenharmony_ci            goto err;
881cb0ef41Sopenharmony_ci        }
891cb0ef41Sopenharmony_ci        /* Generate a random IV if we need one */
901cb0ef41Sopenharmony_ci        ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);
911cb0ef41Sopenharmony_ci        if (ivlen < 0) {
921cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
931cb0ef41Sopenharmony_ci            goto err;
941cb0ef41Sopenharmony_ci        }
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci        if (ivlen > 0) {
971cb0ef41Sopenharmony_ci            if (RAND_bytes_ex(libctx, iv, ivlen, 0) <= 0)
981cb0ef41Sopenharmony_ci                goto err;
991cb0ef41Sopenharmony_ci            piv = iv;
1001cb0ef41Sopenharmony_ci        }
1011cb0ef41Sopenharmony_ci    } else {
1021cb0ef41Sopenharmony_ci        if (evp_cipher_asn1_to_param_ex(ctx, calg->parameter, &aparams) <= 0) {
1031cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
1041cb0ef41Sopenharmony_ci            goto err;
1051cb0ef41Sopenharmony_ci        }
1061cb0ef41Sopenharmony_ci        if ((EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) {
1071cb0ef41Sopenharmony_ci            piv = aparams.iv;
1081cb0ef41Sopenharmony_ci            if (ec->taglen > 0
1091cb0ef41Sopenharmony_ci                    && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
1101cb0ef41Sopenharmony_ci                                           ec->taglen, ec->tag) <= 0) {
1111cb0ef41Sopenharmony_ci                ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_AEAD_SET_TAG_ERROR);
1121cb0ef41Sopenharmony_ci                goto err;
1131cb0ef41Sopenharmony_ci            }
1141cb0ef41Sopenharmony_ci        }
1151cb0ef41Sopenharmony_ci    }
1161cb0ef41Sopenharmony_ci    len = EVP_CIPHER_CTX_get_key_length(ctx);
1171cb0ef41Sopenharmony_ci    if (len <= 0)
1181cb0ef41Sopenharmony_ci        goto err;
1191cb0ef41Sopenharmony_ci    tkeylen = (size_t)len;
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci    /* Generate random session key */
1221cb0ef41Sopenharmony_ci    if (!enc || !ec->key) {
1231cb0ef41Sopenharmony_ci        tkey = OPENSSL_malloc(tkeylen);
1241cb0ef41Sopenharmony_ci        if (tkey == NULL) {
1251cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
1261cb0ef41Sopenharmony_ci            goto err;
1271cb0ef41Sopenharmony_ci        }
1281cb0ef41Sopenharmony_ci        if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
1291cb0ef41Sopenharmony_ci            goto err;
1301cb0ef41Sopenharmony_ci    }
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci    if (!ec->key) {
1331cb0ef41Sopenharmony_ci        ec->key = tkey;
1341cb0ef41Sopenharmony_ci        ec->keylen = tkeylen;
1351cb0ef41Sopenharmony_ci        tkey = NULL;
1361cb0ef41Sopenharmony_ci        if (enc)
1371cb0ef41Sopenharmony_ci            keep_key = 1;
1381cb0ef41Sopenharmony_ci        else
1391cb0ef41Sopenharmony_ci            ERR_clear_error();
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    }
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci    if (ec->keylen != tkeylen) {
1441cb0ef41Sopenharmony_ci        /* If necessary set key length */
1451cb0ef41Sopenharmony_ci        if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) {
1461cb0ef41Sopenharmony_ci            /*
1471cb0ef41Sopenharmony_ci             * Only reveal failure if debugging so we don't leak information
1481cb0ef41Sopenharmony_ci             * which may be useful in MMA.
1491cb0ef41Sopenharmony_ci             */
1501cb0ef41Sopenharmony_ci            if (enc || ec->debug) {
1511cb0ef41Sopenharmony_ci                ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH);
1521cb0ef41Sopenharmony_ci                goto err;
1531cb0ef41Sopenharmony_ci            } else {
1541cb0ef41Sopenharmony_ci                /* Use random key */
1551cb0ef41Sopenharmony_ci                OPENSSL_clear_free(ec->key, ec->keylen);
1561cb0ef41Sopenharmony_ci                ec->key = tkey;
1571cb0ef41Sopenharmony_ci                ec->keylen = tkeylen;
1581cb0ef41Sopenharmony_ci                tkey = NULL;
1591cb0ef41Sopenharmony_ci                ERR_clear_error();
1601cb0ef41Sopenharmony_ci            }
1611cb0ef41Sopenharmony_ci        }
1621cb0ef41Sopenharmony_ci    }
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci    if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
1651cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR);
1661cb0ef41Sopenharmony_ci        goto err;
1671cb0ef41Sopenharmony_ci    }
1681cb0ef41Sopenharmony_ci    if (enc) {
1691cb0ef41Sopenharmony_ci        calg->parameter = ASN1_TYPE_new();
1701cb0ef41Sopenharmony_ci        if (calg->parameter == NULL) {
1711cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
1721cb0ef41Sopenharmony_ci            goto err;
1731cb0ef41Sopenharmony_ci        }
1741cb0ef41Sopenharmony_ci        if ((EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) {
1751cb0ef41Sopenharmony_ci            memcpy(aparams.iv, piv, ivlen);
1761cb0ef41Sopenharmony_ci            aparams.iv_len = ivlen;
1771cb0ef41Sopenharmony_ci            aparams.tag_len = EVP_CIPHER_CTX_get_tag_length(ctx);
1781cb0ef41Sopenharmony_ci            if (aparams.tag_len <= 0)
1791cb0ef41Sopenharmony_ci                goto err;
1801cb0ef41Sopenharmony_ci        }
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci        if (evp_cipher_param_to_asn1_ex(ctx, calg->parameter, &aparams) <= 0) {
1831cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
1841cb0ef41Sopenharmony_ci            goto err;
1851cb0ef41Sopenharmony_ci        }
1861cb0ef41Sopenharmony_ci        /* If parameter type not set omit parameter */
1871cb0ef41Sopenharmony_ci        if (calg->parameter->type == V_ASN1_UNDEF) {
1881cb0ef41Sopenharmony_ci            ASN1_TYPE_free(calg->parameter);
1891cb0ef41Sopenharmony_ci            calg->parameter = NULL;
1901cb0ef41Sopenharmony_ci        }
1911cb0ef41Sopenharmony_ci    }
1921cb0ef41Sopenharmony_ci    ok = 1;
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci err:
1951cb0ef41Sopenharmony_ci    EVP_CIPHER_free(fetched_ciph);
1961cb0ef41Sopenharmony_ci    if (!keep_key || !ok) {
1971cb0ef41Sopenharmony_ci        OPENSSL_clear_free(ec->key, ec->keylen);
1981cb0ef41Sopenharmony_ci        ec->key = NULL;
1991cb0ef41Sopenharmony_ci    }
2001cb0ef41Sopenharmony_ci    OPENSSL_clear_free(tkey, tkeylen);
2011cb0ef41Sopenharmony_ci    if (ok)
2021cb0ef41Sopenharmony_ci        return b;
2031cb0ef41Sopenharmony_ci    BIO_free(b);
2041cb0ef41Sopenharmony_ci    return NULL;
2051cb0ef41Sopenharmony_ci}
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ciint ossl_cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
2081cb0ef41Sopenharmony_ci                                   const EVP_CIPHER *cipher,
2091cb0ef41Sopenharmony_ci                                   const unsigned char *key, size_t keylen,
2101cb0ef41Sopenharmony_ci                                   const CMS_CTX *cms_ctx)
2111cb0ef41Sopenharmony_ci{
2121cb0ef41Sopenharmony_ci    ec->cipher = cipher;
2131cb0ef41Sopenharmony_ci    if (key) {
2141cb0ef41Sopenharmony_ci        if ((ec->key = OPENSSL_malloc(keylen)) == NULL) {
2151cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
2161cb0ef41Sopenharmony_ci            return 0;
2171cb0ef41Sopenharmony_ci        }
2181cb0ef41Sopenharmony_ci        memcpy(ec->key, key, keylen);
2191cb0ef41Sopenharmony_ci    }
2201cb0ef41Sopenharmony_ci    ec->keylen = keylen;
2211cb0ef41Sopenharmony_ci    if (cipher != NULL)
2221cb0ef41Sopenharmony_ci        ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
2231cb0ef41Sopenharmony_ci    return 1;
2241cb0ef41Sopenharmony_ci}
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ciint CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
2271cb0ef41Sopenharmony_ci                               const unsigned char *key, size_t keylen)
2281cb0ef41Sopenharmony_ci{
2291cb0ef41Sopenharmony_ci    CMS_EncryptedContentInfo *ec;
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci    if (!key || !keylen) {
2321cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_NO_KEY);
2331cb0ef41Sopenharmony_ci        return 0;
2341cb0ef41Sopenharmony_ci    }
2351cb0ef41Sopenharmony_ci    if (ciph) {
2361cb0ef41Sopenharmony_ci        cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData);
2371cb0ef41Sopenharmony_ci        if (!cms->d.encryptedData) {
2381cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
2391cb0ef41Sopenharmony_ci            return 0;
2401cb0ef41Sopenharmony_ci        }
2411cb0ef41Sopenharmony_ci        cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
2421cb0ef41Sopenharmony_ci        cms->d.encryptedData->version = 0;
2431cb0ef41Sopenharmony_ci    } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
2441cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_NOT_ENCRYPTED_DATA);
2451cb0ef41Sopenharmony_ci        return 0;
2461cb0ef41Sopenharmony_ci    }
2471cb0ef41Sopenharmony_ci    ec = cms->d.encryptedData->encryptedContentInfo;
2481cb0ef41Sopenharmony_ci    return ossl_cms_EncryptedContent_init(ec, ciph, key, keylen,
2491cb0ef41Sopenharmony_ci                                          ossl_cms_get0_cmsctx(cms));
2501cb0ef41Sopenharmony_ci}
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ciBIO *ossl_cms_EncryptedData_init_bio(const CMS_ContentInfo *cms)
2531cb0ef41Sopenharmony_ci{
2541cb0ef41Sopenharmony_ci    CMS_EncryptedData *enc = cms->d.encryptedData;
2551cb0ef41Sopenharmony_ci    if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
2561cb0ef41Sopenharmony_ci        enc->version = 2;
2571cb0ef41Sopenharmony_ci    return ossl_cms_EncryptedContent_init_bio(enc->encryptedContentInfo,
2581cb0ef41Sopenharmony_ci                                              ossl_cms_get0_cmsctx(cms));
2591cb0ef41Sopenharmony_ci}
260