]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
{CMS,PKCS7}_verify(): use 'certs' parameter ('-certfile' option) also for chain building
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Wed, 4 Oct 2023 19:32:00 +0000 (21:32 +0200)
committerTomas Mraz <tomas@openssl.org>
Wed, 17 Jul 2024 14:34:53 +0000 (16:34 +0200)
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18916)

apps/cms.c
apps/smime.c
crypto/cms/cms_smime.c
crypto/pkcs7/pk7_lib.c
crypto/pkcs7/pk7_local.h
crypto/pkcs7/pk7_smime.c
doc/man1/openssl-cms.pod.in
doc/man1/openssl-smime.pod.in
doc/man3/CMS_verify.pod
doc/man3/PKCS7_verify.pod
test/recipes/80-test_cms.t

index f93c98ac92c4164bfbc2b10953e2ce62d8e9655d..daa1d7c1a6b8f9b5e89b207bc6481a78091efad0 100644 (file)
@@ -175,7 +175,10 @@ const OPTIONS cms_options[] = {
     OPT_SECTION("Signing"),
     {"md", OPT_MD, 's', "Digest algorithm to use"},
     {"signer", OPT_SIGNER, 's', "Signer certificate input file"},
-    {"certfile", OPT_CERTFILE, '<', "Other certificates file"},
+    {"certfile", OPT_CERTFILE, '<',
+     "Extra signer and intermediate CA certificates to include when signing"},
+    {OPT_MORE_STR, 0, 0,
+     "or to use as preferred signer certs and for chain building when verifying"},
     {"cades", OPT_CADES, '-',
      "Include signingCertificate attribute (CAdES-BES)"},
     {"nodetach", OPT_NODETACH, '-', "Use opaque signing"},
index b59e14b0b5ed6fe57867d92d2752e8dacd3a6b4e..88ce8fd98d9d4cbe7e308f62ac4e807b72bd9726 100644 (file)
@@ -96,7 +96,10 @@ const OPTIONS smime_options[] = {
     {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"},
     {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"},
 
-    {"certfile", OPT_CERTFILE, '<', "Other certificates file"},
+    {"certfile", OPT_CERTFILE, '<',
+     "Extra signer and intermediate CA certificates to include when signing"},
+    {OPT_MORE_STR, 0, 0,
+     "or to use as preferred signer certs and for chain building when verifying"},
     {"recip", OPT_RECIP, '<', "Recipient certificate file for decryption"},
 
     OPT_SECTION("Email"),
index 4df4487cbc28f13065abc5584f8fefd414707db0..3bc70a7b30bf083211762ed6001c06625a01ec81 100644 (file)
@@ -15,6 +15,7 @@
 #include <openssl/cms.h>
 #include "cms_local.h"
 #include "crypto/asn1.h"
+#include "crypto/x509.h"
 
 static BIO *cms_get_text_bio(BIO *out, unsigned int flags)
 {
@@ -308,7 +309,7 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
 {
     CMS_SignerInfo *si;
     STACK_OF(CMS_SignerInfo) *sinfos;
-    STACK_OF(X509) *cms_certs = NULL;
+    STACK_OF(X509) *untrusted = NULL;
     STACK_OF(X509_CRL) *crls = NULL;
     STACK_OF(X509) **si_chains = NULL;
     X509 *signer;
@@ -360,13 +361,21 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
             if (si_chains == NULL)
                 goto err;
         }
-        cms_certs = CMS_get1_certs(cms);
-        if (!(flags & CMS_NOCRL))
-            crls = CMS_get1_crls(cms);
+        if ((untrusted = CMS_get1_certs(cms)) == NULL)
+            goto err;
+        if (sk_X509_num(certs) > 0
+            && !ossl_x509_add_certs_new(&untrusted, certs,
+                                        X509_ADD_FLAG_UP_REF |
+                                        X509_ADD_FLAG_NO_DUP))
+            goto err;
+
+        if ((flags & CMS_NOCRL) == 0
+            && (crls = CMS_get1_crls(cms)) == NULL)
+            goto err;
         for (i = 0; i < scount; i++) {
             si = sk_CMS_SignerInfo_value(sinfos, i);
 
-            if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls,
+            if (!cms_signerinfo_verify_cert(si, store, untrusted, crls,
                                             si_chains ? &si_chains[i] : NULL,
                                             ctx))
                 goto err;
@@ -482,7 +491,7 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
             OSSL_STACK_OF_X509_free(si_chains[i]);
         OPENSSL_free(si_chains);
     }
-    OSSL_STACK_OF_X509_free(cms_certs);
+    sk_X509_pop_free(untrusted, X509_free);
     sk_X509_CRL_pop_free(crls, X509_CRL_free);
 
     return ret;
index 7be292854296445d13ba56bc8e9475c92d6762cc..05ca70ae24c5887523986e7ab686ec097e1edaef 100644 (file)
@@ -413,7 +413,7 @@ PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey,
     return NULL;
 }
 
-static STACK_OF(X509) *pkcs7_get_signer_certs(const PKCS7 *p7)
+STACK_OF(X509) *pkcs7_get0_certificates(const PKCS7 *p7)
 {
     if (p7->d.ptr == NULL)
         return NULL;
@@ -454,7 +454,7 @@ void ossl_pkcs7_resolve_libctx(PKCS7 *p7)
 
     rinfos = pkcs7_get_recipient_info(p7);
     sinfos = PKCS7_get_signer_info(p7);
-    certs = pkcs7_get_signer_certs(p7);
+    certs = pkcs7_get0_certificates(p7);
 
     for (i = 0; i < sk_X509_num(certs); i++)
         ossl_x509_set0_libctx(sk_X509_value(certs, i), libctx, propq);
index 8deb342b79134d16860b90585c7ed1ce7006beee..7e9335f6017157145d898f9070c5bde554926a25 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "crypto/pkcs7.h"
 
+STACK_OF(X509) *pkcs7_get0_certificates(const PKCS7 *p7);
 const PKCS7_CTX *ossl_pkcs7_get0_ctx(const PKCS7 *p7);
 OSSL_LIB_CTX *ossl_pkcs7_ctx_get0_libctx(const PKCS7_CTX *ctx);
 const char *ossl_pkcs7_ctx_get0_propq(const PKCS7_CTX *ctx);
index 747c41771866e5071f9b587c7939a610a6d8c31f..3f9ba3b7d6df4f7b5d1fc1c7ad1a2ef25e0206c3 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <stdio.h>
 #include "internal/cryptlib.h"
+#include "crypto/x509.h"
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include "pk7_local.h"
@@ -215,6 +216,8 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
                  BIO *indata, BIO *out, int flags)
 {
     STACK_OF(X509) *signers;
+    STACK_OF(X509) *included_certs;
+    STACK_OF(X509) *untrusted = NULL;
     X509 *signer;
     STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
     PKCS7_SIGNER_INFO *si;
@@ -272,21 +275,24 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
                                      ossl_pkcs7_ctx_get0_propq(p7_ctx));
     if (cert_ctx == NULL)
         goto err;
-    if (!(flags & PKCS7_NOVERIFY))
+    if ((flags & PKCS7_NOVERIFY) == 0) {
+        if (!ossl_x509_add_certs_new(&untrusted, certs, X509_ADD_FLAG_NO_DUP))
+            goto err;
+        included_certs = pkcs7_get0_certificates(p7);
+        if ((flags & PKCS7_NOCHAIN) == 0
+            && !ossl_x509_add_certs_new(&untrusted, included_certs,
+                                        X509_ADD_FLAG_NO_DUP))
+            goto err;
+
         for (k = 0; k < sk_X509_num(signers); k++) {
             signer = sk_X509_value(signers, k);
-            if (!(flags & PKCS7_NOCHAIN)) {
-                if (!X509_STORE_CTX_init(cert_ctx, store, signer,
-                                         p7->d.sign->cert)) {
-                    ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB);
-                    goto err;
-                }
-                if (!X509_STORE_CTX_set_default(cert_ctx, "smime_sign"))
-                    goto err;
-            } else if (!X509_STORE_CTX_init(cert_ctx, store, signer, NULL)) {
+            if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted)) {
                 ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB);
                 goto err;
             }
+            if ((flags & PKCS7_NOCHAIN) == 0
+                    && !X509_STORE_CTX_set_default(cert_ctx, "smime_sign"))
+                goto err;
             if (!(flags & PKCS7_NOCRL))
                 X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl);
             i = X509_verify_cert(cert_ctx);
@@ -299,6 +305,7 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
             }
             /* Check for revocation status here */
         }
