TS and CMS CAdES-BES: Refactor check_signing_certs() funcs into common ESS func
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Fri, 12 Mar 2021 18:45:40 +0000 (19:45 +0100)
committerDr. David von Oheimb <dev@ddvo.net>
Thu, 18 Mar 2021 06:03:53 +0000 (07:03 +0100)
Also constify related CMS/PKCS7 functions and improve error codes thrown.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14503)

24 files changed:
CHANGES.md
apps/cms.c
crypto/cms/cms_att.c
crypto/cms/cms_err.c
crypto/cms/cms_ess.c
crypto/cms/cms_local.h
crypto/cms/cms_smime.c
crypto/err/openssl.txt
crypto/ess/ess_asn1.c
crypto/ess/ess_err.c
crypto/ess/ess_lib.c
crypto/pkcs7/pk7_doit.c
crypto/ts/ts_rsp_verify.c
doc/man1/openssl-cms.pod.in
doc/man1/openssl-ts.pod.in
doc/man3/CMS_verify.pod
include/crypto/cms.h
include/crypto/ess.h
include/crypto/esserr.h
include/openssl/cms.h.in
include/openssl/cmserr.h
include/openssl/esserr.h
include/openssl/pkcs7.h.in
test/recipes/80-test_cms.t

index cb074f2ff0c47040023f3a904754e137d325dd52..f6800a337d1516a3386da656f124a114553632c2 100644 (file)
@@ -59,7 +59,7 @@ OpenSSL 3.0
    *Richard Levitte*
 
  * Improved adherence to Enhanced Security Services (ESS, RFC 2634 and RFC 5035)
-   for the TSP implementation.
+   for the TSP and CMS Advanced Electronic Signatures (CAdES) implementations.
    As required by RFC 5035 check both ESSCertID and ESSCertIDv2 if both present.
    Correct the semantics of checking the validation chain in case ESSCertID{,v2}
    contains more than one certificate identifier: This means that all
index cea1b73d888717ddfac9b8c2bb8fe596c8f26449..b03e981a56cdfb920c52f8be65429d51036a1e27 100644 (file)
@@ -126,7 +126,7 @@ const OPTIONS cms_options[] = {
     {"sign", OPT_SIGN, '-', "Sign message"},
     {"sign_receipt", OPT_SIGN_RECEIPT, '-', "Generate a signed receipt for the message"},
     {"resign", OPT_RESIGN, '-', "Resign a signed message"},
-    {"cades", OPT_CADES, '-', "Include signer certificate digest"},
+    {"cades", OPT_CADES, '-', "Include or check signingCertificate (CAdES-BES)"},
     {"verify", OPT_VERIFY, '-', "Verify signed message"},
     {"verify_retcode", OPT_VERIFY_RETCODE, '-',
         "Exit non-zero on verification failure"},
@@ -728,12 +728,12 @@ int cms_main(int argc, char **argv)
     if ((flags & CMS_CADES) != 0) {
         if ((flags & CMS_NOATTR) != 0) {
             BIO_puts(bio_err, "Incompatible options: "
-                     "CAdES required signed attributes\n");
+                     "CAdES requires 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"
+            BIO_puts(bio_err, "Incompatible options: CAdES validation requires"
                      " certs and signed attributes validations\n");
             goto opthelp;
         }
index a9ef0357e5502b7df74fd31bb8f9032200485179..2ac118b9e6a5e2ab9bfcf2c2ba2b2b2971a2d03d 100644 (file)
@@ -125,7 +125,8 @@ int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si,
     return 0;
 }
 
-void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *oid,
+void *CMS_signed_get0_data_by_OBJ(const CMS_SignerInfo *si,
+                                  const ASN1_OBJECT *oid,
                                   int lastpos, int type)
 {
     return X509at_get0_data_by_OBJ(si->signedAttrs, oid, lastpos, type);
index 173e1596f6c173d07c5604972792607cb20d15d4..81249ce689505319bc8055f815034230424f1efe 100644 (file)
@@ -59,8 +59,6 @@ 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),
index b8b0076e038a77ca54a81f42badadd3c3f199e0a..5982035c45edb9d8cb650a88f4700b1e13696dd2 100644 (file)
@@ -46,67 +46,14 @@ int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
     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 ossl_ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain)
