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