Coverage Report

Created: 2025-03-09 06:52

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