+int ossl_cms_check_signing_certs(const CMS_SignerInfo *si,
+                                 const STACK_OF(X509) *chain)
 {
     ESS_SIGNING_CERT *ss = NULL;
     ESS_SIGNING_CERT_V2 *ssv2 = NULL;
-    X509 *cert;
-    int i = 0, ret = 0;
-
-    if (ossl_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 (ossl_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 (ossl_ess_find_cert(cert_ids, cert) < 0)
-                    goto err;
-            }
-        }
-    } else if (ossl_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 (ossl_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 (ossl_ess_find_cert_v2(cert_ids_v2, cert) < 0)
-                    goto err;
-            }
-        }
-    } else {
-        ERR_raise(ERR_LIB_CMS, CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE);
-        return 0;
-    }
-    ret = 1;
- err:
-    if (!ret)
-        ERR_raise(ERR_LIB_CMS, CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR);
+    int ret = ossl_cms_signerinfo_get_signing_cert(si, &ss) >= 0
+        && ossl_cms_signerinfo_get_signing_cert_v2(si, &ssv2) >= 0
+        && ossl_ess_check_signing_certs(ss, ssv2, chain, 1);
 
     ESS_SIGNING_CERT_free(ss);
     ESS_SIGNING_CERT_V2_free(ssv2);
index 2429202fa81c6eaebeac882eb6ab444d559ddb5b..0827c55a1c1b3fb6c02268c110928cd35e509baa 100644 (file)
@@ -473,7 +473,8 @@ void ossl_cms_SignerInfos_set_cmsctx(CMS_ContentInfo *cms);
 
 
 /* ESS routines */
-int ossl_ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain);
+int ossl_cms_check_signing_certs(const CMS_SignerInfo *si,
+                                 const STACK_OF(X509) *chain);
 
 int ossl_cms_dh_envelope(CMS_RecipientInfo *ri, int decrypt);
 int ossl_cms_ecdh_envelope(CMS_RecipientInfo *ri, int decrypt);
index ac4ad2d490f62370877cfa9ec3a505b465894218..3ab4cd2e6f524d255792ab517804a9911be78cf8 100644 (file)
@@ -381,7 +381,7 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
             if (cadesVerify) {
                 STACK_OF(X509) *si_chain = si_chains ? si_chains[i] : NULL;
 
-                if (ossl_ess_check_signing_certs(si, si_chain) <= 0)
+                if (ossl_cms_check_signing_certs(si, si_chain) <= 0)
                     goto err;
             }
         }
index 53e8c4cd3933a22a6edb8be6e2d4cfe2135a8a18..68c2ea8aa36b18ec44a757d4ae303682cb0699f2 100644 (file)
@@ -299,7 +299,6 @@ 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
@@ -629,9 +628,16 @@ ENGINE_R_UNIMPLEMENTED_CIPHER:146:unimplemented cipher
 ENGINE_R_UNIMPLEMENTED_DIGEST:147:unimplemented digest
 ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD:101:unimplemented public key method
 ENGINE_R_VERSION_INCOMPATIBILITY:145:version incompatibility
+ESS_R_EMPTY_ESS_CERT_ID_LIST:107:empty ess cert id list
+ESS_R_ESS_CERT_DIGEST_ERROR:103:ess cert digest error
+ESS_R_ESS_CERT_ID_NOT_FOUND:104:ess cert id not found
+ESS_R_ESS_CERT_ID_WRONG_ORDER:105:ess cert id wrong order
+ESS_R_ESS_DIGEST_ALG_UNKNOWN:106:ess digest alg unknown
 ESS_R_ESS_SIGNING_CERTIFICATE_ERROR:102:ess signing certificate error
 ESS_R_ESS_SIGNING_CERT_ADD_ERROR:100:ess signing cert add error
 ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR:101:ess signing cert v2 add error
+ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE:108:\
+       missing signing certificate attribute
 EVP_R_AES_KEY_SETUP_FAILED:143:aes key setup failed
 EVP_R_ARIA_KEY_SETUP_FAILED:176:aria key setup failed
 EVP_R_BAD_ALGORITHM_NAME:200:bad algorithm name
