summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFdaSilvaYY <fdasilvayy@gmail.com>2019-06-12 19:52:39 +0200
committerTomas Mraz <tmraz@fedoraproject.org>2020-05-27 13:16:30 +0200
commit9e3c510bde91350c5a40b7ba4e9e0945895e9368 (patch)
tree1720a2cfea2ffded3a4e374e2c6e110f2499dbc4
parentf7f53d7d61bba235b8babf4cf580114d74183e3e (diff)
crypto/cms: add CAdES-BES signed attributes validation
for signing certificate V2 and signing certificate extensions. CAdES: lowercase name for now internal methods. crypto/cms: generated file changes. Add some CHANGES entries. [extended tests] Reviewed-by: Shane Lontis <shane.lontis@oracle.com> Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/8098)
-rw-r--r--CHANGES.md9
-rw-r--r--apps/cms.c13
-rw-r--r--crypto/cms/cms_err.c4
-rw-r--r--crypto/cms/cms_ess.c92
-rw-r--r--crypto/cms/cms_local.h3
-rw-r--r--crypto/cms/cms_smime.c43
-rw-r--r--crypto/err/openssl.txt4
-rw-r--r--crypto/ess/build.info9
-rw-r--r--crypto/ess/ess_asn1.c62
-rw-r--r--crypto/ess/ess_err.c2
-rw-r--r--crypto/ess/ess_lib.c98
-rw-r--r--crypto/ts/ts_rsp_verify.c93
-rw-r--r--doc/man1/openssl-cms.pod.in10
-rw-r--r--doc/man3/CMS_verify.pod10
-rw-r--r--include/crypto/cms.h10
-rw-r--r--include/crypto/ess.h6
-rw-r--r--include/openssl/cmserr.h4
-rw-r--r--include/openssl/esserr.h3
-rw-r--r--test/recipes/80-test_cms.t137
19 files changed, 462 insertions, 150 deletions
diff --git a/CHANGES.md b/CHANGES.md
index eb8659e9cf..10fd8d541d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -23,6 +23,15 @@ OpenSSL 3.0
### Changes between 1.1.1 and 3.0 [xx XXX xxxx]
+ * Add CAdES-BES signature verification support, mostly derived
+ from ESSCertIDv2 TS (RFC 5816) contribution by Marek Klein.
+
+ *Filipe Raimundo da Silva*
+
+ * Add CAdES-BES signature scheme and attributes support (RFC 5126) to CMS API.
+
+ *Antonio Iacono*
+
* Deprecated EC_POINT_make_affine() and EC_POINTs_make_affine(). These
functions are not widely used and now OpenSSL automatically perform this
conversion when needed.
diff --git a/apps/cms.c b/apps/cms.c
index 6b5577ecee..445fec5388 100644
--- a/apps/cms.c
+++ b/apps/cms.c
@@ -670,12 +670,18 @@ int cms_main(int argc, char **argv)
goto opthelp;
}
- if (flags & CMS_CADES) {
- if (flags & CMS_NOATTR) {
+ if ((flags & CMS_CADES) != 0) {
+ if ((flags & CMS_NOATTR) != 0) {
BIO_puts(bio_err, "Incompatible options: "
"CAdES required signed attributes\n");
goto opthelp;
}
+ if (operation == SMIME_VERIFY
+ && (flags & (CMS_NO_SIGNER_CERT_VERIFY | CMS_NO_ATTR_VERIFY)) != 0) {
+ BIO_puts(bio_err, "Incompatible options: CAdES validation require"
+ " certs and signed attributes validations\n");
+ goto opthelp;
+ }
}
if (operation & SMIME_SIGNERS) {
@@ -1115,7 +1121,8 @@ int cms_main(int argc, char **argv)
goto end;
} else if (operation == SMIME_VERIFY) {
if (CMS_verify(cms, other, store, indata, out, flags) > 0) {
- BIO_printf(bio_err, "Verification successful\n");
+ BIO_printf(bio_err, "%s Verification successful\n",
+ (flags & CMS_CADES) ? "CAdES" : "CMS");
} else {
BIO_printf(bio_err, "Verification failure\n");
if (verify_retcode)
diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c
index 526d77357e..16e25afc7f 100644
--- a/crypto/cms/cms_err.c
+++ b/crypto/cms/cms_err.c
@@ -52,6 +52,10 @@ static const ERR_STRING_DATA CMS_str_reasons[] = {
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_SETTING_KEY), "error setting key"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_SETTING_RECIPIENTINFO),
"error setting recipientinfo"},
+ {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE),
+ "ess no signing certid attribute"},
+ {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR),
+ "ess signing certid mismatch error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_ENCRYPTED_KEY_LENGTH),
"invalid encrypted key length"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER),
diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c
index 3901074033..e3604f7db8 100644
--- a/crypto/cms/cms_ess.c
+++ b/crypto/cms/cms_ess.c
@@ -21,6 +21,9 @@
DEFINE_STACK_OF(GENERAL_NAMES)
DEFINE_STACK_OF(CMS_SignerInfo)
+DEFINE_STACK_OF(ESS_CERT_ID)
+DEFINE_STACK_OF(ESS_CERT_ID_V2)
+DEFINE_STACK_OF(X509)
IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
@@ -29,33 +32,100 @@ IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
{
ASN1_STRING *str;
- CMS_ReceiptRequest *rr = NULL;
- if (prr)
+ CMS_ReceiptRequest *rr;
+ ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_receiptRequest);
+
+ if (prr != NULL)
*prr = NULL;
- str = CMS_signed_get0_data_by_OBJ(si,
- OBJ_nid2obj
- (NID_id_smime_aa_receiptRequest), -3,
- V_ASN1_SEQUENCE);
- if (!str)
+ str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE);
+ if (str == NULL)
return 0;
rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
- if (!rr)
+ if (rr == NULL)
return -1;
- if (prr)
+ if (prr != NULL)
*prr = rr;
else
CMS_ReceiptRequest_free(rr);
return 1;
}
+/*
+ First, get the ESS_SIGNING_CERT(V2) signed attribute from |si|.
+ Then check matching of each cert of trust |chain| with one of
+ the |cert_ids|(Hash+IssuerID) list from this ESS_SIGNING_CERT.
+ Derived from ts_check_signing_certs()
+*/
+int ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain)
+{
+ ESS_SIGNING_CERT *ss = NULL;
+ ESS_SIGNING_CERT_V2 *ssv2 = NULL;
+ X509 *cert;
+ int i = 0, ret = 0;
+
+ if (cms_signerinfo_get_signing_cert(si, &ss) > 0 && ss->cert_ids != NULL) {
+ STACK_OF(ESS_CERT_ID) *cert_ids = ss->cert_ids;
+
+ cert = sk_X509_value(chain, 0);
+ if (ess_find_cert(cert_ids, cert) != 0)
+ goto err;
+
+ /*
+ * Check the other certificates of the chain.
+ * Fail if no signing certificate ids found for each certificate.
+ */
+ if (sk_ESS_CERT_ID_num(cert_ids) > 1) {
+ /* for each chain cert, try to find its cert id */
+ for (i = 1; i < sk_X509_num(chain); ++i) {
+ cert = sk_X509_value(chain, i);
+ if (ess_find_cert(cert_ids, cert) < 0)
+ goto err;
+ }
+ }
+ } else if (cms_signerinfo_get_signing_cert_v2(si, &ssv2) > 0
+ && ssv2->cert_ids!= NULL) {
+ STACK_OF(ESS_CERT_ID_V2) *cert_ids_v2 = ssv2->cert_ids;
+
+ cert = sk_X509_value(chain, 0);
+ if (ess_find_cert_v2(cert_ids_v2, cert) != 0)
+ goto err;
+
+ /*
+ * Check the other certificates of the chain.
+ * Fail if no signing certificate ids found for each certificate.
+ */
+ if (sk_ESS_CERT_ID_V2_num(cert_ids_v2) > 1) {
+ /* for each chain cert, try to find its cert id */
+ for (i = 1; i < sk_X509_num(chain); ++i) {
+ cert = sk_X509_value(chain, i);
+ if (ess_find_cert_v2(cert_ids_v2, cert) < 0)
+ goto err;
+ }
+ }
+ } else {
+ CMSerr(CMS_F_ESS_CHECK_SIGNING_CERTS,
+ CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE);
+ return 0;
+ }
+ ret = 1;
+ err:
+ if (!ret)
+ CMSerr(CMS_F_ESS_CHECK_SIGNING_CERTS,
+ CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR);
+
+ ESS_SIGNING_CERT_free(ss);
+ ESS_SIGNING_CERT_V2_free(ssv2);
+ return ret;
+}
+
CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
int allorfirst,
STACK_OF(GENERAL_NAMES)
*receiptList, STACK_OF(GENERAL_NAMES)
*receiptsTo)
{
- CMS_ReceiptRequest *rr = NULL;
+ CMS_ReceiptRequest *rr;
rr = CMS_ReceiptRequest_new();
if (rr == NULL)
@@ -145,6 +215,7 @@ static int cms_msgSigDigest(CMS_SignerInfo *si,
unsigned char *dig, unsigned int *diglen)
{
const EVP_MD *md;
+
md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
if (md == NULL)
return 0;
@@ -160,6 +231,7 @@ int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
{
unsigned char dig[EVP_MAX_MD_SIZE];
unsigned int diglen;
+
if (!cms_msgSigDigest(src, dig, &diglen)) {
CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
return 0;
diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h
index 00ea9006c8..68c885622b 100644
--- a/crypto/cms/cms_local.h
+++ b/crypto/cms/cms_local.h
@@ -421,6 +421,9 @@ int cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, CMS_RecipientInfo *
/* SignerInfo routines */
int CMS_si_check_attributes(const CMS_SignerInfo *si);
+/* ESS routines */
+int ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain);
+
DECLARE_ASN1_ITEM(CMS_CertificateChoices)
DECLARE_ASN1_ITEM(CMS_DigestedData)
DECLARE_ASN1_ITEM(CMS_EncryptedData)
diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c
index dbdc815e97..a83edce0f7 100644
--- a/crypto/cms/cms_smime.c
+++ b/crypto/cms/cms_smime.c
@@ -233,7 +233,8 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
X509_STORE *store,
STACK_OF(X509) *certs,
- STACK_OF(X509_CRL) *crls)
+ STACK_OF(X509_CRL) *crls,
+ STACK_OF(X509) **chain)
{
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
X509 *signer;
@@ -262,6 +263,10 @@ static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
goto err;
}
r = 1;
+
+ /* also send back the trust chain when required */
+ if (chain != NULL)
+ *chain = X509_STORE_CTX_get1_chain(ctx);
err:
X509_STORE_CTX_free(ctx);
return r;
@@ -275,9 +280,11 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
STACK_OF(CMS_SignerInfo) *sinfos;
STACK_OF(X509) *cms_certs = NULL;
STACK_OF(X509_CRL) *crls = NULL;
+ STACK_OF(X509) **si_chains = NULL;
X509 *signer;
int i, scount = 0, ret = 0;
BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL;
+ int cadesVerify = (flags & CMS_CADES) != 0;
if (!dcont && !check_content(cms))
return 0;
@@ -312,27 +319,44 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
}
/* Attempt to verify all signers certs */
-
- if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) {
+ /* at this point scount == sk_CMS_SignerInfo_num(sinfos) */
+
+ if ((flags & CMS_NO_SIGNER_CERT_VERIFY) == 0 || cadesVerify) {
+ if (cadesVerify) {
+ /* Certificate trust chain is required to check CAdES signature */
+ si_chains = OPENSSL_zalloc(scount * sizeof(si_chains[0]));
+ if (si_chains == NULL) {
+ CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
cms_certs = CMS_get1_certs(cms);
if (!(flags & CMS_NOCRL))
crls = CMS_get1_crls(cms);
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
+ 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, cms_certs, crls,
+ si_chains ? &si_chains[i] : NULL))
goto err;
}
}
/* Attempt to verify all SignerInfo signed attribute signatures */
- if (!(flags & CMS_NO_ATTR_VERIFY)) {
- for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
+ if ((flags & CMS_NO_ATTR_VERIFY) == 0 || cadesVerify) {
+ for (i = 0; i < scount; i++) {
si = sk_CMS_SignerInfo_value(sinfos, i);
if (CMS_signed_get_attr_count(si) < 0)
continue;
if (CMS_SignerInfo_verify(si) <= 0)
goto err;
+ if (cadesVerify) {
+ STACK_OF(X509) *si_chain = si_chains ? si_chains[i] : NULL;
+
+ if (ess_check_signing_certs(si, si_chain) <= 0)
+ goto err;
+ }
}
}
@@ -420,6 +444,11 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
BIO_free_all(tmpout);
err2:
+ if (si_chains != NULL) {
+ for (i = 0; i < scount; ++i)
+ sk_X509_pop_free(si_chains[i], X509_free);
+ OPENSSL_free(si_chains);
+ }
sk_X509_pop_free(cms_certs, X509_free);
sk_X509_CRL_pop_free(crls, X509_CRL_free);
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 1b2c94b0a2..8afc67e747 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -320,6 +320,7 @@ CMS_F_CMS_SET_DETACHED:147:CMS_set_detached
CMS_F_CMS_SIGN:148:CMS_sign
CMS_F_CMS_SIGNED_DATA_INIT:149:cms_signed_data_init
CMS_F_CMS_SIGNERINFO_CONTENT_SIGN:150:cms_SignerInfo_content_sign
+CMS_F_CMS_SIGNERINFO_GET_CHAIN:184:cms_signerinfo_get_chain
CMS_F_CMS_SIGNERINFO_SIGN:151:CMS_SignerInfo_sign
CMS_F_CMS_SIGNERINFO_VERIFY:152:CMS_SignerInfo_verify
CMS_F_CMS_SIGNERINFO_VERIFY_CERT:153:cms_signerinfo_verify_cert
@@ -329,6 +330,7 @@ CMS_F_CMS_SI_CHECK_ATTRIBUTES:183:CMS_si_check_attributes
CMS_F_CMS_STREAM:155:CMS_stream
CMS_F_CMS_UNCOMPRESS:156:CMS_uncompress
CMS_F_CMS_VERIFY:157:CMS_verify
+CMS_F_ESS_CHECK_SIGNING_CERTS:185:ess_check_signing_certs
CMS_F_KEK_UNWRAP_KEY:180:kek_unwrap_key
COMP_F_BIO_ZLIB_FLUSH:99:bio_zlib_flush
COMP_F_BIO_ZLIB_NEW:100:bio_zlib_new
@@ -2188,6 +2190,8 @@ CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE:114:\
error reading messagedigest attribute
CMS_R_ERROR_SETTING_KEY:115:error setting key
CMS_R_ERROR_SETTING_RECIPIENTINFO:116:error setting recipientinfo
+CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE:182:ess no signing certid attribute
+CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR:183:ess signing certid mismatch error
CMS_R_INVALID_ENCRYPTED_KEY_LENGTH:117:invalid encrypted key length
CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER:176:invalid key encryption parameter
CMS_R_INVALID_KEY_LENGTH:118:invalid key length
diff --git a/crypto/ess/build.info b/crypto/ess/build.info
index 24fcecc8f5..fa2bc41d08 100644
--- a/crypto/ess/build.info
+++ b/crypto/ess/build.info
@@ -1,3 +1,8 @@
LIBS=../../libcrypto
-SOURCE[../../libcrypto]= \
- ess_lib.c ess_asn1.c ess_err.c
+
+IF[{- !$disabled{'cms'} and !$disabled{'ts'} -}]
+ SOURCE[../../libcrypto]= ess_lib.c
+ENDIF
+
+SOURCE[../../libcrypto]= ess_asn1.c ess_err.c
+
diff --git a/crypto/ess/ess_asn1.c b/crypto/ess/ess_asn1.c
index 19589d97f3..a8d13a3a20 100644
--- a/crypto/ess/ess_asn1.c
+++ b/crypto/ess/ess_asn1.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -9,9 +9,11 @@
#include <openssl/err.h>
#include <openssl/asn1t.h>
+#include <openssl/cms.h>
#include <openssl/ess.h>
#include <openssl/x509v3.h>
#include "crypto/ess.h"
+#include "crypto/cms.h"
/* ASN1 stuff for ESS Structure */
@@ -55,3 +57,61 @@ ASN1_SEQUENCE(ESS_SIGNING_CERT_V2) = {
IMPLEMENT_ASN1_FUNCTIONS(ESS_SIGNING_CERT_V2)
IMPLEMENT_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT_V2)
+
+/* No cms support means no CMS_SignerInfo* definitions */
+#ifndef OPENSSL_NO_CMS
+
+/*
+ * Returns < 0 if attribute is not found, 1 if found, or
+ * -1 on attribute parsing failure.
+ */
+int cms_signerinfo_get_signing_cert_v2(CMS_SignerInfo *si,
+ ESS_SIGNING_CERT_V2 **psc)
+{
+ ASN1_STRING *str;
+ ESS_SIGNING_CERT_V2 *sc;
+ ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_signingCertificateV2);
+
+ if (psc != NULL)
+ *psc = NULL;
+ str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE);
+ if (str == NULL)
+ return 0;
+
+ sc = ASN1_item_unpack(str, ASN1_ITEM_rptr(ESS_SIGNING_CERT_V2));
+ if (sc == NULL)
+ return -1;
+ if (psc != NULL)
+ *psc = sc;
+ else
+ ESS_SIGNING_CERT_V2_free(sc);
+ return 1;
+}
+
+/*
+ * Returns < 0 if attribute is not found, 1 if found, or
+ * -1 on attribute parsing failure.
+ */
+int cms_signerinfo_get_signing_cert(CMS_SignerInfo *si,
+ ESS_SIGNING_CERT **psc)
+{
+ ASN1_STRING *str;
+ ESS_SIGNING_CERT *sc;
+ ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_signingCertificate);
+
+ if (psc != NULL)
+ *psc = NULL;
+ str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE);
+ if (str == NULL)
+ return 0;
+
+ sc = ASN1_item_unpack(str, ASN1_ITEM_rptr(ESS_SIGNING_CERT));
+ if (sc == NULL)
+ return -1;
+ if (psc != NULL)
+ *psc = sc;
+ else
+ ESS_SIGNING_CERT_free(sc);
+ return 1;
+}
+#endif /* !OPENSSL_NO_CMS */
diff --git a/crypto/ess/ess_err.c b/crypto/ess/ess_err.c
index b494aa246f..6547645fea 100644
--- a/crypto/ess/ess_err.c
+++ b/crypto/ess/ess_err.c
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
diff --git a/crypto/ess/ess_lib.c b/crypto/ess/ess_lib.c
index 9d9defa9d7..17f9db98ff 100644
--- a/crypto/ess/ess_lib.c
+++ b/crypto/ess/ess_lib.c
@@ -15,8 +15,8 @@
DEFINE_STACK_OF(ESS_CERT_ID)
DEFINE_STACK_OF(ESS_CERT_ID_V2)
-DEFINE_STACK_OF(X509)
DEFINE_STACK_OF(GENERAL_NAME)
+DEFINE_STACK_OF(X509)
static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed);
static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg,
@@ -61,9 +61,12 @@ static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed)
unsigned char cert_sha1[SHA_DIGEST_LENGTH];
/* Call for side-effect of computing hash and caching extensions */
- X509_check_purpose(cert, -1, 0);
+ if (!X509v3_cache_extensions(cert, NULL, NULL))
+ return NULL;
+
if ((cid = ESS_CERT_ID_new()) == NULL)
goto err;
+ /* TODO(3.0): fetch sha1 algorithm from providers */
if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL))
goto err;
if (!ASN1_OCTET_STRING_set(cid->hash, cert_sha1, SHA_DIGEST_LENGTH))
@@ -85,8 +88,8 @@ static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed)
goto err;
name = NULL; /* Ownership is lost. */
ASN1_INTEGER_free(cid->issuer_serial->serial);
- if (!(cid->issuer_serial->serial =
- ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
+ if ((cid->issuer_serial->serial =
+ ASN1_INTEGER_dup(X509_get_serialNumber(cert))) == NULL)
goto err;
return cid;
@@ -159,6 +162,7 @@ static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg,
cid->hash_alg = NULL;
}
+ /* TODO(3.0): fetch sha1 algorithm from providers */
if (!X509_digest(cert, hash_alg, hash, &hash_len))
goto err;
@@ -196,8 +200,9 @@ ESS_SIGNING_CERT *ESS_SIGNING_CERT_get(PKCS7_SIGNER_INFO *si)
{
ASN1_TYPE *attr;
const unsigned char *p;
+
attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate);
- if (!attr)
+ if (attr == NULL)
return NULL;
p = attr->value.sequence->data;
return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
@@ -273,3 +278,86 @@ int ESS_SIGNING_CERT_V2_add(PKCS7_SIGNER_INFO *si,
OPENSSL_free(pp);
return 0;
}
+
+static int ess_issuer_serial_cmp(const ESS_ISSUER_SERIAL *is, const X509 *cert)
+{
+ GENERAL_NAME *issuer;
+
+ if (is == NULL || cert == NULL || sk_GENERAL_NAME_num(is->issuer) != 1)
+ return -1;
+
+ issuer = sk_GENERAL_NAME_value(is->issuer, 0);
+ if (issuer->type != GEN_DIRNAME
+ || X509_NAME_cmp(issuer->d.dirn, X509_get_issuer_name(cert)) != 0)
+ return -1;
+
+ return ASN1_INTEGER_cmp(is->serial, X509_get0_serialNumber(cert));
+}
+
+/* Returns < 0 if certificate is not found, certificate index otherwise. */
+int ess_find_cert(const STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert)
+{
+ int i;
+ unsigned char cert_sha1[SHA_DIGEST_LENGTH];
+
+ if (cert_ids == NULL || cert == NULL)
+ return -1;
+
+ /* Recompute SHA1 hash of certificate if necessary (side effect). */
+ if (!X509v3_cache_extensions(cert, NULL, NULL))
+ return -1;
+
+ /* TODO(3.0): fetch sha1 algorithm from providers */
+ if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL))
+ return -1;
+
+ /* Look for cert in the cert_ids vector. */
+ for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i) {
+ const ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i);
+
+ if (cid->hash->length == SHA_DIGEST_LENGTH
+ && memcmp(cid->hash->data, cert_sha1, SHA_DIGEST_LENGTH) == 0) {
+ const ESS_ISSUER_SERIAL *is = cid->issuer_serial;
+
+ if (is == NULL || ess_issuer_serial_cmp(is, cert) == 0)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/* Returns < 0 if certificate is not found, certificate index otherwise. */
+int ess_find_cert_v2(const STACK_OF(ESS_CERT_ID_V2) *cert_ids, const X509 *cert)
+{
+ int i;
+ unsigned char cert_digest[EVP_MAX_MD_SIZE];
+ unsigned int len;
+
+ /* Look for cert in the cert_ids vector. */
+ for (i = 0; i < sk_ESS_CERT_ID_V2_num(cert_ids); ++i) {
+ const ESS_CERT_ID_V2 *cid = sk_ESS_CERT_ID_V2_value(cert_ids, i);
+ const EVP_MD *md;
+
+ if (cid != NULL && cid->hash_alg != NULL)
+ md = EVP_get_digestbyobj(cid->hash_alg->algorithm);
+ else
+ md = EVP_sha256();
+
+ /* TODO(3.0): fetch sha1 algorithm from providers */
+ if (!X509_digest(cert, md, cert_digest, &len))
+ return -1;
+
+ if (cid->hash->length != (int)len)
+ return -1;
+
+ if (memcmp(cid->hash->data, cert_digest, cid->hash->length) == 0) {
+ const ESS_ISSUER_SERIAL *is = cid->issuer_serial;
+
+ if (is == NULL || ess_issuer_serial_cmp(is, cert) == 0)
+ return i;
+ }
+ }
+
+ return -1;
+}
diff --git a/crypto/ts/ts_rsp_verify.c b/crypto/ts/ts_rsp_verify.c
index b872f75bea..c909b211d4 100644
--- a/crypto/ts/ts_rsp_verify.c
+++ b/crypto/ts/ts_rsp_verify.c
@@ -26,8 +26,7 @@ static int ts_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
X509 *signer, STACK_OF(X509) **chain);
static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
STACK_OF(X509) *chain);
-static int ts_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert);
-static int ts_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509 *cert);
+
static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx,
PKCS7 *token, TS_TST_INFO *tst_info);
static int ts_check_status_info(TS_RESP *response);
@@ -44,7 +43,6 @@ static int ts_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info);
static int ts_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer);
static int ts_find_name(STACK_OF(GENERAL_NAME) *gen_names,
GENERAL_NAME *name);
-static int ts_find_cert_v2(STACK_OF(ESS_CERT_ID_V2) *cert_ids, X509 *cert);
/*
* This must be large enough to hold all values in ts_status_text (with
@@ -218,7 +216,7 @@ static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
if (ss != NULL) {
cert_ids = ss->cert_ids;
cert = sk_X509_value(chain, 0);
- if (ts_find_cert(cert_ids, cert) != 0)
+ if (ess_find_cert(cert_ids, cert) != 0)
goto err;
/*
@@ -228,14 +226,14 @@ static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
if (sk_ESS_CERT_ID_num(cert_ids) > 1) {
for (i = 1; i < sk_X509_num(chain); ++i) {
cert = sk_X509_value(chain, i);
- if (ts_find_cert(cert_ids, cert) < 0)
+ if (ess_find_cert(cert_ids, cert) < 0)
goto err;
}
}
} else if (ssv2 != NULL) {
cert_ids_v2 = ssv2->cert_ids;
cert = sk_X509_value(chain, 0);
- if (ts_find_cert_v2(cert_ids_v2, cert) != 0)
+ if (ess_find_cert_v2(cert_ids_v2, cert) != 0)
goto err;
/*
@@ -245,7 +243,7 @@ static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
if (sk_ESS_CERT_ID_V2_num(cert_ids_v2) > 1) {
for (i = 1; i < sk_X509_num(chain); ++i) {
cert = sk_X509_value(chain, i);
- if (ts_find_cert_v2(cert_ids_v2, cert) < 0)
+ if (ess_find_cert_v2(cert_ids_v2, cert) < 0)
goto err;
}
}
@@ -263,87 +261,6 @@ static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
return ret;
}
-/* Returns < 0 if certificate is not found, certificate index otherwise. */
-static int ts_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert)
-{
- int i;
- unsigned char cert_sha1[SHA_DIGEST_LENGTH];
-
- if (!cert_ids || !cert)
- return -1;
-
- /* Recompute SHA1 hash of certificate if necessary (side effect). */
- X509_check_purpose(cert, -1, 0);
-
- if (!X509_digest(cert, EVP_sha1(), cert_sha1, NULL))
- return -1;
-
- /* Look for cert in the cert_ids vector. */
- for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i) {
- ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i);
-
- if (cid->hash->length == SHA_DIGEST_LENGTH
- && memcmp(cid->hash->data, cert_sha1, SHA_DIGEST_LENGTH) == 0) {
- ESS_ISSUER_SERIAL *is = cid->issuer_serial;
- if (!is || !ts_issuer_serial_cmp(is, cert))
- return i;
- }
- }
-
- return -1;
-}
-
-/* Returns < 0 if certificate is not found, certificate index otherwise. */
-static int ts_find_cert_v2(STACK_OF(ESS_CERT_ID_V2) *cert_ids, X509 *cert)
-{
- int i;
- unsigned char cert_digest[EVP_MAX_MD_SIZE];
- unsigned int len;
-
- /* Look for cert in the cert_ids vector. */
- for (i = 0; i < sk_ESS_CERT_ID_V2_num(cert_ids); ++i) {
- ESS_CERT_ID_V2 *cid = sk_ESS_CERT_ID_V2_value(cert_ids, i);
- const EVP_MD *md;
-
- if (cid->hash_alg != NULL)
- md = EVP_get_digestbyobj(cid->hash_alg->algorithm);
- else
- md = EVP_sha256();
-
- if (!X509_digest(cert, md, cert_digest, &len))
- return -1;
- if (cid->hash->length != (int)len)
- return -1;
-
- if (memcmp(cid->hash->data, cert_digest, cid->hash->length) == 0) {
- ESS_ISSUER_SERIAL *is = cid->issuer_serial;
-
- if (is == NULL || !ts_issuer_serial_cmp(is, cert))
- return i;
- }
- }
-
- return -1;
-}
-
-static int ts_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509 *cert)
-{
- GENERAL_NAME *issuer;
-
- if (!is || !cert || sk_GENERAL_NAME_num(is->issuer) != 1)
- return -1;
-
- issuer = sk_GENERAL_NAME_value(is->issuer, 0);
- if (issuer->type != GEN_DIRNAME
- || X509_NAME_cmp(issuer->d.dirn, X509_get_issuer_name(cert)))
- return -1;
-
- if (ASN1_INTEGER_cmp(is->serial, X509_get_serialNumber(cert)))
- return -1;
-
- return 0;
-}
-
/*-
* Verifies whether 'response' contains a valid response with regards
* to the settings of the context:
diff --git a/doc/man1/openssl-cms.pod.in b/doc/man1/openssl-cms.pod.in
index 375d358703..5ef1219a2e 100644
--- a/doc/man1/openssl-cms.pod.in
+++ b/doc/man1/openssl-cms.pod.in
@@ -569,7 +569,8 @@ Message-digest of the eContent OCTET STRING within encapContentInfo being signed
=item *
-An ESS signing-certificate or ESS signing-certificate-v2 attribute, as defined in Enhanced Security Services (ESS), RFC 2634 and RFC 5035.
+An ESS signing-certificate or ESS signing-certificate-v2 attribute, as defined
+in Enhanced Security Services (ESS), RFC 2634 and RFC 5035.
An ESS signing-certificate attribute only allows for the use of SHA-1 as a digest algorithm.
An ESS signing-certificate-v2 attribute allows for the use of any digest algorithm.
@@ -577,9 +578,10 @@ An ESS signing-certificate-v2 attribute allows for the use of any digest algorit
The digital signature value computed on the user data and, when present, on the signed attributes.
-Note that currently the B<-cades> option applies only to the B<-sign> operation and is ignored during
-the B<-verify> operation, i.e. the signing certification is not checked during the verification process.
-This feature might be added in a future version.
+NOTE that the B<-cades> option applies to the B<-sign> or B<-verify> operations.
+With this option, the B<-verify> operation also checks that the signing-certificates
+attribute is present, and its value matches the verification trust chain built
+during the verification process.
=back
diff --git a/doc/man3/CMS_verify.pod b/doc/man3/CMS_verify.pod
index 159c378b0e..ed289b1aff 100644
--- a/doc/man3/CMS_verify.pod
+++ b/doc/man3/CMS_verify.pod
@@ -66,10 +66,14 @@ from the content. If the content is not of type B<text/plain> then an error is
returned.
If B<CMS_NO_SIGNER_CERT_VERIFY> is set the signing certificates are not
-verified.
+verified, unless CMS_CADES flag is also set.
If B<CMS_NO_ATTR_VERIFY> is set the signed attributes signature is not
-verified.
+verified, unless CMS_CADES flag is als