Line data Source code
1 : /* crypto/cms/cms_enc.c */
2 : /*
3 : * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4 : * project.
5 : */
6 : /* ====================================================================
7 : * Copyright (c) 2008 The OpenSSL Project. All rights reserved.
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions
11 : * are met:
12 : *
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice, this list of conditions and the following disclaimer.
15 : *
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
19 : * distribution.
20 : *
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/)"
25 : *
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.
30 : *
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.
34 : *
35 : * 6. Redistributions of any form whatsoever must retain the following
36 : * acknowledgment:
37 : * "This product includes software developed by the OpenSSL Project
38 : * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 : *
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 : * ====================================================================
53 : */
54 :
55 : #include "cryptlib.h"
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>
62 : #include "cms_lcl.h"
63 :
64 : /* CMS EncryptedData Utilities */
65 :
66 : DECLARE_ASN1_ITEM(CMS_EncryptedData)
67 :
68 : /* Return BIO based on EncryptedContentInfo and key */
69 :
70 0 : BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
71 : {
72 : BIO *b;
73 : EVP_CIPHER_CTX *ctx;
74 : const EVP_CIPHER *ciph;
75 0 : X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
76 : unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
77 : unsigned char *tkey = NULL;
78 : size_t tkeylen = 0;
79 :
80 : int ok = 0;
81 :
82 : int enc, keep_key = 0;
83 :
84 0 : enc = ec->cipher ? 1 : 0;
85 :
86 0 : b = BIO_new(BIO_f_cipher());
87 0 : if (!b) {
88 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
89 0 : return NULL;
90 : }
91 :
92 0 : BIO_get_cipher_ctx(b, &ctx);
93 :
94 0 : if (enc) {
95 0 : ciph = ec->cipher;
96 : /*
97 : * If not keeping key set cipher to NULL so subsequent calls decrypt.
98 : */
99 0 : if (ec->key)
100 0 : ec->cipher = NULL;
101 : } else {
102 0 : ciph = EVP_get_cipherbyobj(calg->algorithm);
103 :
104 0 : if (!ciph) {
105 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER);
106 0 : goto err;
107 : }
108 : }
109 :
110 0 : if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) {
111 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
112 : CMS_R_CIPHER_INITIALISATION_ERROR);
113 0 : goto err;
114 : }
115 :
116 0 : if (enc) {
117 : int ivlen;
118 0 : calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
119 : /* Generate a random IV if we need one */
120 0 : ivlen = EVP_CIPHER_CTX_iv_length(ctx);
121 0 : if (ivlen > 0) {
122 0 : if (RAND_pseudo_bytes(iv, ivlen) <= 0)
123 : goto err;
124 : piv = iv;
125 : }
126 0 : } else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) {
127 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
128 : CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
129 0 : goto err;
130 : }
131 0 : tkeylen = EVP_CIPHER_CTX_key_length(ctx);
132 : /* Generate random session key */
133 0 : if (!enc || !ec->key) {
134 0 : tkey = OPENSSL_malloc(tkeylen);
135 0 : if (!tkey) {
136 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
137 0 : goto err;
138 : }
139 0 : if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
140 : goto err;
141 : }
142 :
143 0 : if (!ec->key) {
144 0 : ec->key = tkey;
145 0 : ec->keylen = tkeylen;
146 : tkey = NULL;
147 0 : if (enc)
148 : keep_key = 1;
149 : else
150 0 : ERR_clear_error();
151 :
152 : }
153 :
154 0 : if (ec->keylen != tkeylen) {
155 : /* If necessary set key length */
156 0 : if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) {
157 : /*
158 : * Only reveal failure if debugging so we don't leak information
159 : * which may be useful in MMA.
160 : */
161 0 : if (enc || ec->debug) {
162 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
163 : CMS_R_INVALID_KEY_LENGTH);
164 0 : goto err;
165 : } else {
166 : /* Use random key */
167 0 : OPENSSL_cleanse(ec->key, ec->keylen);
168 0 : OPENSSL_free(ec->key);
169 0 : ec->key = tkey;
170 0 : ec->keylen = tkeylen;
171 : tkey = NULL;
172 0 : ERR_clear_error();
173 : }
174 : }
175 : }
176 :
177 0 : if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
178 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
179 : CMS_R_CIPHER_INITIALISATION_ERROR);
180 0 : goto err;
181 : }
182 :
183 0 : if (piv) {
184 0 : calg->parameter = ASN1_TYPE_new();
185 0 : if (!calg->parameter) {
186 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
187 0 : goto err;
188 : }
189 0 : if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) {
190 0 : CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
191 : CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
192 0 : goto err;
193 : }
194 : }
195 : ok = 1;
196 :
197 : err:
198 0 : if (ec->key && !keep_key) {
199 0 : OPENSSL_cleanse(ec->key, ec->keylen);
200 0 : OPENSSL_free(ec->key);
201 0 : ec->key = NULL;
202 : }
203 0 : if (tkey) {
204 0 : OPENSSL_cleanse(tkey, tkeylen);
205 0 : OPENSSL_free(tkey);
206 : }
207 0 : if (ok)
208 : return b;
209 0 : BIO_free(b);
210 0 : return NULL;
211 : }
212 :
213 0 : int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
214 : const EVP_CIPHER *cipher,
215 : const unsigned char *key, size_t keylen)
216 : {
217 0 : ec->cipher = cipher;
218 0 : if (key) {
219 0 : ec->key = OPENSSL_malloc(keylen);
220 0 : if (!ec->key)
221 : return 0;
222 : memcpy(ec->key, key, keylen);
223 : }
224 0 : ec->keylen = keylen;
225 0 : if (cipher)
226 0 : ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
227 : return 1;
228 : }
229 :
230 0 : int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
231 : const unsigned char *key, size_t keylen)
232 : {
233 : CMS_EncryptedContentInfo *ec;
234 0 : if (!key || !keylen) {
235 0 : CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NO_KEY);
236 0 : return 0;
237 : }
238 0 : if (ciph) {
239 0 : cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData);
240 0 : if (!cms->d.encryptedData) {
241 0 : CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, ERR_R_MALLOC_FAILURE);
242 0 : return 0;
243 : }
244 0 : cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
245 0 : cms->d.encryptedData->version = 0;
246 0 : } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
247 0 : CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NOT_ENCRYPTED_DATA);
248 0 : return 0;
249 : }
250 0 : ec = cms->d.encryptedData->encryptedContentInfo;
251 0 : return cms_EncryptedContent_init(ec, ciph, key, keylen);
252 : }
253 :
254 0 : BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
255 : {
256 0 : CMS_EncryptedData *enc = cms->d.encryptedData;
257 0 : if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
258 0 : enc->version = 2;
259 0 : return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
260 : }
|