]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
454afd98 | 2 | * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved. |
5a9a4b29 | 3 | * |
b7617a3a | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
62867571 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 | |
5a9a4b29 DSH |
8 | */ |
9 | ||
10 | /* Simple PKCS#7 processing functions */ | |
11 | ||
12 | #include <stdio.h> | |
b39fc560 | 13 | #include "internal/cryptlib.h" |
5a9a4b29 DSH |
14 | #include <openssl/x509.h> |
15 | #include <openssl/x509v3.h> | |
90a1f2d7 | 16 | #include "pk7_local.h" |
5a9a4b29 | 17 | |
8e704858 RS |
18 | #define BUFFERSIZE 4096 |
19 | ||
852c2ed2 RS |
20 | DEFINE_STACK_OF(X509_ALGOR) |
21 | DEFINE_STACK_OF(PKCS7_SIGNER_INFO) | |
22 | ||
55311921 DSH |
23 | static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si); |
24 | ||
90a1f2d7 SL |
25 | PKCS7 *PKCS7_sign_with_libctx(X509 *signcert, EVP_PKEY *pkey, |
26 | STACK_OF(X509) *certs, BIO *data, int flags, | |
27 | OPENSSL_CTX *libctx, const char *propq) | |
5a9a4b29 | 28 | { |
0f113f3e MC |
29 | PKCS7 *p7; |
30 | int i; | |
31 | ||
90a1f2d7 SL |
32 | if ((p7 = PKCS7_new_with_libctx(libctx, propq)) == NULL) { |
33 | PKCS7err(0, ERR_R_MALLOC_FAILURE); | |
0f113f3e MC |
34 | return NULL; |
35 | } | |
36 | ||
37 | if (!PKCS7_set_type(p7, NID_pkcs7_signed)) | |
38 | goto err; | |
39 | ||
40 | if (!PKCS7_content_new(p7, NID_pkcs7_data)) | |
41 | goto err; | |
42 | ||
43 | if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags)) { | |
90a1f2d7 | 44 | PKCS7err(0, PKCS7_R_PKCS7_ADD_SIGNER_ERROR); |
0f113f3e MC |
45 | goto err; |
46 | } | |
47 | ||
48 | if (!(flags & PKCS7_NOCERTS)) { | |
49 | for (i = 0; i < sk_X509_num(certs); i++) { | |
50 | if (!PKCS7_add_certificate(p7, sk_X509_value(certs, i))) | |
51 | goto err; | |
52 | } | |
53 | } | |
54 | ||
55 | if (flags & PKCS7_DETACHED) | |
56 | PKCS7_set_detached(p7, 1); | |
57 | ||
58 | if (flags & (PKCS7_STREAM | PKCS7_PARTIAL)) | |
59 | return p7; | |
60 | ||
61 | if (PKCS7_final(p7, data, flags)) | |
62 | return p7; | |
63 | ||
64 | err: | |
65 | PKCS7_free(p7); | |
66 | return NULL; | |
60f20632 DSH |
67 | } |
68 | ||
90a1f2d7 SL |
69 | PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, |
70 | BIO *data, int flags) | |
71 | { | |
72 | return PKCS7_sign_with_libctx(signcert, pkey, certs, data, flags, NULL, NULL); | |
73 | } | |
74 | ||
75 | ||
60f20632 | 76 | int PKCS7_final(PKCS7 *p7, BIO *data, int flags) |
0f113f3e MC |
77 | { |
78 | BIO *p7bio; | |
79 | int ret = 0; | |
8e704858 | 80 | |
75ebbd9a | 81 | if ((p7bio = PKCS7_dataInit(p7, NULL)) == NULL) { |
0f113f3e MC |
82 | PKCS7err(PKCS7_F_PKCS7_FINAL, ERR_R_MALLOC_FAILURE); |
83 | return 0; | |
84 | } | |
60f20632 | 85 | |
0f113f3e | 86 | SMIME_crlf_copy(data, p7bio, flags); |
994df5a2 | 87 | |
0f113f3e | 88 | (void)BIO_flush(p7bio); |
60f20632 | 89 | |
0f113f3e MC |
90 | if (!PKCS7_dataFinal(p7, p7bio)) { |
91 | PKCS7err(PKCS7_F_PKCS7_FINAL, PKCS7_R_PKCS7_DATASIGN); | |
92 | goto err; | |
93 | } | |
0f113f3e | 94 | ret = 1; |
90a1f2d7 | 95 | err: |
0f113f3e | 96 | BIO_free_all(p7bio); |
60f20632 | 97 | |
0f113f3e | 98 | return ret; |
27068df7 | 99 | |
0f113f3e | 100 | } |
27068df7 | 101 | |
60f20632 | 102 | /* Check to see if a cipher exists and if so add S/MIME capabilities */ |
27068df7 | 103 | |
60f20632 | 104 | static int add_cipher_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg) |
0f113f3e MC |
105 | { |
106 | if (EVP_get_cipherbynid(nid)) | |
107 | return PKCS7_simple_smimecap(sk, nid, arg); | |
108 | return 1; | |
109 | } | |
5a9a4b29 | 110 | |
61e5ec4b | 111 | static int add_digest_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg) |
0f113f3e MC |
112 | { |
113 | if (EVP_get_digestbynid(nid)) | |
114 | return PKCS7_simple_smimecap(sk, nid, arg); | |
115 | return 1; | |
116 | } | |
61e5ec4b | 117 | |
60f20632 | 118 | PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert, |
0f113f3e MC |
119 | EVP_PKEY *pkey, const EVP_MD *md, |
120 | int flags) | |
121 | { | |
122 | PKCS7_SIGNER_INFO *si = NULL; | |
123 | STACK_OF(X509_ALGOR) *smcap = NULL; | |
90a1f2d7 | 124 | |
0f113f3e MC |
125 | if (!X509_check_private_key(signcert, pkey)) { |
126 | PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER, | |
127 | PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); | |
128 | return NULL; | |
129 | } | |
130 | ||
75ebbd9a | 131 | if ((si = PKCS7_add_signature(p7, signcert, pkey, md)) == NULL) { |
0f113f3e MC |
132 | PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER, |
133 | PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR); | |
134 | return NULL; | |
135 | } | |
136 | ||
90a1f2d7 | 137 | si->ctx = pkcs7_get0_ctx(p7); |
0f113f3e MC |
138 | if (!(flags & PKCS7_NOCERTS)) { |
139 | if (!PKCS7_add_certificate(p7, signcert)) | |
140 | goto err; | |
141 | } | |
142 | ||
143 | if (!(flags & PKCS7_NOATTR)) { | |
144 | if (!PKCS7_add_attrib_content_type(si, NULL)) | |
145 | goto err; | |
146 | /* Add SMIMECapabilities */ | |
147 | if (!(flags & PKCS7_NOSMIMECAP)) { | |
75ebbd9a | 148 | if ((smcap = sk_X509_ALGOR_new_null()) == NULL) { |
0f113f3e MC |
149 | PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER, ERR_R_MALLOC_FAILURE); |
150 | goto err; | |
151 | } | |
152 | if (!add_cipher_smcap(smcap, NID_aes_256_cbc, -1) | |
c58f3e42 MC |
153 | || !add_digest_smcap(smcap, NID_id_GostR3411_2012_256, -1) |
154 | || !add_digest_smcap(smcap, NID_id_GostR3411_2012_512, -1) | |
0f113f3e MC |
155 | || !add_digest_smcap(smcap, NID_id_GostR3411_94, -1) |
156 | || !add_cipher_smcap(smcap, NID_id_Gost28147_89, -1) | |
157 | || !add_cipher_smcap(smcap, NID_aes_192_cbc, -1) | |
158 | || !add_cipher_smcap(smcap, NID_aes_128_cbc, -1) | |
159 | || !add_cipher_smcap(smcap, NID_des_ede3_cbc, -1) | |
160 | || !add_cipher_smcap(smcap, NID_rc2_cbc, 128) | |
161 | || !add_cipher_smcap(smcap, NID_rc2_cbc, 64) | |
162 | || !add_cipher_smcap(smcap, NID_des_cbc, -1) | |
163 | || !add_cipher_smcap(smcap, NID_rc2_cbc, 40) | |
164 | || !PKCS7_add_attrib_smimecap(si, smcap)) | |
165 | goto err; | |
166 | sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); | |
167 | smcap = NULL; | |
168 | } | |
169 | if (flags & PKCS7_REUSE_DIGEST) { | |
170 | if (!pkcs7_copy_existing_digest(p7, si)) | |
171 | goto err; | |
90a1f2d7 SL |
172 | if (!(flags & PKCS7_PARTIAL) |
173 | && !PKCS7_SIGNER_INFO_sign(si)) | |
0f113f3e MC |
174 | goto err; |
175 | } | |
176 | } | |
177 | return si; | |
178 | err: | |
222561fe | 179 | sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); |
0f113f3e MC |
180 | return NULL; |
181 | } | |
182 | ||
183 | /* | |
184 | * Search for a digest matching SignerInfo digest type and if found copy | |
185 | * across. | |
55311921 DSH |
186 | */ |
187 | ||
188 | static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si) | |
0f113f3e MC |
189 | { |
190 | int i; | |
191 | STACK_OF(PKCS7_SIGNER_INFO) *sinfos; | |
192 | PKCS7_SIGNER_INFO *sitmp; | |
193 | ASN1_OCTET_STRING *osdig = NULL; | |
194 | sinfos = PKCS7_get_signer_info(p7); | |
195 | for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { | |
196 | sitmp = sk_PKCS7_SIGNER_INFO_value(sinfos, i); | |
197 | if (si == sitmp) | |
198 | break; | |
199 | if (sk_X509_ATTRIBUTE_num(sitmp->auth_attr) <= 0) | |
200 | continue; | |
201 | if (!OBJ_cmp(si->digest_alg->algorithm, sitmp->digest_alg->algorithm)) { | |
202 | osdig = PKCS7_digest_from_attributes(sitmp->auth_attr); | |
203 | break; | |
204 | } | |
205 | ||
206 | } | |
207 | ||
90a1f2d7 | 208 | if (osdig != NULL) |
0f113f3e MC |
209 | return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length); |
210 | ||
211 | PKCS7err(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST, | |
212 | PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND); | |
213 | return 0; | |
214 | } | |
55311921 | 215 | |
5a9a4b29 | 216 | int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, |
0f113f3e | 217 | BIO *indata, BIO *out, int flags) |
5a9a4b29 | 218 | { |
0f113f3e MC |
219 | STACK_OF(X509) *signers; |
220 | X509 *signer; | |
221 | STACK_OF(PKCS7_SIGNER_INFO) *sinfos; | |
222 | PKCS7_SIGNER_INFO *si; | |
f0e0fd51 | 223 | X509_STORE_CTX *cert_ctx = NULL; |
8e704858 | 224 | char *buf = NULL; |
0f113f3e | 225 | int i, j = 0, k, ret = 0; |
55500ea7 AG |
226 | BIO *p7bio = NULL; |
227 | BIO *tmpin = NULL, *tmpout = NULL; | |
90a1f2d7 | 228 | const PKCS7_CTX *p7_ctx; |
0f113f3e | 229 | |
12a765a5 | 230 | if (p7 == NULL) { |
90a1f2d7 | 231 | PKCS7err(0, PKCS7_R_INVALID_NULL_POINTER); |
0f113f3e MC |
232 | return 0; |
233 | } | |
234 | ||
235 | if (!PKCS7_type_is_signed(p7)) { | |
90a1f2d7 | 236 | PKCS7err(0, PKCS7_R_WRONG_CONTENT_TYPE); |
0f113f3e MC |
237 | return 0; |
238 | } | |
239 | ||
240 | /* Check for no data and no content: no data to verify signature */ | |
241 | if (PKCS7_get_detached(p7) && !indata) { | |
90a1f2d7 | 242 | PKCS7err(0, PKCS7_R_NO_CONTENT); |
0f113f3e MC |
243 | return 0; |
244 | } | |
02a938c9 | 245 | |
6b2ebe43 RS |
246 | if (flags & PKCS7_NO_DUAL_CONTENT) { |
247 | /* | |
248 | * This was originally "#if 0" because we thought that only old broken | |
249 | * Netscape did this. It turns out that Authenticode uses this kind | |
250 | * of "extended" PKCS7 format, and things like UEFI secure boot and | |
251 | * tools like osslsigncode need it. In Authenticode the verification | |
252 | * process is different, but the existing PKCs7 verification works. | |
253 | */ | |
254 | if (!PKCS7_get_detached(p7) && indata) { | |
90a1f2d7 | 255 | PKCS7err(0, PKCS7_R_CONTENT_AND_DATA_PRESENT); |
6b2ebe43 RS |
256 | return 0; |
257 | } | |
0f113f3e | 258 | } |
5a9a4b29 | 259 | |
0f113f3e MC |
260 | sinfos = PKCS7_get_signer_info(p7); |
261 | ||
262 | if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { | |
90a1f2d7 | 263 | PKCS7err(0, PKCS7_R_NO_SIGNATURES_ON_DATA); |
0f113f3e MC |
264 | return 0; |
265 | } | |
266 | ||
267 | signers = PKCS7_get0_signers(p7, certs, flags); | |
90a1f2d7 | 268 | if (signers == NULL) |
0f113f3e MC |
269 | return 0; |
270 | ||
271 | /* Now verify the certificates */ | |
90a1f2d7 SL |
272 | p7_ctx = pkcs7_get0_ctx(p7); |
273 | cert_ctx = X509_STORE_CTX_new_with_libctx(p7_ctx->libctx, p7_ctx->propq); | |
f0e0fd51 RS |
274 | if (cert_ctx == NULL) |
275 | goto err; | |
0f113f3e MC |
276 | if (!(flags & PKCS7_NOVERIFY)) |
277 | for (k = 0; k < sk_X509_num(signers); k++) { | |
278 | signer = sk_X509_value(signers, k); | |
279 | if (!(flags & PKCS7_NOCHAIN)) { | |
f0e0fd51 | 280 | if (!X509_STORE_CTX_init(cert_ctx, store, signer, |
0f113f3e | 281 | p7->d.sign->cert)) { |
90a1f2d7 | 282 | PKCS7err(0, ERR_R_X509_LIB); |
55500ea7 | 283 | goto err; |
0f113f3e | 284 | } |
f0e0fd51 RS |
285 | X509_STORE_CTX_set_default(cert_ctx, "smime_sign"); |
286 | } else if (!X509_STORE_CTX_init(cert_ctx, store, signer, NULL)) { | |
90a1f2d7 | 287 | PKCS7err(0, ERR_R_X509_LIB); |
55500ea7 | 288 | goto err; |
0f113f3e MC |
289 | } |
290 | if (!(flags & PKCS7_NOCRL)) | |
f0e0fd51 RS |
291 | X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl); |
292 | i = X509_verify_cert(cert_ctx); | |
0f113f3e | 293 | if (i <= 0) |
f0e0fd51 | 294 | j = X509_STORE_CTX_get_error(cert_ctx); |
36c6f0ad | 295 | X509_STORE_CTX_cleanup(cert_ctx); |
0f113f3e | 296 | if (i <= 0) { |
90a1f2d7 | 297 | PKCS7err(0, PKCS7_R_CERTIFICATE_VERIFY_ERROR); |
0f113f3e MC |
298 | ERR_add_error_data(2, "Verify error:", |
299 | X509_verify_cert_error_string(j)); | |
55500ea7 | 300 | goto err; |
0f113f3e MC |
301 | } |
302 | /* Check for revocation status here */ | |
303 | } | |
304 | ||
305 | /* | |
306 | * Performance optimization: if the content is a memory BIO then store | |
307 | * its contents in a temporary read only memory BIO. This avoids | |
308 | * potentially large numbers of slow copies of data which will occur when | |
309 | * reading from a read write memory BIO when signatures are calculated. | |
310 | */ | |
311 | ||
312 | if (indata && (BIO_method_type(indata) == BIO_TYPE_MEM)) { | |
313 | char *ptr; | |
314 | long len; | |
315 | len = BIO_get_mem_data(indata, &ptr); | |
316 | tmpin = BIO_new_mem_buf(ptr, len); | |
317 | if (tmpin == NULL) { | |
90a1f2d7 | 318 | PKCS7err(0, ERR_R_MALLOC_FAILURE); |
55500ea7 | 319 | goto err; |
0f113f3e MC |
320 | } |
321 | } else | |
322 | tmpin = indata; | |
323 | ||
75ebbd9a | 324 | if ((p7bio = PKCS7_dataInit(p7, tmpin)) == NULL) |
0f113f3e MC |
325 | goto err; |
326 | ||
327 | if (flags & PKCS7_TEXT) { | |
75ebbd9a | 328 | if ((tmpout = BIO_new(BIO_s_mem())) == NULL) { |
90a1f2d7 | 329 | PKCS7err(0, ERR_R_MALLOC_FAILURE); |
0f113f3e MC |
330 | goto err; |
331 | } | |
332 | BIO_set_mem_eof_return(tmpout, 0); | |
333 | } else | |
334 | tmpout = out; | |
335 | ||
336 | /* We now have to 'read' from p7bio to calculate digests etc. */ | |
8e704858 | 337 | if ((buf = OPENSSL_malloc(BUFFERSIZE)) == NULL) { |
90a1f2d7 | 338 | PKCS7err(0, ERR_R_MALLOC_FAILURE); |
8e704858 RS |
339 | goto err; |
340 | } | |
0f113f3e | 341 | for (;;) { |
8e704858 | 342 | i = BIO_read(p7bio, buf, BUFFERSIZE); |
0f113f3e MC |
343 | if (i <= 0) |
344 | break; | |
345 | if (tmpout) | |
346 | BIO_write(tmpout, buf, i); | |
347 | } | |
348 | ||
349 | if (flags & PKCS7_TEXT) { | |
350 | if (!SMIME_text(tmpout, out)) { | |
90a1f2d7 | 351 | PKCS7err(0, PKCS7_R_SMIME_TEXT_ERROR); |
0f113f3e MC |
352 | BIO_free(tmpout); |
353 | goto err; | |
354 | } | |
355 | BIO_free(tmpout); | |
356 | } | |
357 | ||
358 | /* Now Verify All Signatures */ | |
359 | if (!(flags & PKCS7_NOSIGS)) | |
360 | for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { | |
361 | si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); | |
362 | signer = sk_X509_value(signers, i); | |
363 | j = PKCS7_signatureVerify(p7bio, p7, si, signer); | |
364 | if (j <= 0) { | |
90a1f2d7 | 365 | PKCS7err(0, PKCS7_R_SIGNATURE_FAILURE); |
0f113f3e MC |
366 | goto err; |
367 | } | |
368 | } | |
369 | ||
370 | ret = 1; | |
371 | ||
372 | err: | |
f0e0fd51 | 373 | X509_STORE_CTX_free(cert_ctx); |
8e704858 | 374 | OPENSSL_free(buf); |
0f113f3e MC |
375 | if (tmpin == indata) { |
376 | if (indata) | |
377 | BIO_pop(p7bio); | |
378 | } | |
379 | BIO_free_all(p7bio); | |
0f113f3e | 380 | sk_X509_free(signers); |
0f113f3e | 381 | return ret; |
5a9a4b29 DSH |
382 | } |
383 | ||
0f113f3e MC |
384 | STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, |
385 | int flags) | |
55ec5861 | 386 | { |
0f113f3e MC |
387 | STACK_OF(X509) *signers; |
388 | STACK_OF(PKCS7_SIGNER_INFO) *sinfos; | |
389 | PKCS7_SIGNER_INFO *si; | |
390 | PKCS7_ISSUER_AND_SERIAL *ias; | |
391 | X509 *signer; | |
392 | int i; | |
393 | ||
12a765a5 | 394 | if (p7 == NULL) { |
0f113f3e MC |
395 | PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_INVALID_NULL_POINTER); |
396 | return NULL; | |
397 | } | |
398 | ||
399 | if (!PKCS7_type_is_signed(p7)) { | |
400 | PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_WRONG_CONTENT_TYPE); | |
401 | return NULL; | |
402 | } | |
403 | ||
404 | /* Collect all the signers together */ | |
405 | ||
406 | sinfos = PKCS7_get_signer_info(p7); | |
407 | ||
408 | if (sk_PKCS7_SIGNER_INFO_num(sinfos) <= 0) { | |
409 | PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_NO_SIGNERS); | |
410 | return 0; | |
411 | } | |
412 | ||
75ebbd9a | 413 | if ((signers = sk_X509_new_null()) == NULL) { |
0f113f3e MC |
414 | PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, ERR_R_MALLOC_FAILURE); |
415 | return NULL; | |
416 | } | |
417 | ||
418 | for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { | |
419 | si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); | |
420 | ias = si->issuer_and_serial; | |
421 | signer = NULL; | |
422 | /* If any certificates passed they take priority */ | |
423 | if (certs) | |
424 | signer = X509_find_by_issuer_and_serial(certs, | |
425 | ias->issuer, ias->serial); | |
426 | if (!signer && !(flags & PKCS7_NOINTERN) | |
427 | && p7->d.sign->cert) | |
428 | signer = | |
429 | X509_find_by_issuer_and_serial(p7->d.sign->cert, | |
430 | ias->issuer, ias->serial); | |
431 | if (!signer) { | |
432 | PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, | |
433 | PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND); | |
434 | sk_X509_free(signers); | |
435 | return 0; | |
436 | } | |
437 | ||
438 | if (!sk_X509_push(signers, signer)) { | |
439 | sk_X509_free(signers); | |
440 | return NULL; | |
441 | } | |
442 | } | |
443 | return signers; | |
55ec5861 DSH |
444 | } |
445 | ||
5a9a4b29 DSH |
446 | /* Build a complete PKCS#7 enveloped data */ |
447 | ||
90a1f2d7 SL |
448 | PKCS7 *PKCS7_encrypt_with_libctx(STACK_OF(X509) *certs, BIO *in, |
449 | const EVP_CIPHER *cipher, int flags, | |
450 | OPENSSL_CTX *libctx, const char *propq) | |
5a9a4b29 | 451 | { |
0f113f3e MC |
452 | PKCS7 *p7; |
453 | BIO *p7bio = NULL; | |
454 | int i; | |
455 | X509 *x509; | |
90a1f2d7 SL |
456 | |
457 | if ((p7 = PKCS7_new_with_libctx(libctx, propq)) == NULL) { | |
458 | PKCS7err(0, ERR_R_MALLOC_FAILURE); | |
0f113f3e MC |
459 | return NULL; |
460 | } | |
461 | ||
462 | if (!PKCS7_set_type(p7, NID_pkcs7_enveloped)) | |
463 | goto err; | |
464 | if (!PKCS7_set_cipher(p7, cipher)) { | |
90a1f2d7 | 465 | PKCS7err(0, PKCS7_R_ERROR_SETTING_CIPHER); |
0f113f3e MC |
466 | goto err; |
467 | } | |
468 | ||
469 | for (i = 0; i < sk_X509_num(certs); i++) { | |
470 | x509 = sk_X509_value(certs, i); | |
471 | if (!PKCS7_add_recipient(p7, x509)) { | |
90a1f2d7 | 472 | PKCS7err(0, PKCS7_R_ERROR_ADDING_RECIPIENT); |
0f113f3e MC |
473 | goto err; |
474 | } | |
475 | } | |
476 | ||
477 | if (flags & PKCS7_STREAM) | |
478 | return p7; | |
479 | ||
480 | if (PKCS7_final(p7, in, flags)) | |
481 | return p7; | |
482 | ||
483 | err: | |
484 | ||
485 | BIO_free_all(p7bio); | |
486 | PKCS7_free(p7); | |
487 | return NULL; | |
5a9a4b29 DSH |
488 | |
489 | } | |
490 | ||
90a1f2d7 SL |
491 | PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, |
492 | int flags) | |
493 | { | |
494 | return PKCS7_encrypt_with_libctx(certs, in, cipher, flags, NULL, NULL); | |
495 | } | |
496 | ||
497 | ||
5a9a4b29 DSH |
498 | int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags) |
499 | { | |
0f113f3e | 500 | BIO *tmpmem; |
29717229 | 501 | int ret = 0, i; |
8e704858 | 502 | char *buf = NULL; |
0f113f3e | 503 | |
12a765a5 | 504 | if (p7 == NULL) { |
0f113f3e MC |
505 | PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_INVALID_NULL_POINTER); |
506 | return 0; | |
507 | } | |
508 | ||
509 | if (!PKCS7_type_is_enveloped(p7)) { | |
510 | PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_WRONG_CONTENT_TYPE); | |
511 | return 0; | |
512 | } | |
513 | ||
514 | if (cert && !X509_check_private_key(cert, pkey)) { | |
515 | PKCS7err(PKCS7_F_PKCS7_DECRYPT, | |
516 | PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); | |
517 | return 0; | |
518 | } | |
519 | ||
75ebbd9a | 520 | if ((tmpmem = PKCS7_dataDecode(p7, pkey, NULL, cert)) == NULL) { |
0f113f3e MC |
521 | PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_DECRYPT_ERROR); |
522 | return 0; | |
523 | } | |
524 | ||
525 | if (flags & PKCS7_TEXT) { | |
526 | BIO *tmpbuf, *bread; | |
527 | /* Encrypt BIOs can't do BIO_gets() so add a buffer BIO */ | |
75ebbd9a | 528 | if ((tmpbuf = BIO_new(BIO_f_buffer())) == NULL) { |
0f113f3e MC |
529 | PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE); |
530 | BIO_free_all(tmpmem); | |
531 | return 0; | |
532 | } | |
75ebbd9a | 533 | if ((bread = BIO_push(tmpbuf, tmpmem)) == NULL) { |
0f113f3e MC |
534 | PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE); |
535 | BIO_free_all(tmpbuf); | |
536 | BIO_free_all(tmpmem); | |
537 | return 0; | |
538 | } | |
539 | ret = SMIME_text(bread, data); | |
540 | if (ret > 0 && BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) { | |
541 | if (!BIO_get_cipher_status(tmpmem)) | |
542 | ret = 0; | |
543 | } | |
544 | BIO_free_all(bread); | |
545 | return ret; | |
8e704858 RS |
546 | } |
547 | if ((buf = OPENSSL_malloc(BUFFERSIZE)) == NULL) { | |
548 | PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE); | |
549 | goto err; | |
550 | } | |
551 | for (;;) { | |
552 | i = BIO_read(tmpmem, buf, BUFFERSIZE); | |
553 | if (i <= 0) { | |
554 | ret = 1; | |
555 | if (BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) { | |
556 | if (!BIO_get_cipher_status(tmpmem)) | |
557 | ret = 0; | |
0f113f3e | 558 | } |
8e704858 RS |
559 | |
560 | break; | |
561 | } | |
562 | if (BIO_write(data, buf, i) != i) { | |
8e704858 | 563 | break; |
0f113f3e | 564 | } |
0f113f3e | 565 | } |
8e704858 RS |
566 | err: |
567 | OPENSSL_free(buf); | |
568 | BIO_free_all(tmpmem); | |
569 | return ret; | |
5a9a4b29 | 570 | } |