diff options
Diffstat (limited to 'src/lib/libcrypto/cms/cms_enc.c')
-rw-r--r-- | src/lib/libcrypto/cms/cms_enc.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/lib/libcrypto/cms/cms_enc.c b/src/lib/libcrypto/cms/cms_enc.c new file mode 100644 index 0000000000..a1719830e8 --- /dev/null +++ b/src/lib/libcrypto/cms/cms_enc.c | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | * Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved. | ||
3 | * | ||
4 | * Licensed under the OpenSSL license (the "License"). You may not use | ||
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 | ||
8 | */ | ||
9 | |||
10 | #include "internal/cryptlib.h" | ||
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> | ||
17 | #include "cms_lcl.h" | ||
18 | |||
19 | /* CMS EncryptedData Utilities */ | ||
20 | |||
21 | /* Return BIO based on EncryptedContentInfo and key */ | ||
22 | |||
23 | BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec) | ||
24 | { | ||
25 | BIO *b; | ||
26 | EVP_CIPHER_CTX *ctx; | ||
27 | const EVP_CIPHER *ciph; | ||
28 | X509_ALGOR *calg = ec->contentEncryptionAlgorithm; | ||
29 | unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL; | ||
30 | unsigned char *tkey = NULL; | ||
31 | size_t tkeylen = 0; | ||
32 | |||
33 | int ok = 0; | ||
34 | |||
35 | int enc, keep_key = 0; | ||
36 | |||
37 | enc = ec->cipher ? 1 : 0; | ||
38 | |||
39 | b = BIO_new(BIO_f_cipher()); | ||
40 | if (b == NULL) { | ||
41 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); | ||
42 | return NULL; | ||
43 | } | ||
44 | |||
45 | BIO_get_cipher_ctx(b, &ctx); | ||
46 | |||
47 | if (enc) { | ||
48 | ciph = ec->cipher; | ||
49 | /* | ||
50 | * If not keeping key set cipher to NULL so subsequent calls decrypt. | ||
51 | */ | ||
52 | if (ec->key) | ||
53 | ec->cipher = NULL; | ||
54 | } else { | ||
55 | ciph = EVP_get_cipherbyobj(calg->algorithm); | ||
56 | |||
57 | if (!ciph) { | ||
58 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER); | ||
59 | goto err; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) { | ||
64 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, | ||
65 | CMS_R_CIPHER_INITIALISATION_ERROR); | ||
66 | goto err; | ||
67 | } | ||
68 | |||
69 | if (enc) { | ||
70 | int ivlen; | ||
71 | calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); | ||
72 | /* Generate a random IV if we need one */ | ||
73 | ivlen = EVP_CIPHER_CTX_iv_length(ctx); | ||
74 | if (ivlen > 0) { | ||
75 | if (RAND_bytes(iv, ivlen) <= 0) | ||
76 | goto err; | ||
77 | piv = iv; | ||
78 | } | ||
79 | } else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) { | ||
80 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, | ||
81 | CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); | ||
82 | goto err; | ||
83 | } | ||
84 | tkeylen = EVP_CIPHER_CTX_key_length(ctx); | ||
85 | /* Generate random session key */ | ||
86 | if (!enc || !ec->key) { | ||
87 | tkey = OPENSSL_malloc(tkeylen); | ||
88 | if (tkey == NULL) { | ||
89 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); | ||
90 | goto err; | ||
91 | } | ||
92 | if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0) | ||
93 | goto err; | ||
94 | } | ||
95 | |||
96 | if (!ec->key) { | ||
97 | ec->key = tkey; | ||
98 | ec->keylen = tkeylen; | ||
99 | tkey = NULL; | ||
100 | if (enc) | ||
101 | keep_key = 1; | ||
102 | else | ||
103 | ERR_clear_error(); | ||
104 | |||
105 | } | ||
106 | |||
107 | if (ec->keylen != tkeylen) { | ||
108 | /* If necessary set key length */ | ||
109 | if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) { | ||
110 | /* | ||
111 | * Only reveal failure if debugging so we don't leak information | ||
112 | * which may be useful in MMA. | ||
113 | */ | ||
114 | if (enc || ec->debug) { | ||
115 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, | ||
116 | CMS_R_INVALID_KEY_LENGTH); | ||
117 | goto err; | ||
118 | } else { | ||
119 | /* Use random key */ | ||
120 | OPENSSL_clear_free(ec->key, ec->keylen); | ||
121 | ec->key = tkey; | ||
122 | ec->keylen = tkeylen; | ||
123 | tkey = NULL; | ||
124 | ERR_clear_error(); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) { | ||
130 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, | ||
131 | CMS_R_CIPHER_INITIALISATION_ERROR); | ||
132 | goto err; | ||
133 | } | ||
134 | if (enc) { | ||
135 | calg->parameter = ASN1_TYPE_new(); | ||
136 | if (calg->parameter == NULL) { | ||
137 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE); | ||
138 | goto err; | ||
139 | } | ||
140 | if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) { | ||
141 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, | ||
142 | CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); | ||
143 | goto err; | ||
144 | } | ||
145 | /* If parameter type not set omit parameter */ | ||
146 | if (calg->parameter->type == V_ASN1_UNDEF) { | ||
147 | ASN1_TYPE_free(calg->parameter); | ||
148 | calg->parameter = NULL; | ||
149 | } | ||
150 | } | ||
151 | ok = 1; | ||
152 | |||
153 | err: | ||
154 | if (!keep_key || !ok) { | ||
155 | OPENSSL_clear_free(ec->key, ec->keylen); | ||
156 | ec->key = NULL; | ||
157 | } | ||
158 | OPENSSL_clear_free(tkey, tkeylen); | ||
159 | if (ok) | ||
160 | return b; | ||
161 | BIO_free(b); | ||
162 | return NULL; | ||
163 | } | ||
164 | |||
165 | int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec, | ||
166 | const EVP_CIPHER *cipher, | ||
167 | const unsigned char *key, size_t keylen) | ||
168 | { | ||
169 | ec->cipher = cipher; | ||
170 | if (key) { | ||
171 | if ((ec->key = OPENSSL_malloc(keylen)) == NULL) { | ||
172 | CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT, ERR_R_MALLOC_FAILURE); | ||
173 | return 0; | ||
174 | } | ||
175 | memcpy(ec->key, key, keylen); | ||
176 | } | ||
177 | ec->keylen = keylen; | ||
178 | if (cipher) | ||
179 | ec->contentType = OBJ_nid2obj(NID_pkcs7_data); | ||
180 | return 1; | ||
181 | } | ||
182 | |||
183 | int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, | ||
184 | const unsigned char *key, size_t keylen) | ||
185 | { | ||
186 | CMS_EncryptedContentInfo *ec; | ||
187 | if (!key || !keylen) { | ||
188 | CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NO_KEY); | ||
189 | return 0; | ||
190 | } | ||
191 | if (ciph) { | ||
192 | cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData); | ||
193 | if (!cms->d.encryptedData) { | ||
194 | CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, ERR_R_MALLOC_FAILURE); | ||
195 | return 0; | ||
196 | } | ||
197 | cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted); | ||
198 | cms->d.encryptedData->version = 0; | ||
199 | } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) { | ||
200 | CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NOT_ENCRYPTED_DATA); | ||
201 | return 0; | ||
202 | } | ||
203 | ec = cms->d.encryptedData->encryptedContentInfo; | ||
204 | return cms_EncryptedContent_init(ec, ciph, key, keylen); | ||
205 | } | ||
206 | |||
207 | BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms) | ||
208 | { | ||
209 | CMS_EncryptedData *enc = cms->d.encryptedData; | ||
210 | if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs) | ||
211 | enc->version = 2; | ||
212 | return cms_EncryptedContent_init_bio(enc->encryptedContentInfo); | ||
213 | } | ||