1 /* crypto/cms/cms_enc.c */
3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
6 /* ====================================================================
7 * Copyright (c) 2008 The OpenSSL Project. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
21 * 3. All advertising materials mentioning features or use of this
22 * software must display the following acknowledgment:
23 * "This product includes software developed by the OpenSSL Project
24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 * endorse or promote products derived from this software without
28 * prior written permission. For written permission, please contact
29 * licensing@OpenSSL.org.
31 * 5. Products derived from this software may not be called "OpenSSL"
32 * nor may "OpenSSL" appear in their names without prior written
33 * permission of the OpenSSL Project.
35 * 6. Redistributions of any form whatsoever must retain the following
37 * "This product includes software developed by the OpenSSL Project
38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
56 #include <openssl/asn1t.h>
57 #include <openssl/pem.h>
58 #include <openssl/x509v3.h>
59 #include <openssl/err.h>
60 #include <openssl/cms.h>
61 #include <openssl/rand.h>
64 /* CMS EncryptedData Utilities */
66 DECLARE_ASN1_ITEM(CMS_EncryptedData
)
68 /* Return BIO based on EncryptedContentInfo and key */
70 BIO
*cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo
*ec
)
74 const EVP_CIPHER
*ciph
;
75 X509_ALGOR
*calg
= ec
->contentEncryptionAlgorithm
;
76 unsigned char iv
[EVP_MAX_IV_LENGTH
], *piv
= NULL
;
77 unsigned char *tkey
= NULL
;
82 int enc
, keep_key
= 0;
84 enc
= ec
->cipher
? 1 : 0;
86 b
= BIO_new(BIO_f_cipher());
88 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
, ERR_R_MALLOC_FAILURE
);
92 BIO_get_cipher_ctx(b
, &ctx
);
97 * If not keeping key set cipher to NULL so subsequent calls decrypt.
102 ciph
= EVP_get_cipherbyobj(calg
->algorithm
);
105 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
, CMS_R_UNKNOWN_CIPHER
);
110 if (EVP_CipherInit_ex(ctx
, ciph
, NULL
, NULL
, NULL
, enc
) <= 0) {
111 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
,
112 CMS_R_CIPHER_INITIALISATION_ERROR
);
118 calg
->algorithm
= OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx
));
119 /* Generate a random IV if we need one */
120 ivlen
= EVP_CIPHER_CTX_iv_length(ctx
);
122 if (RAND_bytes(iv
, ivlen
) <= 0)
126 } else if (EVP_CIPHER_asn1_to_param(ctx
, calg
->parameter
) <= 0) {
127 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
,
128 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR
);
131 tkeylen
= EVP_CIPHER_CTX_key_length(ctx
);
132 /* Generate random session key */
133 if (!enc
|| !ec
->key
) {
134 tkey
= OPENSSL_malloc(tkeylen
);
136 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
, ERR_R_MALLOC_FAILURE
);
139 if (EVP_CIPHER_CTX_rand_key(ctx
, tkey
) <= 0)
145 ec
->keylen
= tkeylen
;
154 if (ec
->keylen
!= tkeylen
) {
155 /* If necessary set key length */
156 if (EVP_CIPHER_CTX_set_key_length(ctx
, ec
->keylen
) <= 0) {
158 * Only reveal failure if debugging so we don't leak information
159 * which may be useful in MMA.
161 if (enc
|| ec
->debug
) {
162 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
,
163 CMS_R_INVALID_KEY_LENGTH
);
167 OPENSSL_clear_free(ec
->key
, ec
->keylen
);
169 ec
->keylen
= tkeylen
;
176 if (EVP_CipherInit_ex(ctx
, NULL
, NULL
, ec
->key
, piv
, enc
) <= 0) {
177 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
,
178 CMS_R_CIPHER_INITIALISATION_ERROR
);
183 calg
->parameter
= ASN1_TYPE_new();
184 if (!calg
->parameter
) {
185 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
, ERR_R_MALLOC_FAILURE
);
188 if (EVP_CIPHER_param_to_asn1(ctx
, calg
->parameter
) <= 0) {
189 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO
,
190 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR
);
197 if (ec
->key
&& !keep_key
) {
198 OPENSSL_clear_free(ec
->key
, ec
->keylen
);
201 OPENSSL_clear_free(tkey
, tkeylen
);
208 int cms_EncryptedContent_init(CMS_EncryptedContentInfo
*ec
,
209 const EVP_CIPHER
*cipher
,
210 const unsigned char *key
, size_t keylen
)
214 ec
->key
= OPENSSL_malloc(keylen
);
217 memcpy(ec
->key
, key
, keylen
);
221 ec
->contentType
= OBJ_nid2obj(NID_pkcs7_data
);
225 int CMS_EncryptedData_set1_key(CMS_ContentInfo
*cms
, const EVP_CIPHER
*ciph
,
226 const unsigned char *key
, size_t keylen
)
228 CMS_EncryptedContentInfo
*ec
;
229 if (!key
|| !keylen
) {
230 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY
, CMS_R_NO_KEY
);
234 cms
->d
.encryptedData
= M_ASN1_new_of(CMS_EncryptedData
);
235 if (!cms
->d
.encryptedData
) {
236 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY
, ERR_R_MALLOC_FAILURE
);
239 cms
->contentType
= OBJ_nid2obj(NID_pkcs7_encrypted
);
240 cms
->d
.encryptedData
->version
= 0;
241 } else if (OBJ_obj2nid(cms
->contentType
) != NID_pkcs7_encrypted
) {
242 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY
, CMS_R_NOT_ENCRYPTED_DATA
);
245 ec
= cms
->d
.encryptedData
->encryptedContentInfo
;
246 return cms_EncryptedContent_init(ec
, ciph
, key
, keylen
);
249 BIO
*cms_EncryptedData_init_bio(CMS_ContentInfo
*cms
)
251 CMS_EncryptedData
*enc
= cms
->d
.encryptedData
;
252 if (enc
->encryptedContentInfo
->cipher
&& enc
->unprotectedAttrs
)
254 return cms_EncryptedContent_init_bio(enc
->encryptedContentInfo
);