{CMS,PKCS7}_verify(): use 'certs' parameter ('-certfile' option) also for chain building
Reviewed-by: Viktor Dukhovni <viktor@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/18916)
This commit is contained in:
parent
cc31db1eb6
commit
29bbe7d008
11 changed files with 107 additions and 32 deletions
|
@ -175,7 +175,10 @@ const OPTIONS cms_options[] = {
|
||||||
OPT_SECTION("Signing"),
|
OPT_SECTION("Signing"),
|
||||||
{"md", OPT_MD, 's', "Digest algorithm to use"},
|
{"md", OPT_MD, 's', "Digest algorithm to use"},
|
||||||
{"signer", OPT_SIGNER, 's', "Signer certificate input file"},
|
{"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, '-',
|
{"cades", OPT_CADES, '-',
|
||||||
"Include signingCertificate attribute (CAdES-BES)"},
|
"Include signingCertificate attribute (CAdES-BES)"},
|
||||||
{"nodetach", OPT_NODETACH, '-', "Use opaque signing"},
|
{"nodetach", OPT_NODETACH, '-', "Use opaque signing"},
|
||||||
|
|
|
@ -96,7 +96,10 @@ const OPTIONS smime_options[] = {
|
||||||
{"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"},
|
{"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"},
|
||||||
{"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"},
|
{"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"},
|
{"recip", OPT_RECIP, '<', "Recipient certificate file for decryption"},
|
||||||
|
|
||||||
OPT_SECTION("Email"),
|
OPT_SECTION("Email"),
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <openssl/cms.h>
|
#include <openssl/cms.h>
|
||||||
#include "cms_local.h"
|
#include "cms_local.h"
|
||||||
#include "crypto/asn1.h"
|
#include "crypto/asn1.h"
|
||||||
|
#include "crypto/x509.h"
|
||||||
|
|
||||||
static BIO *cms_get_text_bio(BIO *out, unsigned int flags)
|
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;
|
CMS_SignerInfo *si;
|
||||||
STACK_OF(CMS_SignerInfo) *sinfos;
|
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_CRL) *crls = NULL;
|
||||||
STACK_OF(X509) **si_chains = NULL;
|
STACK_OF(X509) **si_chains = NULL;
|
||||||
X509 *signer;
|
X509 *signer;
|
||||||
|
@ -360,13 +361,21 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
|
||||||
if (si_chains == NULL)
|
if (si_chains == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
cms_certs = CMS_get1_certs(cms);
|
if ((untrusted = CMS_get1_certs(cms)) == NULL)
|
||||||
if (!(flags & CMS_NOCRL))
|
goto err;
|
||||||
crls = CMS_get1_crls(cms);
|
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++) {
|
for (i = 0; i < scount; i++) {
|
||||||
si = sk_CMS_SignerInfo_value(sinfos, 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,
|
si_chains ? &si_chains[i] : NULL,
|
||||||
ctx))
|
ctx))
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -482,7 +491,7 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
|
||||||
OSSL_STACK_OF_X509_free(si_chains[i]);
|
OSSL_STACK_OF_X509_free(si_chains[i]);
|
||||||
OPENSSL_free(si_chains);
|
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);
|
sk_X509_CRL_pop_free(crls, X509_CRL_free);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -413,7 +413,7 @@ PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey,
|
||||||
return NULL;
|
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)
|
if (p7->d.ptr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -454,7 +454,7 @@ void ossl_pkcs7_resolve_libctx(PKCS7 *p7)
|
||||||
|
|
||||||
rinfos = pkcs7_get_recipient_info(p7);
|
rinfos = pkcs7_get_recipient_info(p7);
|
||||||
sinfos = PKCS7_get_signer_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++)
|
for (i = 0; i < sk_X509_num(certs); i++)
|
||||||
ossl_x509_set0_libctx(sk_X509_value(certs, i), libctx, propq);
|
ossl_x509_set0_libctx(sk_X509_value(certs, i), libctx, propq);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "crypto/pkcs7.h"
|
#include "crypto/pkcs7.h"
|
||||||
|
|
||||||
|
STACK_OF(X509) *pkcs7_get0_certificates(const PKCS7 *p7);
|
||||||
const PKCS7_CTX *ossl_pkcs7_get0_ctx(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);
|
OSSL_LIB_CTX *ossl_pkcs7_ctx_get0_libctx(const PKCS7_CTX *ctx);
|
||||||
const char *ossl_pkcs7_ctx_get0_propq(const PKCS7_CTX *ctx);
|
const char *ossl_pkcs7_ctx_get0_propq(const PKCS7_CTX *ctx);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "internal/cryptlib.h"
|
#include "internal/cryptlib.h"
|
||||||
|
#include "crypto/x509.h"
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
#include "pk7_local.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)
|
BIO *indata, BIO *out, int flags)
|
||||||
{
|
{
|
||||||
STACK_OF(X509) *signers;
|
STACK_OF(X509) *signers;
|
||||||
|
STACK_OF(X509) *included_certs;
|
||||||
|
STACK_OF(X509) *untrusted = NULL;
|
||||||
X509 *signer;
|
X509 *signer;
|
||||||
STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
|
STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
|
||||||
PKCS7_SIGNER_INFO *si;
|
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));
|
ossl_pkcs7_ctx_get0_propq(p7_ctx));
|
||||||
if (cert_ctx == NULL)
|
if (cert_ctx == NULL)
|
||||||
goto err;
|
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++) {
|
for (k = 0; k < sk_X509_num(signers); k++) {
|
||||||
signer = sk_X509_value(signers, k);
|
signer = sk_X509_value(signers, k);
|
||||||
if (!(flags & PKCS7_NOCHAIN)) {
|
if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted)) {
|
||||||
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)) {
|
|
||||||
ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB);
|
ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
if ((flags & PKCS7_NOCHAIN) == 0
|
||||||
|
&& !X509_STORE_CTX_set_default(cert_ctx, "smime_sign"))
|
||||||
|
goto err;
|
||||||
if (!(flags & PKCS7_NOCRL))
|
if (!(flags & PKCS7_NOCRL))
|
||||||
X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl);
|
X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl);
|
||||||
i = X509_verify_cert(cert_ctx);
|
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 */
|
/* Check for revocation status here */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((p7bio = PKCS7_dataInit(p7, indata)) == NULL)
|
if ((p7bio = PKCS7_dataInit(p7, indata)) == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -353,13 +360,14 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
|
||||||
BIO_pop(p7bio);
|
BIO_pop(p7bio);
|
||||||
BIO_free_all(p7bio);
|
BIO_free_all(p7bio);
|
||||||
sk_X509_free(signers);
|
sk_X509_free(signers);
|
||||||
|
sk_X509_free(untrusted);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs,
|
STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
STACK_OF(X509) *signers;
|
STACK_OF(X509) *signers, *included_certs;
|
||||||
STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
|
STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
|
||||||
PKCS7_SIGNER_INFO *si;
|
PKCS7_SIGNER_INFO *si;
|
||||||
PKCS7_ISSUER_AND_SERIAL *ias;
|
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);
|
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
included_certs = pkcs7_get0_certificates(p7);
|
||||||
|
|
||||||
/* Collect all the signers together */
|
/* 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;
|
ias = si->issuer_and_serial;
|
||||||
signer = NULL;
|
signer = NULL;
|
||||||
/* If any certificates passed they take priority */
|
/* 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);
|
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) {
|
if (signer == NULL) {
|
||||||
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND);
|
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND);
|
||||||
sk_X509_free(signers);
|
sk_X509_free(signers);
|
||||||
|
|
|
@ -453,8 +453,9 @@ used multiple times if more than one signer is required.
|
||||||
=item B<-certfile> I<file>
|
=item B<-certfile> I<file>
|
||||||
|
|
||||||
Allows additional certificates to be specified. When signing these will
|
Allows additional certificates to be specified. When signing these will
|
||||||
be included with the message. When verifying these will be searched for
|
be included with the message. When verifying, these will be searched for
|
||||||
the signers certificates.
|
signer certificates and will be used for chain building.
|
||||||
|
|
||||||
The input can be in PEM, DER, or PKCS#12 format.
|
The input can be in PEM, DER, or PKCS#12 format.
|
||||||
|
|
||||||
=item B<-cades>
|
=item B<-cades>
|
||||||
|
|
|
@ -234,8 +234,9 @@ option is present B<CRLF> is used instead.
|
||||||
=item B<-certfile> I<file>
|
=item B<-certfile> I<file>
|
||||||
|
|
||||||
Allows additional certificates to be specified. When signing these will
|
Allows additional certificates to be specified. When signing these will
|
||||||
be included with the message. When verifying these will be searched for
|
be included with the message. When verifying, these will be searched for
|
||||||
the signers certificates.
|
signer certificates and will be used for chain building.
|
||||||
|
|
||||||
The input can be in PEM, DER, or PKCS#12 format.
|
The input can be in PEM, DER, or PKCS#12 format.
|
||||||
|
|
||||||
=item B<-signer> I<file>
|
=item B<-signer> I<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.
|
I<cms> points to the B<CMS_ContentInfo> structure to verify.
|
||||||
The optional I<certs> parameter refers to a set of certificates
|
The optional I<certs> parameter refers to a set of certificates
|
||||||
in which to search for signing 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
|
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.
|
chain building as well as CRLs that may be used for certificate validation.
|
||||||
I<store> may be NULL or point to
|
I<store> may be NULL or point to
|
||||||
|
|
|
@ -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>.
|
It verifies a PKCS#7 signedData structure given in I<p7>.
|
||||||
The optional I<certs> parameter refers to a set of certificates
|
The optional I<certs> parameter refers to a set of certificates
|
||||||
in which to search for signer's 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
|
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.
|
chain building as well as CRLs that may be used for certificate validation.
|
||||||
I<store> may be NULL or point to
|
I<store> may be NULL or point to
|
||||||
|
|
|
@ -1044,6 +1044,53 @@ subtest "CMS signed digest, S/MIME format" => sub {
|
||||||
"Verify CMS signed digest, S/MIME format");
|
"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 {
|
subtest "CMS code signing test" => sub {
|
||||||
plan tests => 7;
|
plan tests => 7;
|
||||||
my $sig_file = "signature.p7s";
|
my $sig_file = "signature.p7s";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue