xref: /openbsd/lib/libcrypto/cms/cms_pwri.c (revision 723bccac)
1 /* $OpenBSD: cms_pwri.c,v 1.31 2024/01/14 18:40:24 tb Exp $ */
2 /*
3  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4  * project.
5  */
6 /* ====================================================================
7  * Copyright (c) 2009 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 <sys/types.h>
56 
57 #include <stdlib.h>
58 #include <string.h>
59 
60 #include <openssl/asn1.h>
61 #include <openssl/err.h>
62 #include <openssl/evp.h>
63 #include <openssl/cms.h>
64 #include <openssl/objects.h>
65 #include <openssl/x509.h>
66 
67 #include "cms_local.h"
68 #include "evp_local.h"
69 #include "x509_local.h"
70 
71 int
CMS_RecipientInfo_set0_password(CMS_RecipientInfo * ri,unsigned char * pass,ssize_t passlen)72 CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri, unsigned char *pass,
73     ssize_t passlen)
74 {
75 	CMS_PasswordRecipientInfo *pwri;
76 
77 	if (ri->type != CMS_RECIPINFO_PASS) {
78 		CMSerror(CMS_R_NOT_PWRI);
79 		return 0;
80 	}
81 
82 	pwri = ri->d.pwri;
83 	pwri->pass = pass;
84 	if (pass && passlen < 0)
85 		passlen = strlen((char *)pass);
86 	pwri->passlen = passlen;
87 
88 	return 1;
89 }
90 LCRYPTO_ALIAS(CMS_RecipientInfo_set0_password);
91 
92 CMS_RecipientInfo *
CMS_add0_recipient_password(CMS_ContentInfo * cms,int iter,int wrap_nid,int pbe_nid,unsigned char * pass,ssize_t passlen,const EVP_CIPHER * kekciph)93 CMS_add0_recipient_password(CMS_ContentInfo *cms, int iter, int wrap_nid,
94     int pbe_nid, unsigned char *pass, ssize_t passlen,
95     const EVP_CIPHER *kekciph)
96 {
97 	CMS_RecipientInfo *ri = NULL;
98 	CMS_EnvelopedData *env;
99 	CMS_PasswordRecipientInfo *pwri;
100 	EVP_CIPHER_CTX *ctx = NULL;
101 	X509_ALGOR *encalg = NULL;
102 	unsigned char iv[EVP_MAX_IV_LENGTH];
103 	int ivlen;
104 
105 	env = cms_get0_enveloped(cms);
106 	if (!env)
107 		return NULL;
108 
109 	if (wrap_nid <= 0)
110 		wrap_nid = NID_id_alg_PWRI_KEK;
111 
112 	if (pbe_nid <= 0)
113 		pbe_nid = NID_id_pbkdf2;
114 
115 	/* Get from enveloped data */
116 	if (kekciph == NULL)
117 		kekciph = env->encryptedContentInfo->cipher;
118 
119 	if (kekciph == NULL) {
120 		CMSerror(CMS_R_NO_CIPHER);
121 		return NULL;
122 	}
123 	if (wrap_nid != NID_id_alg_PWRI_KEK) {
124 		CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
125 		return NULL;
126 	}
127 
128 	/* Setup algorithm identifier for cipher */
129 	encalg = X509_ALGOR_new();
130 	if (encalg == NULL) {
131 		goto merr;
132 	}
133 
134 	if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
135 		goto merr;
136 
137 	if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) {
138 		CMSerror(ERR_R_EVP_LIB);
139 		goto err;
140 	}
141 
142 	ivlen = EVP_CIPHER_CTX_iv_length(ctx);
143 
144 	if (ivlen > 0) {
145 		arc4random_buf(iv, ivlen);
146 		if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) {
147 			CMSerror(ERR_R_EVP_LIB);
148 			goto err;
149 		}
150 		encalg->parameter = ASN1_TYPE_new();
151 		if (!encalg->parameter) {
152 			CMSerror(ERR_R_MALLOC_FAILURE);
153 			goto err;
154 		}
155 		if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) {
156 			CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
157 			goto err;
158 		}
159 	}
160 
161 	encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
162 
163 	EVP_CIPHER_CTX_free(ctx);
164 	ctx = NULL;
165 
166 	/* Initialize recipient info */
167 	ri = (CMS_RecipientInfo *)ASN1_item_new(&CMS_RecipientInfo_it);
168 	if (ri == NULL)
169 		goto merr;
170 
171 	ri->d.pwri = (CMS_PasswordRecipientInfo *)ASN1_item_new(&CMS_PasswordRecipientInfo_it);
172 	if (ri->d.pwri == NULL)
173 		goto merr;
174 	ri->type = CMS_RECIPINFO_PASS;
175 
176 	pwri = ri->d.pwri;
177 	/* Since this is overwritten, free up empty structure already there */
178 	X509_ALGOR_free(pwri->keyEncryptionAlgorithm);
179 	pwri->keyEncryptionAlgorithm = X509_ALGOR_new();
180 	if (pwri->keyEncryptionAlgorithm == NULL)
181 		goto merr;
182 	pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
183 	pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
184 	if (pwri->keyEncryptionAlgorithm->parameter == NULL)
185 		goto merr;
186 
187 	if (!ASN1_item_pack(encalg, &X509_ALGOR_it,
188 	    &pwri->keyEncryptionAlgorithm->parameter->value.sequence))
189 		 goto merr;
190 	pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;
191 
192 	X509_ALGOR_free(encalg);
193 	encalg = NULL;
194 
195 	/* Setup PBE algorithm */
196 
197 	pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1);
198 
199 	if (!pwri->keyDerivationAlgorithm)
200 		goto err;
201 
202 	CMS_RecipientInfo_set0_password(ri, pass, passlen);
203 	pwri->version = 0;
204 
205 	if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
206 		goto merr;
207 
208 	return ri;
209 
210  merr:
211 	CMSerror(ERR_R_MALLOC_FAILURE);
212  err:
213 	EVP_CIPHER_CTX_free(ctx);
214 	if (ri)
215 		ASN1_item_free((ASN1_VALUE *)ri, &CMS_RecipientInfo_it);
216 	X509_ALGOR_free(encalg);
217 
218 	return NULL;
219 }
220 LCRYPTO_ALIAS(CMS_add0_recipient_password);
221 
222 /*
223  * This is an implementation of the key wrapping mechanism in RFC3211, at
224  * some point this should go into EVP.
225  */
226 
227 static int
kek_unwrap_key(unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen,EVP_CIPHER_CTX * ctx)228 kek_unwrap_key(unsigned char *out, size_t *outlen, const unsigned char *in,
229     size_t inlen, EVP_CIPHER_CTX *ctx)
230 {
231 	size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
232 	unsigned char *tmp;
233 	int outl, rv = 0;
234 
235 	if (inlen < 2 * blocklen) {
236 		/* too small */
237 		return 0;
238 	}
239 	if (inlen % blocklen) {
240 		/* Invalid size */
241 		return 0;
242 	}
243 	if ((tmp = malloc(inlen)) == NULL) {
244 		CMSerror(ERR_R_MALLOC_FAILURE);
245 		return 0;
246 	}
247 
248 	/* setup IV by decrypting last two blocks */
249 	if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
250 	    in + inlen - 2 * blocklen, blocklen * 2)
251 		/*
252 		 * Do a decrypt of last decrypted block to set IV to correct value
253 		 * output it to start of buffer so we don't corrupt decrypted block
254 		 * this works because buffer is at least two block lengths long.
255 		 */
256 		|| !EVP_DecryptUpdate(ctx, tmp, &outl, tmp + inlen - blocklen, blocklen)
257 		/* Can now decrypt first n - 1 blocks */
258 		|| !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen)
259 
260 		/* Reset IV to original value */
261 		|| !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL)
262 		/* Decrypt again */
263 		|| !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen))
264 		goto err;
265 	/* Check check bytes */
266 	if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) {
267 		/* Check byte failure */
268 		goto err;
269 	}
270 	if (inlen < (size_t)(tmp[0] - 4)) {
271 		/* Invalid length value */
272 		goto err;
273 	}
274 	*outlen = (size_t)tmp[0];
275 	memcpy(out, tmp + 4, *outlen);
276 	rv = 1;
277 
278  err:
279 	freezero(tmp, inlen);
280 
281 	return rv;
282 }
283 
284 static int
kek_wrap_key(unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen,EVP_CIPHER_CTX * ctx)285 kek_wrap_key(unsigned char *out, size_t *outlen, const unsigned char *in,
286     size_t inlen, EVP_CIPHER_CTX *ctx)
287 {
288 	size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
289 	size_t olen;
290 	int dummy;
291 
292 	/*
293 	 * First decide length of output buffer: need header and round up to
294 	 * multiple of block length.
295 	 */
296 	olen = (inlen + 4 + blocklen - 1) / blocklen;
297 	olen *= blocklen;
298 	if (olen < 2 * blocklen) {
299 		/* Key too small */
300 		return 0;
301 	}
302 	if (inlen > 0xFF) {
303 		/* Key too large */
304 		return 0;
305 	}
306 	if (out) {
307 		/* Set header */
308 		out[0] = (unsigned char)inlen;
309 		out[1] = in[0] ^ 0xFF;
310 		out[2] = in[1] ^ 0xFF;
311 		out[3] = in[2] ^ 0xFF;
312 		memcpy(out + 4, in, inlen);
313 		/* Add random padding to end */
314 		if (olen > inlen + 4)
315 			arc4random_buf(out + 4 + inlen, olen - 4 - inlen);
316 		/* Encrypt twice */
317 		if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen) ||
318 		    !EVP_EncryptUpdate(ctx, out, &dummy, out, olen))
319 			return 0;
320 	}
321 
322 	*outlen = olen;
323 
324 	return 1;
325 }
326 
327 /* Encrypt/Decrypt content key in PWRI recipient info */
328 
329 int
cms_RecipientInfo_pwri_crypt(CMS_ContentInfo * cms,CMS_RecipientInfo * ri,int en_de)330 cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
331     int en_de)
332 {
333 	CMS_EncryptedContentInfo *ec;
334 	CMS_PasswordRecipientInfo *pwri;
335 	int r = 0;
336 	X509_ALGOR *algtmp, *kekalg = NULL;
337 	EVP_CIPHER_CTX *kekctx = NULL;
338 	const EVP_CIPHER *kekcipher;
339 	unsigned char *key = NULL;
340 	size_t keylen;
341 
342 	ec = cms->d.envelopedData->encryptedContentInfo;
343 
344 	pwri = ri->d.pwri;
345 
346 	if (!pwri->pass) {
347 		CMSerror(CMS_R_NO_PASSWORD);
348 		return 0;
349 	}
350 	algtmp = pwri->keyEncryptionAlgorithm;
351 
352 	if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) {
353 		CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
354 		return 0;
355 	}
356 
357 	if (algtmp->parameter != NULL &&
358 	    algtmp->parameter->type == V_ASN1_SEQUENCE &&
359 	    algtmp->parameter->value.sequence != NULL)
360 		kekalg = ASN1_item_unpack(algtmp->parameter->value.sequence,
361 		    &X509_ALGOR_it);
362 
363 	if (kekalg == NULL) {
364 		CMSerror(CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);
365 		return 0;
366 	}
367 
368 	kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
369 	if (!kekcipher) {
370 		CMSerror(CMS_R_UNKNOWN_CIPHER);
371 		return 0;
372 	}
373 
374 	kekctx = EVP_CIPHER_CTX_new();
375 	if (kekctx == NULL) {
376 		CMSerror(ERR_R_MALLOC_FAILURE);
377 		return 0;
378 	}
379 	/* Fixup cipher based on AlgorithmIdentifier to set IV etc */
380 	if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de))
381 		goto err;
382 	EVP_CIPHER_CTX_set_padding(kekctx, 0);
383 	if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) {
384 		CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
385 		goto err;
386 	}
387 
388 	algtmp = pwri->keyDerivationAlgorithm;
389 
390 	/* Finish password based key derivation to setup key in "ctx" */
391 
392 	if (EVP_PBE_CipherInit(algtmp->algorithm, (char *)pwri->pass,
393 	    pwri->passlen, algtmp->parameter, kekctx, en_de) < 0) {
394 		CMSerror(ERR_R_EVP_LIB);
395 		goto err;
396 	}
397 
398 	/* Finally wrap/unwrap the key */
399 
400 	if (en_de) {
401 		if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx))
402 			goto err;
403 
404 		key = malloc(keylen);
405 		if (key == NULL)
406 			goto err;
407 
408 		if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx))
409 			goto err;
410 		pwri->encryptedKey->data = key;
411 		pwri->encryptedKey->length = keylen;
412 	} else {
413 		key = malloc(pwri->encryptedKey->length);
414 		if (key == NULL) {
415 			CMSerror(ERR_R_MALLOC_FAILURE);
416 			goto err;
417 		}
418 		if (!kek_unwrap_key(key, &keylen, pwri->encryptedKey->data,
419 		    pwri->encryptedKey->length, kekctx)) {
420 			CMSerror(CMS_R_UNWRAP_FAILURE);
421 			goto err;
422 		}
423 
424 		freezero(ec->key, ec->keylen);
425 		ec->key = key;
426 		ec->keylen = keylen;
427 	}
428 
429 	r = 1;
430 
431  err:
432 	EVP_CIPHER_CTX_free(kekctx);
433 	if (!r)
434 		free(key);
435 	X509_ALGOR_free(kekalg);
436 
437 	return r;
438 }
439