@@ -706,9 +712,9 @@ EVP_R_NO_KEY_SET:154:no key set
 EVP_R_NO_OPERATION_SET:149:no operation set
 EVP_R_NULL_MAC_PKEY_CTX:208:null mac pkey ctx
 EVP_R_ONLY_ONESHOT_SUPPORTED:177:only oneshot supported
+EVP_R_OPERATION_NOT_INITIALIZED:151:operation not initialized
 EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE:150:\
        operation not supported for this keytype
-EVP_R_OPERATION_NOT_INITIALIZED:151:operation not initialized
 EVP_R_OUTPUT_WOULD_OVERFLOW:202:output would overflow
 EVP_R_PARAMETER_TOO_LARGE:187:parameter too large
 EVP_R_PARTIALLY_OVERLAPPING:162:partially overlapping buffers
index 37bac4e707ef24cf2a3fd93ab9a7d9d519f34fa1..08a0be8cc4528959cbfbeb4312186718e7e5e0e1 100644 (file)
@@ -65,7 +65,7 @@ IMPLEMENT_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT_V2)
  * Returns < 0 if attribute is not found, 1 if found, or 
  * -1 on attribute parsing failure.
  */
-int ossl_cms_signerinfo_get_signing_cert_v2(CMS_SignerInfo *si,
+int ossl_cms_signerinfo_get_signing_cert_v2(const CMS_SignerInfo *si,
                                             ESS_SIGNING_CERT_V2 **psc)
 {
     ASN1_STRING *str;
@@ -92,7 +92,7 @@ int ossl_cms_signerinfo_get_signing_cert_v2(CMS_SignerInfo *si,
  * Returns < 0 if attribute is not found, 1 if found, or 
  * -1 on attribute parsing failure.
  */
-int ossl_cms_signerinfo_get_signing_cert(CMS_SignerInfo *si,
+int ossl_cms_signerinfo_get_signing_cert(const CMS_SignerInfo *si,
                                          ESS_SIGNING_CERT **psc)
 {
     ASN1_STRING *str;
index 450c07edaca816ba6468ea024162eac511e35e54..2ece3443bd67109955ef02a5a07dd81340d6ec3d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 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
 #ifndef OPENSSL_NO_ERR
 
 static const ERR_STRING_DATA ESS_str_reasons[] = {
+    {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_EMPTY_ESS_CERT_ID_LIST),
+    "empty ess cert id list"},
+    {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_CERT_DIGEST_ERROR),
+    "ess cert digest error"},
+    {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_CERT_ID_NOT_FOUND),
+    "ess cert id not found"},
+    {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_CERT_ID_WRONG_ORDER),
+    "ess cert id wrong order"},
+    {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_DIGEST_ALG_UNKNOWN),
+    "ess digest alg unknown"},
     {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_SIGNING_CERTIFICATE_ERROR),
     "ess signing certificate error"},
     {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_SIGNING_CERT_ADD_ERROR),
     "ess signing cert add error"},
     {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR),
     "ess signing cert v2 add error"},
+    {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE),
+    "missing signing certificate attribute"},
     {0, NULL}
 };
 
index 7dda6adc98b9202cbfb84b9b41065abc08bdf65e..ec1de943e4c9f6e3c4361f51c7ae130defc7545f 100644 (file)
@@ -192,7 +192,7 @@ static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg,
     return NULL;
 }
 
-ESS_SIGNING_CERT *ossl_ess_signing_cert_get(PKCS7_SIGNER_INFO *si)
+ESS_SIGNING_CERT *ossl_ess_get_signing_cert(const PKCS7_SIGNER_INFO *si)
 {
     ASN1_TYPE *attr;
     const unsigned char *p;
@@ -204,7 +204,7 @@ ESS_SIGNING_CERT *ossl_ess_signing_cert_get(PKCS7_SIGNER_INFO *si)
     return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
 }
 
