2 * Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved.
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
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>
19 /* CMS EncryptedData Utilities */
21 /* Return BIO based on EncryptedContentInfo and key */
23 BIO
*cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo
*ec
)
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
;
35 int enc
, keep_key
= 0;
37 enc
= ec
->cipher
? 1 : 0;
39 b
= BIO_new(BIO_f_cipher());
41 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
, ERR_R_MALLOC_FAILURE
);
45 BIO_get_cipher_ctx(b
, &ctx
);
50 * If not keeping key set cipher to NULL so subsequent calls decrypt.
55 ciph
= EVP_get_cipherbyobj(calg
->algorithm
);
58 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
, CMS_R_UNKNOWN_CIPHER
);
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
);
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
);
75 if (RAND_bytes(iv
, ivlen
) <= 0)
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
);
84 tkeylen
= EVP_CIPHER_CTX_key_length(ctx
);
85 /* Generate random session key */
86 if (!enc
|| !ec
->key
) {
87 tkey
= OPENSSL_malloc(tkeylen
);
89 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
, ERR_R_MALLOC_FAILURE
);
92 if (EVP_CIPHER_CTX_rand_key(ctx
, tkey
) <= 0)
107 if (ec
->keylen
!= tkeylen
) {
108 /* If necessary set key length */
109 if (EVP_CIPHER_CTX_set_key_length(ctx
, ec
->keylen
) <= 0) {
111 * Only reveal failure if debugging so we don't leak information
112 * which may be useful in MMA.
114 if (enc
|| ec
->debug
) {
115 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
,
116 CMS_R_INVALID_KEY_LENGTH
);
120 OPENSSL_clear_free(ec
->key
, ec
->keylen
);
122 ec
->keylen
= tkeylen
;
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
);
135 calg
->parameter
= ASN1_TYPE_new();
136 if (calg
->parameter
== NULL
) {
137 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
, ERR_R_MALLOC_FAILURE
);
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
);
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
;
154 if (!keep_key
|| !ok
) {
155 OPENSSL_clear_free(ec
->key
, ec
->keylen
);
158 OPENSSL_clear_free(tkey
, tkeylen
);
165 int cms_EncryptedContent_init(CMS_EncryptedContentInfo
*ec
,
166 const EVP_CIPHER
*cipher
,
167 const unsigned char *key
, size_t keylen
)
171 if ((ec
->key
= OPENSSL_malloc(keylen
)) == NULL
) {
172 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT
, ERR_R_MALLOC_FAILURE
);
175 memcpy(ec
->key
, key
, keylen
);
179 ec
->contentType
= OBJ_nid2obj(NID_pkcs7_data
);
183 int CMS_EncryptedData_set1_key(CMS_ContentInfo
*cms
, const EVP_CIPHER
*ciph
,
184 const unsigned char *key
, size_t keylen
)
186 CMS_EncryptedContentInfo
*ec
;
187 if (!key
|| !keylen
) {
188 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY
, CMS_R_NO_KEY
);
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
);
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
);
203 ec
= cms
->d
.encryptedData
->encryptedContentInfo
;
204 return cms_EncryptedContent_init(ec
, ciph
, key
, keylen
);
207 BIO
*cms_EncryptedData_init_bio(CMS_ContentInfo
*cms
)
209 CMS_EncryptedData
*enc
= cms
->d
.encryptedData
;
210 if (enc
->encryptedContentInfo
->cipher
&& enc
->unprotectedAttrs
)
212 return cms_EncryptedContent_init_bio(enc
->encryptedContentInfo
);