Coverage Report

Created: 2022-11-30 06:20

/src/openssl/crypto/cms/cms_enc.c
Line
Count
Source (jump to first uncovered line)
1
/* crypto/cms/cms_enc.c */
2
/*
3
 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4
 * project.
5
 */
6
/* ====================================================================
7
 * Copyright (c) 2008 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 "cryptlib.h"
56
#include <openssl/asn1t.h>
57
#include <openssl/pem.h>
58
#include <openssl/x509v3.h>
59
#include <openssl/err.h>
60
#include <openssl/cms.h>
61
#include <openssl/rand.h>
62
#include "cms_lcl.h"
63
64
/* CMS EncryptedData Utilities */
65
66
DECLARE_ASN1_ITEM(CMS_EncryptedData)
67
68
/* Return BIO based on EncryptedContentInfo and key */
69
70
BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
71
0
{
72
0
    BIO *b;
73
0
    EVP_CIPHER_CTX *ctx;
74
0
    const EVP_CIPHER *ciph;
75
0
    X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
76
0
    unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
77
0
    unsigned char *tkey = NULL;
78
0
    size_t tkeylen = 0;
79
80
0
    int ok = 0;
81
82
0
    int enc, keep_key = 0;
83
84
0
    enc = ec->cipher ? 1 : 0;
85
86
0
    b = BIO_new(BIO_f_cipher());
87
0
    if (!b) {
88
0
        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
89
0
        return NULL;
90
0
    }
91
92
0
    BIO_get_cipher_ctx(b, &ctx);
93
94
0
    if (enc) {
95
0
        ciph = ec->cipher;
96
        /*
97
         * If not keeping key set cipher to NULL so subsequent calls decrypt.
98
         */
99
0
        if (ec->key)
100
0
            ec->cipher = NULL;
101
0
    } else {
102
0
        ciph = EVP_get_cipherbyobj(calg->algorithm);
103
104
0
        if (!ciph) {
105
0
            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER);
106
0
            goto err;
107
0
        }
108
0
    }
109
110
0
    if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) {
111
0
        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
112
0
               CMS_R_CIPHER_INITIALISATION_ERROR);
113
0
        goto err;
114
0
    }
115
116
0
    if (enc) {
117
0
        int ivlen;
118
0
        calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
119
        /* Generate a random IV if we need one */
120
0
        ivlen = EVP_CIPHER_CTX_iv_length(ctx);
121
0
        if (ivlen > 0) {
122
0
            if (RAND_bytes(iv, ivlen) <= 0)
123
0
                goto err;
124
0
            piv = iv;
125
0
        }
126
0
    } else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) {
127
0
        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
128
0
               CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
129
0
        goto err;
130
0
    }
131
0
    tkeylen = EVP_CIPHER_CTX_key_length(ctx);
132
    /* Generate random session key */
133
0
    if (!enc || !ec->key) {
134
0
        tkey = OPENSSL_malloc(tkeylen);
135
0
        if (!tkey) {
136
0
            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
137
0
            goto err;
138
0
        }
139
0
        if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
140
0
            goto err;
141
0
    }
142
143
0
    if (!ec->key) {
144
0
        ec->key = tkey;
145
0
        ec->keylen = tkeylen;
146
0
        tkey = NULL;
147
0
        if (enc)
148
0
            keep_key = 1;
149
0
        else
150
0
            ERR_clear_error();
151
152
0
    }
153
154
0
    if (ec->keylen != tkeylen) {
155
        /* If necessary set key length */
156
0
        if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) {
157
            /*
158
             * Only reveal failure if debugging so we don't leak information
159
             * which may be useful in MMA.
160
             */
161
0
            if (enc || ec->debug) {
162
0
                CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
163
0
                       CMS_R_INVALID_KEY_LENGTH);
164
0
                goto err;
165
0
            } else {
166
                /* Use random key */
167
0
                OPENSSL_cleanse(ec->key, ec->keylen);
168
0
                OPENSSL_free(ec->key);
169
0
                ec->key = tkey;
170
0
                ec->keylen = tkeylen;
171
0
                tkey = NULL;
172
0
                ERR_clear_error();
173
0
            }
174
0
        }
175
0
    }
176
177
0
    if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
178
0
        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
179
0
               CMS_R_CIPHER_INITIALISATION_ERROR);
180
0
        goto err;
181
0
    }
182
0
    if (enc) {
183
0
        calg->parameter = ASN1_TYPE_new();
184
0
        if (calg->parameter == NULL) {
185
0
            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
186
0
            goto err;
187
0
        }
188
0
        if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) {
189
0
            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
190
0
                   CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
191
0
            goto err;
192
0
        }
193
        /* If parameter type not set omit parameter */
194
0
        if (calg->parameter->type == V_ASN1_UNDEF) {
195
0
            ASN1_TYPE_free(calg->parameter);
196
0
            calg->parameter = NULL;
197
0
        }
198
0
    }
199
0
    ok = 1;
200
201
0
 err:
202
0
    if (ec->key && (!keep_key || !ok)) {
203
0
        OPENSSL_cleanse(ec->key, ec->keylen);
204
0
        OPENSSL_free(ec->key);
205
0
        ec->key = NULL;
206
0
    }
207
0
    if (tkey) {
208
0
        OPENSSL_cleanse(tkey, tkeylen);
209
0
        OPENSSL_free(tkey);
210
0
    }
211
0
    if (ok)
212
0
        return b;
213
0
    BIO_free(b);
214
0
    return NULL;
215
0
}
216
217
int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
218
                              const EVP_CIPHER *cipher,
219
                              const unsigned char *key, size_t keylen)
220
0
{
221
0
    ec->cipher = cipher;
222
0
    if (key) {
223
0
        ec->key = OPENSSL_malloc(keylen);
224
0
        if (!ec->key)
225
0
            return 0;
226
0
        memcpy(ec->key, key, keylen);
227
0
    }
228
0
    ec->keylen = keylen;
229
0
    if (cipher)
230
0
        ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
231
0
    return 1;
232
0
}
233
234
int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
235
                               const unsigned char *key, size_t keylen)
236
0
{
237
0
    CMS_EncryptedContentInfo *ec;
238
0
    if (!key || !keylen) {
239
0
        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NO_KEY);
240
0
        return 0;
241
0
    }
242
0
    if (ciph) {
243
0
        cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData);
244
0
        if (!cms->d.encryptedData) {
245
0
            CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, ERR_R_MALLOC_FAILURE);
246
0
            return 0;
247
0
        }
248
0
        cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
249
0
        cms->d.encryptedData->version = 0;
250
0
    } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
251
0
        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NOT_ENCRYPTED_DATA);
252
0
        return 0;
253
0
    }
254
0
    ec = cms->d.encryptedData->encryptedContentInfo;
255
0
    return cms_EncryptedContent_init(ec, ciph, key, keylen);
256
0
}
257
258
BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
259
0
{
260
0
    CMS_EncryptedData *enc = cms->d.encryptedData;
261
0
    if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
262
0
        enc->version = 2;
263
0
    return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
264
0
}