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