xref: /freebsd/crypto/openssl/crypto/cms/cms_pwri.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1 /*
2  * Copyright 2009-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include "internal/cryptlib.h"
11 #include <openssl/asn1t.h>
12 #include <openssl/pem.h>
13 #include <openssl/x509v3.h>
14 #include <openssl/err.h>
15 #include <openssl/cms.h>
16 #include <openssl/rand.h>
17 #include <openssl/aes.h>
18 #include "internal/sizes.h"
19 #include "crypto/asn1.h"
20 #include "cms_local.h"
21 
CMS_RecipientInfo_set0_password(CMS_RecipientInfo * ri,unsigned char * pass,ossl_ssize_t passlen)22 int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
23                                     unsigned char *pass, ossl_ssize_t passlen)
24 {
25     CMS_PasswordRecipientInfo *pwri;
26     if (ri->type != CMS_RECIPINFO_PASS) {
27         ERR_raise(ERR_LIB_CMS, CMS_R_NOT_PWRI);
28         return 0;
29     }
30 
31     pwri = ri->d.pwri;
32     pwri->pass = pass;
33     if (pass && passlen < 0)
34         passlen = strlen((char *)pass);
35     pwri->passlen = passlen;
36     return 1;
37 }
38 
CMS_add0_recipient_password(CMS_ContentInfo * cms,int iter,int wrap_nid,int pbe_nid,unsigned char * pass,ossl_ssize_t passlen,const EVP_CIPHER * kekciph)39 CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
40                                                int iter, int wrap_nid,
41                                                int pbe_nid,
42                                                unsigned char *pass,
43                                                ossl_ssize_t passlen,
44                                                const EVP_CIPHER *kekciph)
45 {
46     STACK_OF(CMS_RecipientInfo) *ris;
47     CMS_RecipientInfo *ri = NULL;
48     CMS_EncryptedContentInfo *ec;
49     CMS_PasswordRecipientInfo *pwri;
50     EVP_CIPHER_CTX *ctx = NULL;
51     X509_ALGOR *encalg = NULL;
52     unsigned char iv[EVP_MAX_IV_LENGTH];
53     int ivlen;
54     const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms);
55 
56     ec = ossl_cms_get0_env_enc_content(cms);
57     if (ec == NULL)
58         return NULL;
59     ris = CMS_get0_RecipientInfos(cms);
60     if (ris == NULL)
61         return NULL;
62 
63     if (wrap_nid <= 0)
64         wrap_nid = NID_id_alg_PWRI_KEK;
65 
66     if (pbe_nid <= 0)
67         pbe_nid = NID_id_pbkdf2;
68 
69     /* Get from enveloped data */
70     if (kekciph == NULL)
71         kekciph = ec->cipher;
72 
73     if (kekciph == NULL) {
74         ERR_raise(ERR_LIB_CMS, CMS_R_NO_CIPHER);
75         return NULL;
76     }
77     if (wrap_nid != NID_id_alg_PWRI_KEK) {
78         ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
79         return NULL;
80     }
81 
82     /* Setup algorithm identifier for cipher */
83     encalg = X509_ALGOR_new();
84     if (encalg == NULL) {
85         ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
86         goto err;
87     }
88     ctx = EVP_CIPHER_CTX_new();
89     if (ctx == NULL) {
90         ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
91         goto err;
92     }
93 
94     if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) {
95         ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
96         goto err;
97     }
98 
99     ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);
100     if (ivlen < 0) {
101         ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
102         goto err;
103     }
104 
105     if (ivlen > 0) {
106         if (RAND_bytes_ex(ossl_cms_ctx_get0_libctx(cms_ctx), iv, ivlen, 0) <= 0)
107             goto err;
108         if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) {
109             ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
110             goto err;
111         }
112         encalg->parameter = ASN1_TYPE_new();
113         if (!encalg->parameter) {
114             ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
115             goto err;
116         }
117         if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) {
118             ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
119             goto err;
120         }
121     }
122 
123     encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_get_type(ctx));
124 
125     EVP_CIPHER_CTX_free(ctx);
126     ctx = NULL;
127 
128     /* Initialize recipient info */
129     ri = M_ASN1_new_of(CMS_RecipientInfo);
130     if (ri == NULL) {
131         ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
132         goto err;
133     }
134 
135     ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo);
136     if (ri->d.pwri == NULL) {
137         ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
138         goto err;
139     }
140     ri->type = CMS_RECIPINFO_PASS;
141 
142     pwri = ri->d.pwri;
143     pwri->cms_ctx = cms_ctx;
144     /* Since this is overwritten, free up empty structure already there */
145     X509_ALGOR_free(pwri->keyEncryptionAlgorithm);
146     pwri->keyEncryptionAlgorithm = X509_ALGOR_new();
147     if (pwri->keyEncryptionAlgorithm == NULL) {
148         ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
149         goto err;
150     }
151     pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
152     pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
153     if (pwri->keyEncryptionAlgorithm->parameter == NULL) {
154         ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
155         goto err;
156     }
157 
158     if (!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR),
159                         &pwri->keyEncryptionAlgorithm->parameter->
160                         value.sequence)) {
161         ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
162         goto err;
163     }
164     pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;
165 
166     X509_ALGOR_free(encalg);
167     encalg = NULL;
168 
169     /* Setup PBE algorithm */
170 
171     pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set_ex(iter, NULL, 0, -1, -1,
172                                                        cms_ctx->libctx);
173 
174     if (pwri->keyDerivationAlgorithm == NULL)
175         goto err;
176 
177     CMS_RecipientInfo_set0_password(ri, pass, passlen);
178     pwri->version = 0;
179 
180     if (!sk_CMS_RecipientInfo_push(ris, ri)) {
181         ERR_raise(ERR_LIB_CMS, ERR_R_CRYPTO_LIB);
182         goto err;
183     }
184 
185     return ri;
186 
187  err:
188     EVP_CIPHER_CTX_free(ctx);
189     if (ri)
190         M_ASN1_free_of(ri, CMS_RecipientInfo);
191     X509_ALGOR_free(encalg);
192     return NULL;
193 
194 }
195 
196 /*
197  * This is an implementation of the key wrapping mechanism in RFC3211, at
198  * some point this should go into EVP.
199  */
200 
kek_unwrap_key(unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen,EVP_CIPHER_CTX * ctx)201 static int kek_unwrap_key(unsigned char *out, size_t *outlen,
202                           const unsigned char *in, size_t inlen,
203                           EVP_CIPHER_CTX *ctx)
204 {
205     size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx);
206     unsigned char *tmp;
207     int outl, rv = 0;
208 
209     if (blocklen == 0)
210         return 0;
211 
212     if (inlen < 2 * blocklen) {
213         /* too small */
214         return 0;
215     }
216     if (inlen % blocklen) {
217         /* Invalid size */
218         return 0;
219     }
220     if ((tmp = OPENSSL_malloc(inlen)) == NULL)
221         return 0;
222     /* setup IV by decrypting last two blocks */
223     if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
224                            in + inlen - 2 * blocklen, blocklen * 2)
225         /*
226          * Do a decrypt of last decrypted block to set IV to correct value
227          * output it to start of buffer so we don't corrupt decrypted block
228          * this works because buffer is at least two block lengths long.
229          */
230         || !EVP_DecryptUpdate(ctx, tmp, &outl,
231                               tmp + inlen - blocklen, blocklen)
232         /* Can now decrypt first n - 1 blocks */
233         || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen)
234 
235         /* Reset IV to original value */
236         || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL)
237         /* Decrypt again */
238         || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen))
239         goto err;
240     /* Check check bytes */
241     if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) {
242         /* Check byte failure */
243         goto err;
244     }
245     if (inlen < (size_t)(tmp[0] - 4)) {
246         /* Invalid length value */
247         goto err;
248     }
249     *outlen = (size_t)tmp[0];
250     memcpy(out, tmp + 4, *outlen);
251     rv = 1;
252  err:
253     OPENSSL_clear_free(tmp, inlen);
254     return rv;
255 
256 }
257 
kek_wrap_key(unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen,EVP_CIPHER_CTX * ctx,const CMS_CTX * cms_ctx)258 static int kek_wrap_key(unsigned char *out, size_t *outlen,
259                         const unsigned char *in, size_t inlen,
260                         EVP_CIPHER_CTX *ctx, const CMS_CTX *cms_ctx)
261 {
262     size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx);
263     size_t olen;
264     int dummy;
265 
266     if (blocklen == 0)
267         return 0;
268 
269     /*
270      * First decide length of output buffer: need header and round up to
271      * multiple of block length.
272      */
273     olen = (inlen + 4 + blocklen - 1) / blocklen;
274     olen *= blocklen;
275     if (olen < 2 * blocklen) {
276         /* Key too small */
277         return 0;
278     }
279     if (inlen > 0xFF) {
280         /* Key too large */
281         return 0;
282     }
283     if (out) {
284         /* Set header */
285         out[0] = (unsigned char)inlen;
286         out[1] = in[0] ^ 0xFF;
287         out[2] = in[1] ^ 0xFF;
288         out[3] = in[2] ^ 0xFF;
289         memcpy(out + 4, in, inlen);
290         /* Add random padding to end */
291         if (olen > inlen + 4
292             && RAND_bytes_ex(ossl_cms_ctx_get0_libctx(cms_ctx), out + 4 + inlen,
293                              olen - 4 - inlen, 0) <= 0)
294             return 0;
295         /* Encrypt twice */
296         if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen)
297             || !EVP_EncryptUpdate(ctx, out, &dummy, out, olen))
298             return 0;
299     }
300 
301     *outlen = olen;
302 
303     return 1;
304 }
305 
306 /* Encrypt/Decrypt content key in PWRI recipient info */
307 
ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo * cms,CMS_RecipientInfo * ri,int en_de)308 int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms,
309                                       CMS_RecipientInfo *ri, int en_de)
310 {
311     CMS_EncryptedContentInfo *ec;
312     CMS_PasswordRecipientInfo *pwri;
313     int r = 0;
314     X509_ALGOR *algtmp, *kekalg = NULL;
315     EVP_CIPHER_CTX *kekctx = NULL;
316     char name[OSSL_MAX_NAME_SIZE];
317     EVP_CIPHER *kekcipher;
318     unsigned char *key = NULL;
319     size_t keylen;
320     const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms);
321 
322     ec = ossl_cms_get0_env_enc_content(cms);
323 
324     pwri = ri->d.pwri;
325 
326     if (pwri->pass == NULL) {
327         ERR_raise(ERR_LIB_CMS, CMS_R_NO_PASSWORD);
328         return 0;
329     }
330     algtmp = pwri->keyEncryptionAlgorithm;
331 
332     if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) {
333         ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
334         return 0;
335     }
336 
337     kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),
338                                        algtmp->parameter);
339 
340     if (kekalg == NULL) {
341         ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);
342         return 0;
343     }
344 
345     OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0);
346     kekcipher = EVP_CIPHER_fetch(ossl_cms_ctx_get0_libctx(cms_ctx), name,
347                                  ossl_cms_ctx_get0_propq(cms_ctx));
348 
349     if (kekcipher == NULL) {
350         ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER);
351         goto err;
352     }
353 
354     kekctx = EVP_CIPHER_CTX_new();
355     if (kekctx == NULL) {
356         ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
357         goto err;
358     }
359     /* Fixup cipher based on AlgorithmIdentifier to set IV etc */
360     if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de))
361         goto err;
362     EVP_CIPHER_CTX_set_padding(kekctx, 0);
363     if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) {
364         ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
365         goto err;
366     }
367 
368     algtmp = pwri->keyDerivationAlgorithm;
369 
370     /* Finish password based key derivation to setup key in "ctx" */
371 
372     if (EVP_PBE_CipherInit_ex(algtmp->algorithm,
373                               (char *)pwri->pass, pwri->passlen,
374                               algtmp->parameter, kekctx, en_de,
375                               cms_ctx->libctx, cms_ctx->propq) < 0) {
376         ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB);
377         goto err;
378     }
379 
380     /* Finally wrap/unwrap the key */
381 
382     if (en_de) {
383 
384         if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx, cms_ctx))
385             goto err;
386 
387         key = OPENSSL_malloc(keylen);
388 
389         if (key == NULL)
390             goto err;
391 
392         if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx, cms_ctx))
393             goto err;
394         pwri->encryptedKey->data = key;
395         pwri->encryptedKey->length = keylen;
396     } else {
397         key = OPENSSL_malloc(pwri->encryptedKey->length);
398         if (key == NULL)
399             goto err;
400         if (!kek_unwrap_key(key, &keylen,
401                             pwri->encryptedKey->data,
402                             pwri->encryptedKey->length, kekctx)) {
403             ERR_raise(ERR_LIB_CMS, CMS_R_UNWRAP_FAILURE);
404             goto err;
405         }
406 
407         OPENSSL_clear_free(ec->key, ec->keylen);
408         ec->key = key;
409         ec->keylen = keylen;
410 
411     }
412 
413     r = 1;
414 
415  err:
416     EVP_CIPHER_free(kekcipher);
417     EVP_CIPHER_CTX_free(kekctx);
418 
419     if (!r)
420         OPENSSL_free(key);
421     X509_ALGOR_free(kekalg);
422 
423     return r;
424 
425 }
426