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