xref: /dflybsd-src/crypto/libressl/crypto/cms/cms_enc.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: cms_enc.c,v 1.21 2022/01/20 10:58:35 inoguchi Exp $ */
2cca6fc52SDaniel Fojt /*
3cca6fc52SDaniel Fojt  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4cca6fc52SDaniel Fojt  * project.
5cca6fc52SDaniel Fojt  */
6cca6fc52SDaniel Fojt /* ====================================================================
7cca6fc52SDaniel Fojt  * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
8cca6fc52SDaniel Fojt  *
9cca6fc52SDaniel Fojt  * Redistribution and use in source and binary forms, with or without
10cca6fc52SDaniel Fojt  * modification, are permitted provided that the following conditions
11cca6fc52SDaniel Fojt  * are met:
12cca6fc52SDaniel Fojt  *
13cca6fc52SDaniel Fojt  * 1. Redistributions of source code must retain the above copyright
14cca6fc52SDaniel Fojt  *    notice, this list of conditions and the following disclaimer.
15cca6fc52SDaniel Fojt  *
16cca6fc52SDaniel Fojt  * 2. Redistributions in binary form must reproduce the above copyright
17cca6fc52SDaniel Fojt  *    notice, this list of conditions and the following disclaimer in
18cca6fc52SDaniel Fojt  *    the documentation and/or other materials provided with the
19cca6fc52SDaniel Fojt  *    distribution.
20cca6fc52SDaniel Fojt  *
21cca6fc52SDaniel Fojt  * 3. All advertising materials mentioning features or use of this
22cca6fc52SDaniel Fojt  *    software must display the following acknowledgment:
23cca6fc52SDaniel Fojt  *    "This product includes software developed by the OpenSSL Project
24cca6fc52SDaniel Fojt  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25cca6fc52SDaniel Fojt  *
26cca6fc52SDaniel Fojt  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27cca6fc52SDaniel Fojt  *    endorse or promote products derived from this software without
28cca6fc52SDaniel Fojt  *    prior written permission. For written permission, please contact
29cca6fc52SDaniel Fojt  *    licensing@OpenSSL.org.
30cca6fc52SDaniel Fojt  *
31cca6fc52SDaniel Fojt  * 5. Products derived from this software may not be called "OpenSSL"
32cca6fc52SDaniel Fojt  *    nor may "OpenSSL" appear in their names without prior written
33cca6fc52SDaniel Fojt  *    permission of the OpenSSL Project.
34cca6fc52SDaniel Fojt  *
35cca6fc52SDaniel Fojt  * 6. Redistributions of any form whatsoever must retain the following
36cca6fc52SDaniel Fojt  *    acknowledgment:
37cca6fc52SDaniel Fojt  *    "This product includes software developed by the OpenSSL Project
38cca6fc52SDaniel Fojt  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39cca6fc52SDaniel Fojt  *
40cca6fc52SDaniel Fojt  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41cca6fc52SDaniel Fojt  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42cca6fc52SDaniel Fojt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43cca6fc52SDaniel Fojt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44cca6fc52SDaniel Fojt  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45cca6fc52SDaniel Fojt  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46cca6fc52SDaniel Fojt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47cca6fc52SDaniel Fojt  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48cca6fc52SDaniel Fojt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49cca6fc52SDaniel Fojt  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50cca6fc52SDaniel Fojt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51cca6fc52SDaniel Fojt  * OF THE POSSIBILITY OF SUCH DAMAGE.
52cca6fc52SDaniel Fojt  * ====================================================================
53cca6fc52SDaniel Fojt  */
54cca6fc52SDaniel Fojt 
55cca6fc52SDaniel Fojt #include <string.h>
56cca6fc52SDaniel Fojt 
57cca6fc52SDaniel Fojt #include "cryptlib.h"
58cca6fc52SDaniel Fojt #include <openssl/asn1t.h>
59cca6fc52SDaniel Fojt #include <openssl/pem.h>
60cca6fc52SDaniel Fojt #include <openssl/x509v3.h>
61cca6fc52SDaniel Fojt #include <openssl/err.h>
62cca6fc52SDaniel Fojt #include <openssl/cms.h>
63cca6fc52SDaniel Fojt #include <openssl/rand.h>
64cca6fc52SDaniel Fojt #include "cms_lcl.h"
65cca6fc52SDaniel Fojt 
66cca6fc52SDaniel Fojt /* CMS EncryptedData Utilities */
67cca6fc52SDaniel Fojt 
68cca6fc52SDaniel Fojt /* Return BIO based on EncryptedContentInfo and key */
69cca6fc52SDaniel Fojt 
70cca6fc52SDaniel Fojt BIO *
cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo * ec)71cca6fc52SDaniel Fojt cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
72cca6fc52SDaniel Fojt {
73cca6fc52SDaniel Fojt 	BIO *b;
74cca6fc52SDaniel Fojt 	EVP_CIPHER_CTX *ctx;
75cca6fc52SDaniel Fojt 	const EVP_CIPHER *ciph;
76cca6fc52SDaniel Fojt 	X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
77cca6fc52SDaniel Fojt 	unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
78cca6fc52SDaniel Fojt 	unsigned char *tkey = NULL;
79cca6fc52SDaniel Fojt 	size_t tkeylen = 0;
80cca6fc52SDaniel Fojt 
81cca6fc52SDaniel Fojt 	int ok = 0;
82cca6fc52SDaniel Fojt 
83cca6fc52SDaniel Fojt 	int enc, keep_key = 0;
84cca6fc52SDaniel Fojt 
85cca6fc52SDaniel Fojt 	enc = ec->cipher ? 1 : 0;
86cca6fc52SDaniel Fojt 
87cca6fc52SDaniel Fojt 	b = BIO_new(BIO_f_cipher());
88cca6fc52SDaniel Fojt 	if (b == NULL) {
89cca6fc52SDaniel Fojt 		CMSerror(ERR_R_MALLOC_FAILURE);
90cca6fc52SDaniel Fojt 		return NULL;
91cca6fc52SDaniel Fojt 	}
92cca6fc52SDaniel Fojt 
93cca6fc52SDaniel Fojt 	BIO_get_cipher_ctx(b, &ctx);
94cca6fc52SDaniel Fojt 
95cca6fc52SDaniel Fojt 	if (enc) {
96cca6fc52SDaniel Fojt 		ciph = ec->cipher;
97cca6fc52SDaniel Fojt 		/*
98cca6fc52SDaniel Fojt 		 * If not keeping key set cipher to NULL so subsequent calls decrypt.
99cca6fc52SDaniel Fojt 		 */
100cca6fc52SDaniel Fojt 		if (ec->key)
101cca6fc52SDaniel Fojt 			ec->cipher = NULL;
102cca6fc52SDaniel Fojt 	} else {
103cca6fc52SDaniel Fojt 		ciph = EVP_get_cipherbyobj(calg->algorithm);
104cca6fc52SDaniel Fojt 
105cca6fc52SDaniel Fojt 		if (!ciph) {
106cca6fc52SDaniel Fojt 			CMSerror(CMS_R_UNKNOWN_CIPHER);
107cca6fc52SDaniel Fojt 			goto err;
108cca6fc52SDaniel Fojt 		}
109cca6fc52SDaniel Fojt 	}
110cca6fc52SDaniel Fojt 
111cca6fc52SDaniel Fojt 	if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) {
112cca6fc52SDaniel Fojt 		CMSerror(CMS_R_CIPHER_INITIALISATION_ERROR);
113cca6fc52SDaniel Fojt 		goto err;
114cca6fc52SDaniel Fojt 	}
115cca6fc52SDaniel Fojt 
116cca6fc52SDaniel Fojt 	if (enc) {
117cca6fc52SDaniel Fojt 		int ivlen;
118cca6fc52SDaniel Fojt 		calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
119cca6fc52SDaniel Fojt 		/* Generate a random IV if we need one */
120cca6fc52SDaniel Fojt 		ivlen = EVP_CIPHER_CTX_iv_length(ctx);
121cca6fc52SDaniel Fojt 		if (ivlen > 0) {
122cca6fc52SDaniel Fojt 			arc4random_buf(iv, ivlen);
123cca6fc52SDaniel Fojt 			piv = iv;
124cca6fc52SDaniel Fojt 		}
125cca6fc52SDaniel Fojt 	} else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) {
126cca6fc52SDaniel Fojt 		CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
127cca6fc52SDaniel Fojt 		goto err;
128cca6fc52SDaniel Fojt 	}
129cca6fc52SDaniel Fojt 	tkeylen = EVP_CIPHER_CTX_key_length(ctx);
130cca6fc52SDaniel Fojt 	/* Generate random session key */
131cca6fc52SDaniel Fojt 	if (!enc || !ec->key) {
132cca6fc52SDaniel Fojt 		tkey = malloc(tkeylen);
133cca6fc52SDaniel Fojt 		if (tkey == NULL) {
134cca6fc52SDaniel Fojt 			CMSerror(ERR_R_MALLOC_FAILURE);
135cca6fc52SDaniel Fojt 			goto err;
136cca6fc52SDaniel Fojt 		}
137cca6fc52SDaniel Fojt 		if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
138cca6fc52SDaniel Fojt 			goto err;
139cca6fc52SDaniel Fojt 	}
140cca6fc52SDaniel Fojt 
141cca6fc52SDaniel Fojt 	if (!ec->key) {
142cca6fc52SDaniel Fojt 		ec->key = tkey;
143cca6fc52SDaniel Fojt 		ec->keylen = tkeylen;
144cca6fc52SDaniel Fojt 		tkey = NULL;
145cca6fc52SDaniel Fojt 		if (enc)
146cca6fc52SDaniel Fojt 			keep_key = 1;
147cca6fc52SDaniel Fojt 		else
148cca6fc52SDaniel Fojt 			ERR_clear_error();
149cca6fc52SDaniel Fojt 
150cca6fc52SDaniel Fojt 	}
151cca6fc52SDaniel Fojt 
152cca6fc52SDaniel Fojt 	if (ec->keylen != tkeylen) {
153cca6fc52SDaniel Fojt 		/* If necessary set key length */
154*de0e0e4dSAntonio Huete Jimenez 		if (!EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen)) {
155cca6fc52SDaniel Fojt 			/*
156cca6fc52SDaniel Fojt 			 * Only reveal failure if debugging so we don't leak information
157cca6fc52SDaniel Fojt 			 * which may be useful in MMA.
158cca6fc52SDaniel Fojt 			 */
159cca6fc52SDaniel Fojt 			if (enc || ec->debug) {
160cca6fc52SDaniel Fojt 			    CMSerror(CMS_R_INVALID_KEY_LENGTH);
161cca6fc52SDaniel Fojt 			    goto err;
162cca6fc52SDaniel Fojt 			} else {
163cca6fc52SDaniel Fojt 			    /* Use random key */
164cca6fc52SDaniel Fojt 			    freezero(ec->key, ec->keylen);
165cca6fc52SDaniel Fojt 			    ec->key = tkey;
166cca6fc52SDaniel Fojt 			    ec->keylen = tkeylen;
167cca6fc52SDaniel Fojt 			    tkey = NULL;
168cca6fc52SDaniel Fojt 			    ERR_clear_error();
169cca6fc52SDaniel Fojt 			}
170cca6fc52SDaniel Fojt 		}
171cca6fc52SDaniel Fojt 	}
172cca6fc52SDaniel Fojt 
173cca6fc52SDaniel Fojt 	if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
174cca6fc52SDaniel Fojt 		CMSerror(CMS_R_CIPHER_INITIALISATION_ERROR);
175cca6fc52SDaniel Fojt 		goto err;
176cca6fc52SDaniel Fojt 	}
177cca6fc52SDaniel Fojt 	if (enc) {
178cca6fc52SDaniel Fojt 		calg->parameter = ASN1_TYPE_new();
179cca6fc52SDaniel Fojt 		if (calg->parameter == NULL) {
180cca6fc52SDaniel Fojt 			CMSerror(ERR_R_MALLOC_FAILURE);
181cca6fc52SDaniel Fojt 			goto err;
182cca6fc52SDaniel Fojt 		}
183cca6fc52SDaniel Fojt 		if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) {
184cca6fc52SDaniel Fojt 			CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
185cca6fc52SDaniel Fojt 			goto err;
186cca6fc52SDaniel Fojt 		}
187cca6fc52SDaniel Fojt 		/* If parameter type not set omit parameter */
188cca6fc52SDaniel Fojt 		if (calg->parameter->type == V_ASN1_UNDEF) {
189cca6fc52SDaniel Fojt 			ASN1_TYPE_free(calg->parameter);
190cca6fc52SDaniel Fojt 			calg->parameter = NULL;
191cca6fc52SDaniel Fojt 		}
192cca6fc52SDaniel Fojt 	}
193cca6fc52SDaniel Fojt 	ok = 1;
194cca6fc52SDaniel Fojt 
195cca6fc52SDaniel Fojt  err:
196cca6fc52SDaniel Fojt 	if (!keep_key || !ok) {
197cca6fc52SDaniel Fojt 		freezero(ec->key, ec->keylen);
198cca6fc52SDaniel Fojt 		ec->key = NULL;
199cca6fc52SDaniel Fojt 	}
200cca6fc52SDaniel Fojt 	freezero(tkey, tkeylen);
201cca6fc52SDaniel Fojt 	if (ok)
202cca6fc52SDaniel Fojt 		return b;
203cca6fc52SDaniel Fojt 	BIO_free(b);
204cca6fc52SDaniel Fojt 	return NULL;
205cca6fc52SDaniel Fojt }
206cca6fc52SDaniel Fojt 
207cca6fc52SDaniel Fojt int
cms_EncryptedContent_init(CMS_EncryptedContentInfo * ec,const EVP_CIPHER * cipher,const unsigned char * key,size_t keylen)208cca6fc52SDaniel Fojt cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
209cca6fc52SDaniel Fojt     const EVP_CIPHER *cipher, const unsigned char *key, size_t keylen)
210cca6fc52SDaniel Fojt {
211cca6fc52SDaniel Fojt 	ec->cipher = cipher;
212cca6fc52SDaniel Fojt 	if (key) {
213cca6fc52SDaniel Fojt 		if ((ec->key = malloc(keylen)) == NULL) {
214cca6fc52SDaniel Fojt 			CMSerror(ERR_R_MALLOC_FAILURE);
215cca6fc52SDaniel Fojt 			return 0;
216cca6fc52SDaniel Fojt 		}
217cca6fc52SDaniel Fojt 		memcpy(ec->key, key, keylen);
218cca6fc52SDaniel Fojt 	}
219cca6fc52SDaniel Fojt 	ec->keylen = keylen;
220cca6fc52SDaniel Fojt 	if (cipher)
221cca6fc52SDaniel Fojt 		ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
222cca6fc52SDaniel Fojt 
223cca6fc52SDaniel Fojt 	return 1;
224cca6fc52SDaniel Fojt }
225cca6fc52SDaniel Fojt 
226cca6fc52SDaniel Fojt int
CMS_EncryptedData_set1_key(CMS_ContentInfo * cms,const EVP_CIPHER * ciph,const unsigned char * key,size_t keylen)227cca6fc52SDaniel Fojt CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
228cca6fc52SDaniel Fojt     const unsigned char *key, size_t keylen)
229cca6fc52SDaniel Fojt {
230cca6fc52SDaniel Fojt 	CMS_EncryptedContentInfo *ec;
231cca6fc52SDaniel Fojt 
232cca6fc52SDaniel Fojt 	if (!key || !keylen) {
233cca6fc52SDaniel Fojt 		CMSerror(CMS_R_NO_KEY);
234cca6fc52SDaniel Fojt 		return 0;
235cca6fc52SDaniel Fojt 	}
236cca6fc52SDaniel Fojt 	if (ciph) {
237cca6fc52SDaniel Fojt 		cms->d.encryptedData = (CMS_EncryptedData *)ASN1_item_new(&CMS_EncryptedData_it);
238cca6fc52SDaniel Fojt 		if (!cms->d.encryptedData) {
239cca6fc52SDaniel Fojt 			CMSerror(ERR_R_MALLOC_FAILURE);
240cca6fc52SDaniel Fojt 			return 0;
241cca6fc52SDaniel Fojt 		}
242cca6fc52SDaniel Fojt 		cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
243cca6fc52SDaniel Fojt 		cms->d.encryptedData->version = 0;
244cca6fc52SDaniel Fojt 	} else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
245cca6fc52SDaniel Fojt 		CMSerror(CMS_R_NOT_ENCRYPTED_DATA);
246cca6fc52SDaniel Fojt 		return 0;
247cca6fc52SDaniel Fojt 	}
248cca6fc52SDaniel Fojt 	ec = cms->d.encryptedData->encryptedContentInfo;
249cca6fc52SDaniel Fojt 
250cca6fc52SDaniel Fojt 	return cms_EncryptedContent_init(ec, ciph, key, keylen);
251cca6fc52SDaniel Fojt }
252cca6fc52SDaniel Fojt 
253cca6fc52SDaniel Fojt BIO *
cms_EncryptedData_init_bio(CMS_ContentInfo * cms)254cca6fc52SDaniel Fojt cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
255cca6fc52SDaniel Fojt {
256cca6fc52SDaniel Fojt 	CMS_EncryptedData *enc = cms->d.encryptedData;
257cca6fc52SDaniel Fojt 
258cca6fc52SDaniel Fojt 	if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
259cca6fc52SDaniel Fojt 		enc->version = 2;
260cca6fc52SDaniel Fojt 
261cca6fc52SDaniel Fojt 	return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
262cca6fc52SDaniel Fojt }
263