+    }
 
     if ((p7bio = PKCS7_dataInit(p7, indata)) == NULL)
         goto err;
@@ -353,13 +360,14 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
         BIO_pop(p7bio);
     BIO_free_all(p7bio);
     sk_X509_free(signers);
+    sk_X509_free(untrusted);
     return ret;
 }
 
 STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs,
                                    int flags)
 {
-    STACK_OF(X509) *signers;
+    STACK_OF(X509) *signers, *included_certs;
     STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
     PKCS7_SIGNER_INFO *si;
     PKCS7_ISSUER_AND_SERIAL *ias;
@@ -375,6 +383,7 @@ STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs,
         ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE);
         return NULL;
     }
+    included_certs = pkcs7_get0_certificates(p7);
 
     /* Collect all the signers together */
 
@@ -395,14 +404,11 @@ STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs,
         ias = si->issuer_and_serial;
         signer = NULL;
         /* If any certificates passed they take priority */
-        if (certs != NULL)
-            signer = X509_find_by_issuer_and_serial(certs,
+        signer = X509_find_by_issuer_and_serial(certs,
+                                                ias->issuer, ias->serial);
+        if (signer == NULL && (flags & PKCS7_NOINTERN) == 0)
+            signer = X509_find_by_issuer_and_serial(included_certs,
                                                     ias->issuer, ias->serial);
-        if (signer == NULL && !(flags & PKCS7_NOINTERN)
-            && p7->d.sign->cert)
-            signer =
-                X509_find_by_issuer_and_serial(p7->d.sign->cert,
-                                               ias->issuer, ias->serial);
         if (signer == NULL) {
             ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND);
             sk_X509_free(signers);
index 78be2e6c09006907a460ff597573bee657c7eea1..43a9a1497941ce73f094e3f8beb9754cd40e122f 100644 (file)
@@ -453,8 +453,9 @@ used multiple times if more than one signer is required.
 =item B<-certfile> I<file>
 
 Allows additional certificates to be specified. When signing these will
-be included with the message. When verifying these will be searched for
-the signers certificates.
+be included with the message. When verifying, these will be searched for
+signer certificates and will be used for chain building.
+
 The input can be in PEM, DER, or PKCS#12 format.
 
 =item B<-cades>
index 4d8d6f52cb4cd3f5e48c5225975a311a360f7da0..365276415301f772164619df467305a844afbed6 100644 (file)
@@ -234,8 +234,9 @@ option is present B<CRLF> is used instead.
 =item B<-certfile> I<file>
 
 Allows additional certificates to be specified. When signing these will
-be included with the message. When verifying these will be searched for
-the signers certificates.
+be included with the message. When verifying, these will be searched for
+signer certificates and will be used for chain building.
+
 The input can be in PEM, DER, or PKCS#12 format.
 
 =item B<-signer> I<file>
index bd46a1262cffc867482ea1bf991f72b1e5143de8..3f3488b2f682debf4f17c0a1ffc1c80f3f67cf64 100644 (file)
@@ -26,6 +26,8 @@ B<CMS SignedData> structure contained in a structure of type B<CMS_ContentInfo>.
 I<cms> points to the B<CMS_ContentInfo> structure to verify.
 The optional I<certs> parameter refers to a set of certificates
 in which to search for signing certificates.
+It is also used
+as a source of untrusted intermediate CA certificates for chain building.
 I<cms> may contain extra untrusted CA certificates that may be used for
 chain building as well as CRLs that may be used for certificate validation.
 I<store> may be NULL or point to
index 5d4f6ad9e1d84a51e9ec4a6f208f21ad5eebaf18..99afa0ea1581c82d80b7ef139ac39b454b403116 100644 (file)
@@ -19,6 +19,8 @@ PKCS7_verify() is very similar to L<CMS_verify(3)>.
 It verifies a PKCS#7 signedData structure given in I<p7>.
 The optional I<certs> parameter refers to a set of certificates
 in which to search for signer's certificates.
+It is also used
+as a source of untrusted intermediate CA certificates for chain building.
 I<p7> may contain extra untrusted CA certificates that may be used for
 chain building as well as CRLs that may be used for certificate validation.
 I<store> may be NULL or point to
index 07014945a7d82683fedb6438f3afbff610bb521a..59756cbd861538230098bbda34ba2e3a4f81ba24 100644 (file)
@@ -1044,6 +1044,53 @@ subtest "CMS signed digest, S/MIME format" => sub {
        "Verify CMS signed digest, S/MIME format");
 };
 
