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