-ESS_SIGNING_CERT_V2 *ossl_ess_signing_cert_v2_get(PKCS7_SIGNER_INFO *si)
+ESS_SIGNING_CERT_V2 *ossl_ess_get_signing_cert_v2(const PKCS7_SIGNER_INFO *si)
 {
     ASN1_TYPE *attr;
     const unsigned char *p;
@@ -289,112 +289,92 @@ static int ess_issuer_serial_cmp(const ESS_ISSUER_SERIAL *is, const X509 *cert)
     return ASN1_INTEGER_cmp(is->serial, X509_get0_serialNumber(cert));
 }
 
-/* Returns < 0 if certificate is not found, certificate index otherwise. */
-int ossl_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))
-        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 ossl_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)
-            return -1;
-        if (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;
-}
-
-/* Returns < 0 if certificate is not found, certificate index otherwise. */
-int ossl_ess_find_cid(const STACK_OF(X509) *certs,
-                      ESS_CERT_ID *cid, ESS_CERT_ID_V2 *cid_v2)
+/*
+ * Find cert referenced by |cid| (if not NULL, else |cidv2|) in |certs|.
+ * If the cid{,v2} index is 0, the cert must be in the first in |certs| list.
+ * Return 0 on not found, -1 on error, else 1 + the position in |certs|.
+ */
+static int find(const ESS_CERT_ID *cid, const ESS_CERT_ID_V2 *cid_v2,
+                int index, const STACK_OF(X509) *certs)
 {
+    const X509 *cert;
+    const EVP_MD *md;
     unsigned char cert_digest[EVP_MAX_MD_SIZE];
     unsigned int len, cid_hash_len;
-    int i;
     const ESS_ISSUER_SERIAL *is;
+    int i;
 
-    if (certs == NULL || (cid == NULL && cid_v2 == NULL))
+    if (cid == NULL && cid_v2 == NULL) {
+        ERR_raise(ERR_LIB_ESS, ERR_R_PASSED_INVALID_ARGUMENT);
         return -1;
+    }
 
     /* Look for cert with cid in the certs. */
     for (i = 0; i < sk_X509_num(certs); ++i) {
-        const X509 *cert = sk_X509_value(certs, i);
-        const EVP_MD *md;
+        cert = sk_X509_value(certs, i);
 
-        /* TODO(3.0): fetch sha algorithm from providers */
         if (cid != NULL)
             md = EVP_sha1();
         else
             md = cid_v2->hash_alg == NULL ? EVP_sha256() :
                 EVP_get_digestbyobj(cid_v2->hash_alg->algorithm);
+        if (md == NULL) {
+            ERR_raise(ERR_LIB_ESS, ESS_R_ESS_DIGEST_ALG_UNKNOWN);
+            return -1;
+        }
+
         cid_hash_len = cid != NULL ? cid->hash->length : cid_v2->hash->length;
         if (!X509_digest(cert, md, cert_digest, &len)
-                || cid_hash_len != len)
+                || cid_hash_len != len) {
+            ERR_raise(ERR_LIB_ESS, ESS_R_ESS_CERT_DIGEST_ERROR);
             return -1;
+        }
 
         if (memcmp(cid != NULL ? cid->hash->data : cid_v2->hash->data,
                    cert_digest, len) == 0) {
             is = cid != NULL ? cid->issuer_serial : cid_v2->issuer_serial;
-            if (is == NULL || ess_issuer_serial_cmp(is, cert) == 0)
-                return i;
+            /* Well, it's not really required to match the serial numbers. */
+            if (is == NULL || ess_issuer_serial_cmp(is, cert) == 0) {
+                if ((i == 0) == (index == 0))
+                    return i + 1;
+                ERR_raise(ERR_LIB_ESS, ESS_R_ESS_CERT_ID_WRONG_ORDER);
+                return -1;
+            }
         }
     }
 
