1 /* crypto/cms/cms_pwri.c */
3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
6 /* ====================================================================
7 * Copyright (c) 2009 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>
62 #include <openssl/aes.h>
64 #include "asn1_locl.h"
66 int CMS_RecipientInfo_set0_password(CMS_RecipientInfo
*ri
,
67 unsigned char *pass
, ossl_ssize_t passlen
)
69 CMS_PasswordRecipientInfo
*pwri
;
70 if (ri
->type
!= CMS_RECIPINFO_PASS
) {
71 CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD
, CMS_R_NOT_PWRI
);
77 if (pass
&& passlen
< 0)
78 passlen
= strlen((char *)pass
);
79 pwri
->passlen
= passlen
;
83 CMS_RecipientInfo
*CMS_add0_recipient_password(CMS_ContentInfo
*cms
,
84 int iter
, int wrap_nid
,
88 const EVP_CIPHER
*kekciph
)
90 CMS_RecipientInfo
*ri
= NULL
;
91 CMS_EnvelopedData
*env
;
92 CMS_PasswordRecipientInfo
*pwri
;
94 X509_ALGOR
*encalg
= NULL
;
95 unsigned char iv
[EVP_MAX_IV_LENGTH
];
98 env
= cms_get0_enveloped(cms
);
103 wrap_nid
= NID_id_alg_PWRI_KEK
;
106 pbe_nid
= NID_id_pbkdf2
;
108 /* Get from enveloped data */
110 kekciph
= env
->encryptedContentInfo
->cipher
;
112 if (kekciph
== NULL
) {
113 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD
, CMS_R_NO_CIPHER
);
116 if (wrap_nid
!= NID_id_alg_PWRI_KEK
) {
117 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD
,
118 CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM
);
122 /* Setup algorithm identifier for cipher */
123 encalg
= X509_ALGOR_new();
124 EVP_CIPHER_CTX_init(&ctx
);
126 if (EVP_EncryptInit_ex(&ctx
, kekciph
, NULL
, NULL
, NULL
) <= 0) {
127 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD
, ERR_R_EVP_LIB
);
131 ivlen
= EVP_CIPHER_CTX_iv_length(&ctx
);
134 if (RAND_pseudo_bytes(iv
, ivlen
) <= 0)
136 if (EVP_EncryptInit_ex(&ctx
, NULL
, NULL
, NULL
, iv
) <= 0) {
137 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD
, ERR_R_EVP_LIB
);
140 encalg
->parameter
= ASN1_TYPE_new();
141 if (!encalg
->parameter
) {
142 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD
, ERR_R_MALLOC_FAILURE
);
145 if (EVP_CIPHER_param_to_asn1(&ctx
, encalg
->parameter
) <= 0) {
146 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD
,
147 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR
);
152 encalg
->algorithm
= OBJ_nid2obj(EVP_CIPHER_CTX_type(&ctx
));
154 EVP_CIPHER_CTX_cleanup(&ctx
);
156 /* Initialize recipient info */
157 ri
= M_ASN1_new_of(CMS_RecipientInfo
);
161 ri
->d
.pwri
= M_ASN1_new_of(CMS_PasswordRecipientInfo
);
164 ri
->type
= CMS_RECIPINFO_PASS
;
167 /* Since this is overwritten, free up empty structure already there */
168 X509_ALGOR_free(pwri
->keyEncryptionAlgorithm
);
169 pwri
->keyEncryptionAlgorithm
= X509_ALGOR_new();
170 if (!pwri
->keyEncryptionAlgorithm
)
172 pwri
->keyEncryptionAlgorithm
->algorithm
= OBJ_nid2obj(wrap_nid
);
173 pwri
->keyEncryptionAlgorithm
->parameter
= ASN1_TYPE_new();
174 if (!pwri
->keyEncryptionAlgorithm
->parameter
)
177 if (!ASN1_item_pack(encalg
, ASN1_ITEM_rptr(X509_ALGOR
),
178 &pwri
->keyEncryptionAlgorithm
->parameter
->
181 pwri
->keyEncryptionAlgorithm
->parameter
->type
= V_ASN1_SEQUENCE
;
183 X509_ALGOR_free(encalg
);
186 /* Setup PBE algorithm */
188 pwri
->keyDerivationAlgorithm
= PKCS5_pbkdf2_set(iter
, NULL
, 0, -1, -1);
190 if (!pwri
->keyDerivationAlgorithm
)
193 CMS_RecipientInfo_set0_password(ri
, pass
, passlen
);
196 if (!sk_CMS_RecipientInfo_push(env
->recipientInfos
, ri
))
202 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD
, ERR_R_MALLOC_FAILURE
);
204 EVP_CIPHER_CTX_cleanup(&ctx
);
206 M_ASN1_free_of(ri
, CMS_RecipientInfo
);
208 X509_ALGOR_free(encalg
);
214 * This is an implementation of the key wrapping mechanism in RFC3211, at
215 * some point this should go into EVP.
218 static int kek_unwrap_key(unsigned char *out
, size_t *outlen
,
219 const unsigned char *in
, size_t inlen
,
222 size_t blocklen
= EVP_CIPHER_CTX_block_size(ctx
);
225 if (inlen
< 2 * blocklen
) {
229 if (inlen
% blocklen
) {
233 tmp
= OPENSSL_malloc(inlen
);
236 /* setup IV by decrypting last two blocks */
237 if (!EVP_DecryptUpdate(ctx
, tmp
+ inlen
- 2 * blocklen
, &outl
,
238 in
+ inlen
- 2 * blocklen
, blocklen
* 2)
240 * Do a decrypt of last decrypted block to set IV to correct value
241 * output it to start of buffer so we don't corrupt decrypted block
242 * this works because buffer is at least two block lengths long.
244 || !EVP_DecryptUpdate(ctx
, tmp
, &outl
,
245 tmp
+ inlen
- blocklen
, blocklen
)
246 /* Can now decrypt first n - 1 blocks */
247 || !EVP_DecryptUpdate(ctx
, tmp
, &outl
, in
, inlen
- blocklen
)
249 /* Reset IV to original value */
250 || !EVP_DecryptInit_ex(ctx
, NULL
, NULL
, NULL
, NULL
)
252 || !EVP_DecryptUpdate(ctx
, tmp
, &outl
, tmp
, inlen
))
254 /* Check check bytes */
255 if (((tmp
[1] ^ tmp
[4]) & (tmp
[2] ^ tmp
[5]) & (tmp
[3] ^ tmp
[6])) != 0xff) {
256 /* Check byte failure */
259 if (inlen
< (size_t)(tmp
[0] - 4)) {
260 /* Invalid length value */
263 *outlen
= (size_t)tmp
[0];
264 memcpy(out
, tmp
+ 4, *outlen
);
267 OPENSSL_cleanse(tmp
, inlen
);
273 static int kek_wrap_key(unsigned char *out
, size_t *outlen
,
274 const unsigned char *in
, size_t inlen
,
277 size_t blocklen
= EVP_CIPHER_CTX_block_size(ctx
);
281 * First decide length of output buffer: need header and round up to
282 * multiple of block length.
284 olen
= (inlen
+ 4 + blocklen
- 1) / blocklen
;
286 if (olen
< 2 * blocklen
) {
296 out
[0] = (unsigned char)inlen
;
297 out
[1] = in
[0] ^ 0xFF;
298 out
[2] = in
[1] ^ 0xFF;
299 out
[3] = in
[2] ^ 0xFF;
300 memcpy(out
+ 4, in
, inlen
);
301 /* Add random padding to end */
302 if (olen
> inlen
+ 4)
303 RAND_pseudo_bytes(out
+ 4 + inlen
, olen
- 4 - inlen
);
305 if (!EVP_EncryptUpdate(ctx
, out
, &dummy
, out
, olen
)
306 || !EVP_EncryptUpdate(ctx
, out
, &dummy
, out
, olen
))
315 /* Encrypt/Decrypt content key in PWRI recipient info */
317 int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo
*cms
, CMS_RecipientInfo
*ri
,
320 CMS_EncryptedContentInfo
*ec
;
321 CMS_PasswordRecipientInfo
*pwri
;
322 const unsigned char *p
= NULL
;
325 X509_ALGOR
*algtmp
, *kekalg
= NULL
;
326 EVP_CIPHER_CTX kekctx
;
327 const EVP_CIPHER
*kekcipher
;
328 unsigned char *key
= NULL
;
331 ec
= cms
->d
.envelopedData
->encryptedContentInfo
;
334 EVP_CIPHER_CTX_init(&kekctx
);
337 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT
, CMS_R_NO_PASSWORD
);
340 algtmp
= pwri
->keyEncryptionAlgorithm
;
342 if (!algtmp
|| OBJ_obj2nid(algtmp
->algorithm
) != NID_id_alg_PWRI_KEK
) {
343 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT
,
344 CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM
);
348 if (algtmp
->parameter
->type
== V_ASN1_SEQUENCE
) {
349 p
= algtmp
->parameter
->value
.sequence
->data
;
350 plen
= algtmp
->parameter
->value
.sequence
->length
;
351 kekalg
= d2i_X509_ALGOR(NULL
, &p
, plen
);
353 if (kekalg
== NULL
) {
354 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT
,
355 CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER
);
359 kekcipher
= EVP_get_cipherbyobj(kekalg
->algorithm
);
362 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT
, CMS_R_UNKNOWN_CIPHER
);
366 /* Fixup cipher based on AlgorithmIdentifier to set IV etc */
367 if (!EVP_CipherInit_ex(&kekctx
, kekcipher
, NULL
, NULL
, NULL
, en_de
))
369 EVP_CIPHER_CTX_set_padding(&kekctx
, 0);
370 if (EVP_CIPHER_asn1_to_param(&kekctx
, kekalg
->parameter
) < 0) {
371 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT
,
372 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR
);
376 algtmp
= pwri
->keyDerivationAlgorithm
;
378 /* Finish password based key derivation to setup key in "ctx" */
380 if (EVP_PBE_CipherInit(algtmp
->algorithm
,
381 (char *)pwri
->pass
, pwri
->passlen
,
382 algtmp
->parameter
, &kekctx
, en_de
) < 0) {
383 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT
, ERR_R_EVP_LIB
);
387 /* Finally wrap/unwrap the key */
391 if (!kek_wrap_key(NULL
, &keylen
, ec
->key
, ec
->keylen
, &kekctx
))
394 key
= OPENSSL_malloc(keylen
);
399 if (!kek_wrap_key(key
, &keylen
, ec
->key
, ec
->keylen
, &kekctx
))
401 pwri
->encryptedKey
->data
= key
;
402 pwri
->encryptedKey
->length
= keylen
;
404 key
= OPENSSL_malloc(pwri
->encryptedKey
->length
);
407 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT
, ERR_R_MALLOC_FAILURE
);
410 if (!kek_unwrap_key(key
, &keylen
,
411 pwri
->encryptedKey
->data
,
412 pwri
->encryptedKey
->length
, &kekctx
)) {
413 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT
, CMS_R_UNWRAP_FAILURE
);
426 EVP_CIPHER_CTX_cleanup(&kekctx
);
430 X509_ALGOR_free(kekalg
);