+sub path_tests {
+    our $app = shift;
+    our @path = qw(test certs);
+    our $key = srctop_file(@path, "ee-key.pem");
+    our $ee = srctop_file(@path, "ee-cert.pem");
+    our $ca = srctop_file(@path, "ca-cert.pem");
+    our $root = srctop_file(@path, "root-cert.pem");
+    our $sig_file = "signature.p7s";
+
+    sub sign {
+        my $inter = shift;
+        my @inter = $inter ? ("-certfile", $inter) : ();
+        my $msg = shift;
+        ok(run(app(["openssl", $app, @prov, "-sign", "-in", $smcont,
+                    "-inkey", $key, "-signer", $ee, @inter,
+                    "-out", $sig_file],
+                   "accept $app sign with EE $msg".
+                   " intermediate CA certificates")));
+    }
+    sub verify {
+        my $inter = shift;
+        my @inter = $inter ? ("-certfile", $inter) : ();
+        my $msg = shift;
+        my $res = shift;
+        ok($res == run(app(["openssl", $app, @prov, "-verify", "-in", $sig_file,
+                            "-purpose", "sslserver", "-CAfile", $root, @inter,
+                            "-content", $smcont],
+                           "accept $app verify with EE ".
+                           "$msg intermediate CA certificates")));
+    }
+    sign($ca, "and");
+    verify(0, "with included", 1);
+    sign(0, "without");
+    verify(0, "without", 0);
+    verify($ca, "with added", 1);
+};
+subtest "CMS sign+verify cert path tests" => sub {
+    plan tests => 5;
+
+    path_tests("cms");
+};
+subtest "PKCS7 sign+verify cert path tests" => sub {
+    plan tests => 5;
+
+    path_tests("smime");
+};
+
 subtest "CMS code signing test" => sub {
     plan tests => 7;
     my $sig_file = "signature.p7s";