-    return -1;
+    ERR_raise(ERR_LIB_ESS, ESS_R_ESS_CERT_ID_NOT_FOUND);
+    return 0;
+}
+
+/*
+ * If ESSCertID and/or ESSCertIDv2 exist, which must be non-empty if given,
+ * check if their first ID entry matches the signer cert first in chain
+ * and each further ID entry matches any further cert in the chain.
+ */
+int ossl_ess_check_signing_certs(const ESS_SIGNING_CERT *ss,
+                                 const ESS_SIGNING_CERT_V2 *ssv2,
+                                 const STACK_OF(X509) *chain,
+                                 int require_signing_cert)
+{
+    int n_v1 = ss == NULL ? -1 : sk_ESS_CERT_ID_num(ss->cert_ids);
+    int n_v2 = ssv2 == NULL ? -1 : sk_ESS_CERT_ID_V2_num(ssv2->cert_ids);
+    int i;
+
+    if (require_signing_cert && ss == NULL && ssv2 == NULL) {
+        ERR_raise(ERR_LIB_CMS, ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE);
+        return 0;
+    }
+    if (n_v1 == 0 || n_v2 == 0) {
+        ERR_raise(ERR_LIB_ESS, ESS_R_EMPTY_ESS_CERT_ID_LIST);
+        return 0;
+    }
+    /* If both ss and ssv2 exist, as required evaluate them independently. */
+    for (i = 0; i < n_v1; i++)
+        if (find(sk_ESS_CERT_ID_value(ss->cert_ids, i), NULL, i, chain) <= 0)
+            return 0;
+    for (i = 0; i < n_v2; i++)
+        if (find(NULL, sk_ESS_CERT_ID_V2_value(ssv2->cert_ids, i), i, chain) <= 0)
+            return 0;
+    return 1;
 }
index c9e4d719aa5099128b624f2a9e8656835f859af2..c7a50ff57ed0a1958a1bb37cf6f21c407a746b28 100644 (file)
@@ -18,7 +18,7 @@
 
 static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
                          void *value);
-static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid);
+static ASN1_TYPE *get_attribute(const STACK_OF(X509_ATTRIBUTE) *sk, int nid);
 
 int PKCS7_type_is_other(PKCS7 *p7)
 {
@@ -1209,17 +1209,17 @@ PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx)
     return ri->issuer_and_serial;
 }
 
-ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid)
+ASN1_TYPE *PKCS7_get_signed_attribute(const PKCS7_SIGNER_INFO *si, int nid)
 {
     return get_attribute(si->auth_attr, nid);
 }
 
-ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid)
+ASN1_TYPE *PKCS7_get_attribute(const PKCS7_SIGNER_INFO *si, int nid)
 {
     return get_attribute(si->unauth_attr, nid);
 }
 
-static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid)
+static ASN1_TYPE *get_attribute(const STACK_OF(X509_ATTRIBUTE) *sk, int nid)
 {
     int idx;
     X509_ATTRIBUTE *xa;
index 6798fc8263bc32b7783a3ac62bb1e6fb3b419c90..4660647ffcb9ae0d16e6d4428829f197a5859a5a 100644 (file)
@@ -17,8 +17,8 @@
 
 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_check_signing_certs(const PKCS7_SIGNER_INFO *si,
+                                  const STACK_OF(X509) *chain);
 
 static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx,
                                     PKCS7 *token, TS_TST_INFO *tst_info);
@@ -202,37 +202,13 @@ end:
     return ret;
 }
 
