1 /* 2 * Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (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 "cms_local.h" 18 19 /* CMS EncryptedData Utilities */ 20 21 /* Return BIO based on EncryptedContentInfo and key */ 22 23 BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec) 24 { 25 BIO *b; 26 EVP_CIPHER_CTX *ctx; 27 const EVP_CIPHER *ciph; 28 X509_ALGOR *calg = ec->contentEncryptionAlgorithm; 29 unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL; 30 unsigned char *tkey = NULL; 31 size_t tkeylen = 0; 32 33 int ok = 0; 34 35 int enc, keep_key = 0; 36 37 enc = ec->cipher ? 1 : 0; 38 39 b = BIO_new(BIO_f_cipher()); 40 if (b == NULL) { 41 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); 42 return NULL; 43 } 44 45 BIO_get_cipher_ctx(b, &ctx); 46 47 if (enc) { 48 ciph = ec->cipher; 49 /* 50 * If not keeping key set cipher to NULL so subsequent calls decrypt. 51 */ 52 if (ec->key) 53 ec->cipher = NULL; 54 } else { 55 ciph = EVP_get_cipherbyobj(calg->algorithm); 56 57 if (!ciph) { 58 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER); 59 goto err; 60 } 61 } 62 63 if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) { 64 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, 65 CMS_R_CIPHER_INITIALISATION_ERROR); 66 goto err; 67 } 68 69 if (enc) { 70 int ivlen; 71 calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); 72 /* Generate a random IV if we need one */ 73 ivlen = EVP_CIPHER_CTX_iv_length(ctx); 74 if (ivlen > 0) { 75 if (RAND_bytes(iv, ivlen) <= 0) 76 goto err; 77 piv = iv; 78 } 79 } else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) { 80 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, 81 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); 82 goto err; 83 } 84 tkeylen = EVP_CIPHER_CTX_key_length(ctx); 85 /* Generate random session key */ 86 if (!enc || !ec->key) { 87 tkey = OPENSSL_malloc(tkeylen); 88 if (tkey == NULL) { 89 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); 90 goto err; 91 } 92 if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0) 93 goto err; 94 } 95 96 if (!ec->key) { 97 ec->key = tkey; 98 ec->keylen = tkeylen; 99 tkey = NULL; 100 if (enc) 101 keep_key = 1; 102 else 103 ERR_clear_error(); 104 105 } 106 107 if (ec->keylen != tkeylen) { 108 /* If necessary set key length */ 109 if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) { 110 /* 111 * Only reveal failure if debugging so we don't leak information 112 * which may be useful in MMA. 113 */ 114 if (enc || ec->debug) { 115 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, 116 CMS_R_INVALID_KEY_LENGTH); 117 goto err; 118 } else { 119 /* Use random key */ 120 OPENSSL_clear_free(ec->key, ec->keylen); 121 ec->key = tkey; 122 ec->keylen = tkeylen; 123 tkey = NULL; 124 ERR_clear_error(); 125 } 126 } 127 } 128 129 if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) { 130 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, 131 CMS_R_CIPHER_INITIALISATION_ERROR); 132 goto err; 133 } 134 if (enc) { 135 calg->parameter = ASN1_TYPE_new(); 136 if (calg->parameter == NULL) { 137 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); 138 goto err; 139 } 140 if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) { 141 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, 142 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); 143 goto err; 144 } 145 /* If parameter type not set omit parameter */ 146 if (calg->parameter->type == V_ASN1_UNDEF) { 147 ASN1_TYPE_free(calg->parameter); 148 calg->parameter = NULL; 149 } 150 } 151 ok = 1; 152 153 err: 154 if (!keep_key || !ok) { 155 OPENSSL_clear_free(ec->key, ec->keylen); 156 ec->key = NULL; 157 } 158 OPENSSL_clear_free(tkey, tkeylen); 159 if (ok) 160 return b; 161 BIO_free(b); 162 return NULL; 163 } 164 165 int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec, 166 const EVP_CIPHER *cipher, 167 const unsigned char *key, size_t keylen) 168 { 169 ec->cipher = cipher; 170 if (key) { 171 if ((ec->key = OPENSSL_malloc(keylen)) == NULL) { 172 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT, ERR_R_MALLOC_FAILURE); 173 return 0; 174 } 175 memcpy(ec->key, key, keylen); 176 } 177 ec->keylen = keylen; 178 if (cipher) 179 ec->contentType = OBJ_nid2obj(NID_pkcs7_data); 180 return 1; 181 } 182 183 int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, 184 const unsigned char *key, size_t keylen) 185 { 186 CMS_EncryptedContentInfo *ec; 187 if (!key || !keylen) { 188 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NO_KEY); 189 return 0; 190 } 191 if (ciph) { 192 cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData); 193 if (!cms->d.encryptedData) { 194 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, ERR_R_MALLOC_FAILURE); 195 return 0; 196 } 197 cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted); 198 cms->d.encryptedData->version = 0; 199 } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) { 200 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NOT_ENCRYPTED_DATA); 201 return 0; 202 } 203 ec = cms->d.encryptedData->encryptedContentInfo; 204 return cms_EncryptedContent_init(ec, ciph, key, keylen); 205 } 206 207 BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms) 208 { 209 CMS_EncryptedData *enc = cms->d.encryptedData; 210 if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs) 211 enc->version = 2; 212 return cms_EncryptedContent_init_bio(enc->encryptedContentInfo); 213 } 214