cms_pwri.c revision 279264
1/* crypto/cms/cms_pwri.c */
2/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3 * project.
4 */
5/* ====================================================================
6 * Copyright (c) 2009 The OpenSSL Project.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in
17 *    the documentation and/or other materials provided with the
18 *    distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 *    software must display the following acknowledgment:
22 *    "This product includes software developed by the OpenSSL Project
23 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26 *    endorse or promote products derived from this software without
27 *    prior written permission. For written permission, please contact
28 *    licensing@OpenSSL.org.
29 *
30 * 5. Products derived from this software may not be called "OpenSSL"
31 *    nor may "OpenSSL" appear in their names without prior written
32 *    permission of the OpenSSL Project.
33 *
34 * 6. Redistributions of any form whatsoever must retain the following
35 *    acknowledgment:
36 *    "This product includes software developed by the OpenSSL Project
37 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 */
53
54#include "cryptlib.h"
55#include <openssl/asn1t.h>
56#include <openssl/pem.h>
57#include <openssl/x509v3.h>
58#include <openssl/err.h>
59#include <openssl/cms.h>
60#include <openssl/rand.h>
61#include <openssl/aes.h>
62#include "cms_lcl.h"
63#include "asn1_locl.h"
64
65int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
66				unsigned char *pass, ossl_ssize_t passlen)
67	{
68	CMS_PasswordRecipientInfo *pwri;
69	if (ri->type != CMS_RECIPINFO_PASS)
70		{
71		CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD, CMS_R_NOT_PWRI);
72		return 0;
73		}
74
75	pwri = ri->d.pwri;
76	pwri->pass = pass;
77	if (pass && passlen < 0)
78		passlen = strlen((char *)pass);
79	pwri->passlen = passlen;
80	return 1;
81	}
82
83CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
84					int iter, int wrap_nid, int pbe_nid,
85					unsigned char *pass,
86					ossl_ssize_t passlen,
87					const EVP_CIPHER *kekciph)
88	{
89	CMS_RecipientInfo *ri = NULL;
90	CMS_EnvelopedData *env;
91	CMS_PasswordRecipientInfo *pwri;
92	EVP_CIPHER_CTX ctx;
93	X509_ALGOR *encalg = NULL;
94	unsigned char iv[EVP_MAX_IV_LENGTH];
95	int ivlen;
96
97	env = cms_get0_enveloped(cms);
98	if (!env)
99		return NULL;
100
101	if (wrap_nid <= 0)
102		wrap_nid = NID_id_alg_PWRI_KEK;
103
104	if (pbe_nid <= 0)
105		pbe_nid = NID_id_pbkdf2;
106
107	/* Get from enveloped data */
108	if (kekciph == NULL)
109		kekciph = env->encryptedContentInfo->cipher;
110
111	if (kekciph == NULL)
112		{
113		CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_NO_CIPHER);
114		return NULL;
115		}
116	if (wrap_nid != NID_id_alg_PWRI_KEK)
117		{
118		CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
119				CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
120		return NULL;
121		}
122
123	/* Setup algorithm identifier for cipher */
124	encalg = X509_ALGOR_new();
125	EVP_CIPHER_CTX_init(&ctx);
126
127	if (EVP_EncryptInit_ex(&ctx, kekciph, NULL, NULL, NULL) <= 0)
128		{
129		CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB);
130		goto err;
131		}
132
133	ivlen = EVP_CIPHER_CTX_iv_length(&ctx);
134
135	if (ivlen > 0)
136		{
137		if (RAND_pseudo_bytes(iv, ivlen) <= 0)
138			goto err;
139		if (EVP_EncryptInit_ex(&ctx, NULL, NULL, NULL, iv) <= 0)
140			{
141			CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
142							ERR_R_EVP_LIB);
143			goto err;
144			}
145		encalg->parameter = ASN1_TYPE_new();
146		if (!encalg->parameter)
147			{
148			CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
149							ERR_R_MALLOC_FAILURE);
150			goto err;
151			}
152		if (EVP_CIPHER_param_to_asn1(&ctx, encalg->parameter) <= 0)
153			{
154			CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
155				CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
156			goto err;
157			}
158		}
159
160
161	encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(&ctx));
162
163	EVP_CIPHER_CTX_cleanup(&ctx);
164
165	/* Initialize recipient info */
166	ri = M_ASN1_new_of(CMS_RecipientInfo);
167	if (!ri)
168		goto merr;
169
170	ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo);
171	if (!ri->d.pwri)
172		goto merr;
173	ri->type = CMS_RECIPINFO_PASS;
174
175	pwri = ri->d.pwri;
176	/* Since this is overwritten, free up empty structure already there */
177	X509_ALGOR_free(pwri->keyEncryptionAlgorithm);
178	pwri->keyEncryptionAlgorithm = X509_ALGOR_new();
179	if (!pwri->keyEncryptionAlgorithm)
180		goto merr;
181	pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
182	pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
183	if (!pwri->keyEncryptionAlgorithm->parameter)
184		goto merr;
185
186        if(!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR),
187	    &pwri->keyEncryptionAlgorithm->parameter->value.sequence))
188		goto merr;
189        pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;
190
191	X509_ALGOR_free(encalg);
192	encalg = NULL;
193
194	/* Setup PBE algorithm */
195
196	pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1);
197
198	if (!pwri->keyDerivationAlgorithm)
199		goto err;
200
201	CMS_RecipientInfo_set0_password(ri, pass, passlen);
202	pwri->version = 0;
203
204	if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
205		goto merr;
206
207	return ri;
208
209	merr:
210	CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE);
211	err:
212	EVP_CIPHER_CTX_cleanup(&ctx);
213	if (ri)
214		M_ASN1_free_of(ri, CMS_RecipientInfo);
215	if (encalg)
216		X509_ALGOR_free(encalg);
217	return NULL;
218
219	}
220
221/* This is an implementation of the key wrapping mechanism in RFC3211,
222 * at some point this should go into EVP.
223 */
224
225static int kek_unwrap_key(unsigned char *out, size_t *outlen,
226		const unsigned char *in, size_t inlen, EVP_CIPHER_CTX *ctx)
227	{
228	size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
229	unsigned char *tmp;
230	int outl, rv = 0;
231	if (inlen < 2 * blocklen)
232		{
233		/* too small */
234		return 0;
235		}
236	if (inlen % blocklen)
237		{
238		/* Invalid size */
239		return 0;
240		}
241	tmp = OPENSSL_malloc(inlen);
242	/* setup IV by decrypting last two blocks */
243	EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
244				in  + inlen - 2 * blocklen, blocklen * 2);
245	/* Do a decrypt of last decrypted block to set IV to correct value
246	 * output it to start of buffer so we don't corrupt decrypted block
247	 * this works because buffer is at least two block lengths long.
248	 */
249	EVP_DecryptUpdate(ctx, tmp, &outl,
250				tmp  + inlen - blocklen, blocklen);
251	/* Can now decrypt first n - 1 blocks */
252	EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen);
253
254	/* Reset IV to original value */
255	EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL);
256	/* Decrypt again */
257	EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen);
258	/* Check check bytes */
259	if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff)
260		{
261		/* Check byte failure */
262		goto err;
263		}
264	if (inlen < (size_t)(tmp[0] - 4 ))
265		{
266		/* Invalid length value */
267		goto err;
268		}
269	*outlen = (size_t)tmp[0];
270	memcpy(out, tmp + 4, *outlen);
271	rv = 1;
272	err:
273	OPENSSL_cleanse(tmp, inlen);
274	OPENSSL_free(tmp);
275	return rv;
276
277	}
278
279static int kek_wrap_key(unsigned char *out, size_t *outlen,
280		const unsigned char *in, size_t inlen, EVP_CIPHER_CTX *ctx)
281	{
282	size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
283	size_t olen;
284	int dummy;
285	/* First decide length of output buffer: need header and round up to
286	 * multiple of block length.
287	 */
288	olen = (inlen + 4 + blocklen - 1)/blocklen;
289	olen *= blocklen;
290	if (olen < 2 * blocklen)
291		{
292		/* Key too small */
293		return 0;
294		}
295	if (inlen > 0xFF)
296		{
297		/* Key too large */
298		return 0;
299		}
300	if (out)
301		{
302		/* Set header */
303		out[0] = (unsigned char)inlen;
304		out[1] = in[0] ^ 0xFF;
305		out[2] = in[1] ^ 0xFF;
306		out[3] = in[2] ^ 0xFF;
307		memcpy(out + 4, in, inlen);
308		/* Add random padding to end */
309		if (olen > inlen + 4)
310			RAND_pseudo_bytes(out + 4 + inlen, olen - 4 - inlen);
311		/* Encrypt twice */
312		EVP_EncryptUpdate(ctx, out, &dummy, out, olen);
313		EVP_EncryptUpdate(ctx, out, &dummy, out, olen);
314		}
315
316	*outlen = olen;
317
318	return 1;
319	}
320
321/* Encrypt/Decrypt content key in PWRI recipient info */
322
323int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
324							int en_de)
325	{
326	CMS_EncryptedContentInfo *ec;
327	CMS_PasswordRecipientInfo *pwri;
328	const unsigned char *p = NULL;
329	int plen;
330	int r = 0;
331	X509_ALGOR *algtmp, *kekalg = NULL;
332	EVP_CIPHER_CTX kekctx;
333	const EVP_CIPHER *kekcipher;
334	unsigned char *key = NULL;
335	size_t keylen;
336
337	ec = cms->d.envelopedData->encryptedContentInfo;
338
339	pwri = ri->d.pwri;
340	EVP_CIPHER_CTX_init(&kekctx);
341
342	if (!pwri->pass)
343		{
344		CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_NO_PASSWORD);
345		return 0;
346		}
347	algtmp = pwri->keyEncryptionAlgorithm;
348
349	if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK)
350		{
351		CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
352				CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
353		return 0;
354		}
355
356	if (algtmp->parameter->type == V_ASN1_SEQUENCE)
357		{
358		p = algtmp->parameter->value.sequence->data;
359		plen = algtmp->parameter->value.sequence->length;
360		kekalg = d2i_X509_ALGOR(NULL, &p, plen);
361		}
362	if (kekalg == NULL)
363		{
364		CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
365				CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);
366		return 0;
367		}
368
369	kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
370
371	if(!kekcipher)
372		{
373		CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
374				CMS_R_UNKNOWN_CIPHER);
375		goto err;
376		}
377
378	/* Fixup cipher based on AlgorithmIdentifier to set IV etc */
379	if (!EVP_CipherInit_ex(&kekctx, kekcipher, NULL, NULL, NULL, en_de))
380		goto err;
381	EVP_CIPHER_CTX_set_padding(&kekctx, 0);
382	if(EVP_CIPHER_asn1_to_param(&kekctx, kekalg->parameter) < 0)
383		{
384		CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
385				CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
386		goto err;
387		}
388
389	algtmp = pwri->keyDerivationAlgorithm;
390
391	/* Finish password based key derivation to setup key in "ctx" */
392
393	if (EVP_PBE_CipherInit(algtmp->algorithm,
394				(char *)pwri->pass, pwri->passlen,
395				algtmp->parameter, &kekctx, en_de) < 0)
396		{
397		CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_EVP_LIB);
398		goto err;
399		}
400
401	/* Finally wrap/unwrap the key */
402
403	if (en_de)
404		{
405
406		if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, &kekctx))
407			goto err;
408
409		key = OPENSSL_malloc(keylen);
410
411		if (!key)
412			goto err;
413
414		if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, &kekctx))
415			goto err;
416		pwri->encryptedKey->data = key;
417		pwri->encryptedKey->length = keylen;
418		}
419	else
420		{
421		key = OPENSSL_malloc(pwri->encryptedKey->length);
422
423		if (!key)
424			{
425			CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
426							ERR_R_MALLOC_FAILURE);
427			goto err;
428			}
429		if (!kek_unwrap_key(key, &keylen,
430					pwri->encryptedKey->data,
431					pwri->encryptedKey->length, &kekctx))
432			{
433			CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
434							CMS_R_UNWRAP_FAILURE);
435			goto err;
436			}
437
438		ec->key = key;
439		ec->keylen = keylen;
440
441		}
442
443	r = 1;
444
445	err:
446
447	EVP_CIPHER_CTX_cleanup(&kekctx);
448
449	if (!r && key)
450		OPENSSL_free(key);
451	X509_ALGOR_free(kekalg);
452
453	return r;
454
455	}
456