Skip to content

Commit

Permalink
{CMS,PKCS7}_verify(): use 'certs' parameter ('-certfile' option) also…
Browse files Browse the repository at this point in the history
… for chain building
  • Loading branch information
DDvO committed Oct 6, 2023
1 parent 8176c76 commit f13b738
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 33 deletions.
5 changes: 4 additions & 1 deletion apps/cms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand Down
5 changes: 4 additions & 1 deletion apps/smime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
21 changes: 15 additions & 6 deletions crypto/cms/cms_smime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -307,7 +308,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;
Expand Down Expand Up @@ -359,13 +360,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;
Expand Down Expand Up @@ -481,7 +490,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);
OSSL_STACK_OF_X509_free(untrusted);
sk_X509_CRL_pop_free(crls, X509_CRL_free);

return ret;
Expand Down
4 changes: 2 additions & 2 deletions crypto/pkcs7/pk7_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions crypto/pkcs7/pk7_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
43 changes: 25 additions & 18 deletions crypto/pkcs7/pk7_smime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -272,21 +275,25 @@ 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 (certs != NULL && (untrusted = X509_chain_up_ref(certs)) == NULL)
goto err;
included_certs = pkcs7_get0_certificates(p7);
if ((flags & PKCS7_NOCHAIN) == 0 && sk_X509_num(included_certs) > 0
&& !ossl_x509_add_certs_new(&untrusted, included_certs,
X509_ADD_FLAG_UP_REF |
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);
Expand All @@ -300,6 +307,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;
Expand Down Expand Up @@ -354,13 +362,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;
Expand All @@ -376,6 +385,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 */

Expand All @@ -396,14 +406,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);
Expand Down
5 changes: 3 additions & 2 deletions doc/man1/openssl-cms.pod.in
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
5 changes: 3 additions & 2 deletions doc/man1/openssl-smime.pod.in
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 2 additions & 0 deletions doc/man3/CMS_verify.pod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions doc/man3/PKCS7_verify.pod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 34 additions & 1 deletion test/recipes/80-test_cms.t
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib)

$no_rc2 = 1 if disabled("legacy");

plan tests => 21;
plan tests => 22;

ok(run(test(["pkcs7_test"])), "test pkcs7");

Expand Down Expand Up @@ -1035,6 +1035,39 @@ subtest "CMS signed digest, S/MIME format" => sub {
"Verify CMS signed digest, S/MIME format");
};


subtest "CMS signing cert path test" => sub {
plan tests => 5;
my @path = qw(test certs);
my $key = srctop_file(@path, "ee-key.pem");
my $ee = srctop_file(@path, "ee-cert.pem");
my $ca = srctop_file(@path, "ca-cert.pem");
my $root = srctop_file(@path, "root-cert.pem");
my $sig_file = "signature.p7s";
ok(run(app(["openssl", "cms", @prov, "-sign", "-in", $smcont,
"-inkey", $key, "-signer", $ee, "-certfile", $ca,
"-out", $sig_file])),
"accept perform CMS signature with EE and intermediate CA certificates");

ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
"-purpose", "sslserver",
"-CAfile", $root, "-content", $smcont])),
"accept verify CMS signature with included intermediate CA certificate");

ok(run(app(["openssl", "cms", @prov, "-sign", "-in", $smcont,
"-inkey", $key, "-signer", $ee,
"-out", $sig_file])),
"accept perform CMS signature with just EE certificate");
ok(!run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
"-purpose", "sslserver",
"-CAfile", $root, "-content", $smcont])),
"accept verify CMS signature without intermediate CA certificate");
ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
"-purpose", "sslserver",
"-certfile", $ca, "-CAfile", $root, "-content", $smcont])),
"accept verify CMS signature with added intermediate CA certificate");
};

subtest "CMS code signing test" => sub {
plan tests => 7;
my $sig_file = "signature.p7s";
Expand Down

0 comments on commit f13b738

Please sign in to comment.