]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
4333b89f | 2 | * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved. |
5c4436c9 | 3 | * |
08ddd302 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
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 | |
5c4436c9 DSH |
8 | */ |
9 | ||
b39fc560 | 10 | #include "internal/cryptlib.h" |
5c4436c9 DSH |
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> | |
924663c3 | 17 | #include "crypto/evp.h" |
fa9e6ad4 | 18 | #include "crypto/asn1.h" |
706457b7 | 19 | #include "cms_local.h" |
5c4436c9 DSH |
20 | |
21 | /* CMS EncryptedData Utilities */ | |
22 | ||
320bfc1b DSH |
23 | /* Return BIO based on EncryptedContentInfo and key */ |
24 | ||
53155f1c SL |
25 | BIO *ossl_cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec, |
26 | const CMS_CTX *cms_ctx) | |
0f113f3e MC |
27 | { |
28 | BIO *b; | |
29 | EVP_CIPHER_CTX *ctx; | |
c1669f41 SL |
30 | EVP_CIPHER *fetched_ciph = NULL; |
31 | const EVP_CIPHER *cipher = NULL; | |
0f113f3e | 32 | X509_ALGOR *calg = ec->contentEncryptionAlgorithm; |
924663c3 | 33 | evp_cipher_aead_asn1_params aparams; |
0f113f3e MC |
34 | unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL; |
35 | unsigned char *tkey = NULL; | |
c8ea9bc6 | 36 | int len; |
924663c3 | 37 | int ivlen = 0; |
0f113f3e | 38 | size_t tkeylen = 0; |
0f113f3e | 39 | int ok = 0; |
0f113f3e | 40 | int enc, keep_key = 0; |
53155f1c SL |
41 | OSSL_LIB_CTX *libctx = ossl_cms_ctx_get0_libctx(cms_ctx); |
42 | const char *propq = ossl_cms_ctx_get0_propq(cms_ctx); | |
5c4436c9 | 43 | |
0f113f3e | 44 | enc = ec->cipher ? 1 : 0; |
5c4436c9 | 45 | |
0f113f3e | 46 | b = BIO_new(BIO_f_cipher()); |
90945fa3 | 47 | if (b == NULL) { |
e077455e | 48 | ERR_raise(ERR_LIB_CMS, ERR_R_BIO_LIB); |
0f113f3e MC |
49 | return NULL; |
50 | } | |
5c4436c9 | 51 | |
0f113f3e | 52 | BIO_get_cipher_ctx(b, &ctx); |
5c4436c9 | 53 | |
1acb2e6f | 54 | (void)ERR_set_mark(); |
0f113f3e | 55 | if (enc) { |
c1669f41 | 56 | cipher = ec->cipher; |
0f113f3e MC |
57 | /* |
58 | * If not keeping key set cipher to NULL so subsequent calls decrypt. | |
59 | */ | |
c1669f41 | 60 | if (ec->key != NULL) |
0f113f3e MC |
61 | ec->cipher = NULL; |
62 | } else { | |
c1669f41 SL |
63 | cipher = EVP_get_cipherbyobj(calg->algorithm); |
64 | } | |
65 | if (cipher != NULL) { | |
ed576acd TM |
66 | fetched_ciph = EVP_CIPHER_fetch(libctx, EVP_CIPHER_get0_name(cipher), |
67 | propq); | |
1acb2e6f SL |
68 | if (fetched_ciph != NULL) |
69 | cipher = fetched_ciph; | |
70 | } | |
71 | if (cipher == NULL) { | |
72 | (void)ERR_clear_last_mark(); | |
9311d0c4 | 73 | ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER); |
1acb2e6f | 74 | goto err; |
0f113f3e | 75 | } |
1acb2e6f SL |
76 | (void)ERR_pop_to_mark(); |
77 | ||
78 | if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc) <= 0) { | |
9311d0c4 | 79 | ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR); |
0f113f3e MC |
80 | goto err; |
81 | } | |
5c4436c9 | 82 | |
0f113f3e | 83 | if (enc) { |
ed576acd | 84 | calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_get_type(ctx)); |
bd160912 | 85 | if (calg->algorithm == NULL || calg->algorithm->nid == NID_undef) { |
bf3f8f2c MC |
86 | ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM); |
87 | goto err; | |
88 | } | |
0f113f3e | 89 | /* Generate a random IV if we need one */ |
ed576acd | 90 | ivlen = EVP_CIPHER_CTX_get_iv_length(ctx); |
83ab43da DB |
91 | if (ivlen < 0) { |
92 | ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); | |
93 | goto err; | |
94 | } | |
95 | ||
0f113f3e | 96 | if (ivlen > 0) { |
5cbd2ea3 | 97 | if (RAND_bytes_ex(libctx, iv, ivlen, 0) <= 0) |
0f113f3e MC |
98 | goto err; |
99 | piv = iv; | |
100 | } | |
924663c3 JZ |
101 | } else { |
102 | if (evp_cipher_asn1_to_param_ex(ctx, calg->parameter, &aparams) <= 0) { | |
9311d0c4 | 103 | ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); |
924663c3 JZ |
104 | goto err; |
105 | } | |
ed576acd | 106 | if ((EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) { |
924663c3 JZ |
107 | piv = aparams.iv; |
108 | if (ec->taglen > 0 | |
109 | && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, | |
110 | ec->taglen, ec->tag) <= 0) { | |
9311d0c4 | 111 | ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_AEAD_SET_TAG_ERROR); |
924663c3 JZ |
112 | goto err; |
113 | } | |
114 | } | |
0f113f3e | 115 | } |
ed576acd | 116 | len = EVP_CIPHER_CTX_get_key_length(ctx); |
c8ea9bc6 SL |
117 | if (len <= 0) |
118 | goto err; | |
119 | tkeylen = (size_t)len; | |
120 | ||
0f113f3e MC |
121 | /* Generate random session key */ |
122 | if (!enc || !ec->key) { | |
123 | tkey = OPENSSL_malloc(tkeylen); | |
e077455e | 124 | if (tkey == NULL) |
0f113f3e | 125 | goto err; |
0f113f3e MC |
126 | if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0) |
127 | goto err; | |
128 | } | |
146b52ed | 129 | |
0f113f3e MC |
130 | if (!ec->key) { |
131 | ec->key = tkey; | |
132 | ec->keylen = tkeylen; | |
133 | tkey = NULL; | |
134 | if (enc) | |
135 | keep_key = 1; | |
136 | else | |
137 | ERR_clear_error(); | |
146b52ed | 138 | |
0f113f3e | 139 | } |
e540d1cd | 140 | |
0f113f3e MC |
141 | if (ec->keylen != tkeylen) { |
142 | /* If necessary set key length */ | |
143 | if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) { | |
144 | /* | |
145 | * Only reveal failure if debugging so we don't leak information | |
146 | * which may be useful in MMA. | |
147 | */ | |
148 | if (enc || ec->debug) { | |
9311d0c4 | 149 | ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH); |
0f113f3e MC |
150 | goto err; |
151 | } else { | |
152 | /* Use random key */ | |
4b45c6e5 | 153 | OPENSSL_clear_free(ec->key, ec->keylen); |
0f113f3e MC |
154 | ec->key = tkey; |
155 | ec->keylen = tkeylen; | |
156 | tkey = NULL; | |
157 | ERR_clear_error(); | |
158 | } | |
159 | } | |
160 | } | |
5c4436c9 | 161 | |
0f113f3e | 162 | if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) { |
9311d0c4 | 163 | ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR); |
0f113f3e MC |
164 | goto err; |
165 | } | |
708cf5de DSH |
166 | if (enc) { |
167 | calg->parameter = ASN1_TYPE_new(); | |
168 | if (calg->parameter == NULL) { | |
e077455e | 169 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); |
708cf5de DSH |
170 | goto err; |
171 | } | |
ed576acd | 172 | if ((EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) { |
924663c3 JZ |
173 | memcpy(aparams.iv, piv, ivlen); |
174 | aparams.iv_len = ivlen; | |
ed576acd | 175 | aparams.tag_len = EVP_CIPHER_CTX_get_tag_length(ctx); |
924663c3 JZ |
176 | if (aparams.tag_len <= 0) |
177 | goto err; | |
178 | } | |
179 | ||
180 | if (evp_cipher_param_to_asn1_ex(ctx, calg->parameter, &aparams) <= 0) { | |
9311d0c4 | 181 | ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); |
708cf5de DSH |
182 | goto err; |
183 | } | |
184 | /* If parameter type not set omit parameter */ | |
185 | if (calg->parameter->type == V_ASN1_UNDEF) { | |
186 | ASN1_TYPE_free(calg->parameter); | |
187 | calg->parameter = NULL; | |
188 | } | |
0f113f3e MC |
189 | } |
190 | ok = 1; | |
5c4436c9 | 191 | |
0f113f3e | 192 | err: |
1acb2e6f | 193 | EVP_CIPHER_free(fetched_ciph); |
891eac46 | 194 | if (!keep_key || !ok) { |
4b45c6e5 | 195 | OPENSSL_clear_free(ec->key, ec->keylen); |
0f113f3e MC |
196 | ec->key = NULL; |
197 | } | |
4b45c6e5 | 198 | OPENSSL_clear_free(tkey, tkeylen); |
0f113f3e MC |
199 | if (ok) |
200 | return b; | |
201 | BIO_free(b); | |
202 | return NULL; | |
203 | } | |
204 | ||
53155f1c SL |
205 | int ossl_cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec, |
206 | const EVP_CIPHER *cipher, | |
207 | const unsigned char *key, size_t keylen, | |
208 | const CMS_CTX *cms_ctx) | |
0f113f3e MC |
209 | { |
210 | ec->cipher = cipher; | |
211 | if (key) { | |
e077455e | 212 | if ((ec->key = OPENSSL_malloc(keylen)) == NULL) |
0f113f3e MC |
213 | return 0; |
214 | memcpy(ec->key, key, keylen); | |
215 | } | |
216 | ec->keylen = keylen; | |
c1669f41 | 217 | if (cipher != NULL) |
0f113f3e MC |
218 | ec->contentType = OBJ_nid2obj(NID_pkcs7_data); |
219 | return 1; | |
220 | } | |
320bfc1b DSH |
221 | |
222 | int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, | |
0f113f3e MC |
223 | const unsigned char *key, size_t keylen) |
224 | { | |
225 | CMS_EncryptedContentInfo *ec; | |
c1669f41 | 226 | |
0f113f3e | 227 | if (!key || !keylen) { |
9311d0c4 | 228 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_KEY); |
0f113f3e MC |
229 | return 0; |
230 | } | |
231 | if (ciph) { | |
232 | cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData); | |
233 | if (!cms->d.encryptedData) { | |
e077455e | 234 | ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB); |
0f113f3e MC |
235 | return 0; |
236 | } | |
237 | cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted); | |
238 | cms->d.encryptedData->version = 0; | |
239 | } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) { | |
9311d0c4 | 240 | ERR_raise(ERR_LIB_CMS, CMS_R_NOT_ENCRYPTED_DATA); |
0f113f3e MC |
241 | return 0; |
242 | } | |
243 | ec = cms->d.encryptedData->encryptedContentInfo; | |
53155f1c SL |
244 | return ossl_cms_EncryptedContent_init(ec, ciph, key, keylen, |
245 | ossl_cms_get0_cmsctx(cms)); | |
0f113f3e | 246 | } |
320bfc1b | 247 | |
53155f1c | 248 | BIO *ossl_cms_EncryptedData_init_bio(const CMS_ContentInfo *cms) |
0f113f3e MC |
249 | { |
250 | CMS_EncryptedData *enc = cms->d.encryptedData; | |
251 | if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs) | |
252 | enc->version = 2; | |
53155f1c SL |
253 | return ossl_cms_EncryptedContent_init_bio(enc->encryptedContentInfo, |
254 | ossl_cms_get0_cmsctx(cms)); | |
0f113f3e | 255 | } |