-static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
-                                  STACK_OF(X509) *chain)
+static int ts_check_signing_certs(const PKCS7_SIGNER_INFO *si,
+                                  const STACK_OF(X509) *chain)
 {
-    ESS_SIGNING_CERT *ss = ossl_ess_signing_cert_get(si);
-    ESS_SIGNING_CERT_V2 *ssv2 = ossl_ess_signing_cert_v2_get(si);
-    int i, j;
-    int ret = 0;
+    ESS_SIGNING_CERT *ss = ossl_ess_get_signing_cert(si);
+    ESS_SIGNING_CERT_V2 *ssv2 = ossl_ess_get_signing_cert_v2(si);
+    int ret = ossl_ess_check_signing_certs(ss, ssv2, chain, 1);
 
-    /*
-     * Check if first ESSCertIDs matches signer cert
-     * and each further ESSCertIDs matches any cert in the chain.
-     */
-    if (ss != NULL)
-        for (i = 0; i < sk_ESS_CERT_ID_num(ss->cert_ids); i++) {
-            j = ossl_ess_find_cid(chain, sk_ESS_CERT_ID_value(ss->cert_ids, i),
-                                  NULL);
-            if (j < 0 || (i == 0 && j != 0))
-                goto err;
-        }
-    if (ssv2 != NULL)
-        for (i = 0; i < sk_ESS_CERT_ID_V2_num(ssv2->cert_ids); i++) {
-            j = ossl_ess_find_cid(chain, NULL,
-                                  sk_ESS_CERT_ID_V2_value(ssv2->cert_ids, i));
-            if (j < 0 || (i == 0 && j != 0))
-                goto err;
-        }
-    ret = 1;
-
- err:
-    if (!ret)
-        ERR_raise(ERR_LIB_TS, TS_R_ESS_SIGNING_CERTIFICATE_ERROR);
     ESS_SIGNING_CERT_free(ss);
     ESS_SIGNING_CERT_V2_free(ssv2);
     return ret;
index 847ebaccd8dec8f982fd0e7989b080db934c8dc6..54e258a8f389c51b874f7cd3a1f45f0e2b59a0f8 100644 (file)
@@ -161,9 +161,12 @@ Resign a message: take an existing message and one or more new signers.
 
 =item B<-cades>
 
-Add an ESS signing-certificate or ESS signing-certificate-v2 signed-attribute to the SignerInfo, in order to make
-the signature comply with the requirements for a CAdES Basic Electronic Signature (CAdES-BES). See the NOTES
-section for more details.
+When used with B<-sign>,
+add an ESS signingCertificate or ESS signingCertificateV2 signed-attribute
+to the SignerInfo, in order to make the signature comply with the requirements
+for a CAdES Basic Electronic Signature (CAdES-BES).
+When used with B<-verify>, require and check signer certificate digest.
+See the NOTES section for more details.
 
 =item B<-data_create>
 
@@ -564,7 +567,8 @@ with caution. For a fuller description see L<CMS_decrypt(3)>).
 
 =head1 CADES BASIC ELECTRONIC SIGNATURE (CADES-BES)
 
-A CAdES Basic Electronic Signature (CAdES-BES), as defined in the European Standard ETSI EN 319 122-1 V1.1.1, contains:
+A CAdES Basic Electronic Signature (CAdES-BES),
+as defined in the European Standard ETSI EN 319 122-1 V1.1.1, contains:
 
 =over 4
 
@@ -582,19 +586,19 @@ 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 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.
+An ESS signingCertificate or ESS signingCertificateV2 attribute,
+as defined in Enhanced Security Services (ESS), RFC 2634 and RFC 5035.
+An ESS signingCertificate attribute only allows for SHA-1 as digest algorithm.
+An ESS signingCertificateV2 attribute allows for any digest algorithm.
 
 =item *
 
 The digital signature value computed on the user data and, when present, on the signed attributes.
 
 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.
+With this option, the B<-verify> operation also requires that the
+signingCertificate attribute is present and checks that the given identifiers
+match the verification trust chain built during the verification process.
 
 =back
 
index 402a7a879a4889ac53bfc6d61b1019172be79678..c68f79c156a22cdfaa29408e9840d8cc7aefef05 100644 (file)
@@ -469,12 +469,13 @@ the TSA name field of the response. Default is no. (Optional)
 
 The SignedData objects created by the TSA always contain the
 certificate identifier of the signing certificate in a signed
-attribute (see RFC 2634, Enhanced Security Services). If this option
-is set to yes and either the B<certs> variable or the B<-chain> option
+attribute (see RFC 2634, Enhanced Security Services).
+If this variable is set to no, only this signing certificate identifier
+is included in the SigningCertificate signed attribute.
+If this variable is set to yes and the B<certs> variable or the B<-chain> option
 is specified then the certificate identifiers of the chain will also
-be included in the SigningCertificate signed attribute. If this
-variable is set to no, only the signing certificate identifier is
-included. Default is no. (Optional)
+be included, where the B<-chain> option overrides the B<certs> variable.
+Default is no.  (Optional)
 
 =item B<ess_cert_id_alg>
 
