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