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"},
{"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"),
#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)
{
{
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;
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;
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;
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;
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);
#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);
#include <stdio.h>
#include "internal/cryptlib.h"
+#include "crypto/x509.h"
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "pk7_local.h"
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;
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);
}
/* Check for revocation status here */
}
+ }
if ((p7bio = PKCS7_dataInit(p7, indata)) == NULL)
goto err;
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;
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE);
return NULL;
}
+ included_certs = pkcs7_get0_certificates(p7);
/* Collect all the signers together */
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);
=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>
=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>
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
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
"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";