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