index d56540290f4287d7cf1742a0be2f24c48127f5eb..89f50a20100cb19bcb353e905cb922f0fe652ff4 100644 (file)
@@ -72,8 +72,8 @@ If B<CMS_NO_ATTR_VERIFY> is set the signed attributes signature is not
 verified, unless CMS_CADES flag is also set.
 
 If B<CMS_CADES> is set, each signer certificate is checked against the 
-"ESS signing-certificate" extension added in the signed attributes of the 
-signature.
+ESS signingCertificate or ESS signingCertificateV2 extension
+that is required in the signed attributes of the signature.
 
 If B<CMS_NO_CONTENT_VERIFY> is set then the content digest is not checked.
 
index f1cf6bd6bf2e47456d480b5f8d3e847661de7f63..fe1aed0c096ef52c410784ab5336b17753e16bea 100644 (file)
@@ -18,9 +18,9 @@
 int ossl_cms_add1_signing_cert(CMS_SignerInfo *si, ESS_SIGNING_CERT *sc);
 int ossl_cms_add1_signing_cert_v2(CMS_SignerInfo *si, ESS_SIGNING_CERT_V2 *sc);
 
-int ossl_cms_signerinfo_get_signing_cert_v2(CMS_SignerInfo *si,
+int ossl_cms_signerinfo_get_signing_cert_v2(const CMS_SignerInfo *si,
                                             ESS_SIGNING_CERT_V2 **psc);
-int ossl_cms_signerinfo_get_signing_cert(CMS_SignerInfo *si,
+int ossl_cms_signerinfo_get_signing_cert(const CMS_SignerInfo *si,
                                          ESS_SIGNING_CERT **psc);
 # endif /* OPENSSL_NO_CMS */
 
index 099e3de9a5af1bc65bd57e13252d6e183b6d31c9..1961e39067b7be968b033b57b00ec38cd37e9093 100644 (file)
 
 /* internal ESS related stuff */
 
-ESS_SIGNING_CERT *ossl_ess_signing_cert_get(PKCS7_SIGNER_INFO *si);
+ESS_SIGNING_CERT *ossl_ess_get_signing_cert(const PKCS7_SIGNER_INFO *si);
 int ossl_ess_signing_cert_add(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT *sc);
 
 ESS_SIGNING_CERT *ossl_ess_signing_cert_new_init(X509 *signcert,
                                                  STACK_OF(X509) *certs,
                                                  int issuer_needed);
 
-ESS_SIGNING_CERT_V2 *ossl_ess_signing_cert_v2_get(PKCS7_SIGNER_INFO *si);
+ESS_SIGNING_CERT_V2 *ossl_ess_get_signing_cert_v2(const PKCS7_SIGNER_INFO *si);
 int ossl_ess_signing_cert_v2_add(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT_V2 *sc);
 
 ESS_SIGNING_CERT_V2 *ossl_ess_signing_cert_v2_new_init(const EVP_MD *hash_alg,
@@ -28,12 +28,10 @@ ESS_SIGNING_CERT_V2 *ossl_ess_signing_cert_v2_new_init(const EVP_MD *hash_alg,
                                                        STACK_OF(X509) *certs,
                                                        int issuer_needed);
 
-/* Returns < 0 if certificate is not found, certificate index otherwise. */
-int ossl_ess_find_cert_v2(const STACK_OF(ESS_CERT_ID_V2) *cert_ids,
-                          const X509 *cert);
-int ossl_ess_find_cert(const STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert);
-int ossl_ess_find_cid(const STACK_OF(X509) *certs,
-                      ESS_CERT_ID *cid, ESS_CERT_ID_V2 *cid_v2);
+int ossl_ess_check_signing_certs(const ESS_SIGNING_CERT *ss,
+                                 const ESS_SIGNING_CERT_V2 *ssv2,
+                                 const STACK_OF(X509) *chain,
+                                 int require_signing_cert);
 
 /*-
  * IssuerSerial ::= SEQUENCE {
index d253356a9023e9d8f74623fbd9856081ac6f98e4..a87d4fabceae70e7dd2e5c6bd544f1106049755a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2021 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
index 5ffd3b44053f772ba31871c3ccc5a20089fb7448..e2912b47ccb7d06090417d8158b5ada3c35cee1a 100644 (file)
@@ -310,7 +310,8 @@ int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si,
 int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si,
                                 const char *attrname, int type,
                                 const void *bytes, int len);
-void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *oid,
+void *CMS_signed_get0_data_by_OBJ(const CMS_SignerInfo *si,
+                                  const ASN1_OBJECT *oid,
                                   int lastpos, int type);
 
 int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si);
index 418e8baff90d383d7545d2ed72fd570c8e153fa5..1c4f4c799dc3d534cc379229047200d8d507f285 100644 (file)
@@ -49,7 +49,6 @@
 #  define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE      114
 #  define CMS_R_ERROR_SETTING_KEY                          115
 #  define CMS_R_ERROR_SETTING_RECIPIENTINFO                116
-#  define CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE            182
 #  define CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR          183
 #  define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH               117
 #  define CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER           176
index 2eb82c1eb75f9bac1c231328c06192331d1b3ea2..0b9e89e4cb73cac184147787ebc518aa28847416 100644 (file)
 /*
  * ESS reason codes.
  */
+# define ESS_R_EMPTY_ESS_CERT_ID_LIST                     107
+# define ESS_R_ESS_CERT_DIGEST_ERROR                      103
+# define ESS_R_ESS_CERT_ID_NOT_FOUND                      104
+# define ESS_R_ESS_CERT_ID_WRONG_ORDER                    105
+# define ESS_R_ESS_DIGEST_ALG_UNKNOWN                     106
 # define ESS_R_ESS_SIGNING_CERTIFICATE_ERROR              102
 # define ESS_R_ESS_SIGNING_CERT_ADD_ERROR                 100
 # define ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR              101
+# define ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE      108
 
 #endif
index df53acc2a1a00ae2628c34eb0772048ca2d0c561..87dda5411508c3207ec87c45bd3e672a30782096 100644 (file)
@@ -304,8 +304,8 @@ int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int type,
                                void *data);
 int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
                         void *value);
-ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid);
-ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid);
+ASN1_TYPE *PKCS7_get_attribute(const PKCS7_SIGNER_INFO *si, int nid);
+ASN1_TYPE *PKCS7_get_signed_attribute(const PKCS7_SIGNER_INFO *si, int nid);
 int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
                                 STACK_OF(X509_ATTRIBUTE) *sk);
 int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,
