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