index 8e3275c2e5bebab96085d4a195c7e2095d172cd5..1837a51bbed33c32d4da82ad8d33c48dbcc33d06 100644 (file)
@@ -451,10 +451,11 @@ my @smime_cms_cades_tests = (
 );
 
 my @smime_cms_cades_ko_tests = (
-    [ "signed content DER format, RSA key, but verified as CAdES-BES compatible",
+    [ "sign content DER format, RSA key, not CAdES-BES compatible",
       [ @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
         "-certfile", catfile($smdir, "smroot.pem"),
         "-signer", catfile($smdir, "smrsa1.pem"), "-out", "{output}.cms" ],
+      "fail to verify token because requiring CAdES-BES compatibility",
       [ @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
         "-CAfile", catfile($smdir, "smroot.pem"), "-out", "{output}.txt" ],
       \&final_compare
@@ -798,16 +799,15 @@ subtest "CAdES; cms incompatible arguments tests\n" => sub {
 };
 
 subtest "CAdES ko tests\n" => sub {
-    plan tests => (scalar @smime_cms_cades_ko_tests);
+    plan tests => 2 * scalar @smime_cms_cades_ko_tests;
 
     foreach (@smime_cms_cades_ko_tests) {
       SKIP: {
         my $skip_reason = check_availability($$_[0]);
         skip $skip_reason, 1 if $skip_reason;
 
-        ok(run(app(["openssl", "cms", @{$$_[1]}]))
-            && !run(app(["openssl", "cms", @{$$_[2]}])),
-            $$_[0]);
+        ok(run(app(["openssl", "cms", @{$$_[1]}])), $$_[0]);
+        ok(!run(app(["openssl", "cms", @{$$_[3]}])), $$_[2]);
         }
     }
 };