diff options
author | Dr. David von Oheimb <David.von.Oheimb@siemens.com> | 2021-03-12 19:45:40 +0100 |
---|---|---|
committer | Dr. David von Oheimb <dev@ddvo.net> | 2021-03-18 07:03:53 +0100 |
commit | 63b64f19c13d59d68dc2e525f454aea62a739842 (patch) | |
tree | a0eb5a23182f4d056dcb435dadf4c96fb50e76c1 | |
parent | bef876f97e26309ccd20f916cf1e5e305735ee98 (diff) |
TS and CMS CAdES-BES: Refactor check_signing_certs() funcs into common ESS func
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)
-rw-r--r-- | CHANGES.md | 2 | ||||
-rw-r--r-- | apps/cms.c | 6 | ||||
-rw-r--r-- | crypto/cms/cms_att.c | 3 | ||||
-rw-r--r-- | crypto/cms/cms_err.c | 2 | ||||
-rw-r--r-- | crypto/cms/cms_ess.c | 63 | ||||
-rw-r--r-- | crypto/cms/cms_local.h | 3 | ||||
-rw-r--r-- | crypto/cms/cms_smime.c | 2 | ||||
-rw-r--r-- | crypto/err/openssl.txt | 10 | ||||
-rw-r--r-- | crypto/ess/ess_asn1.c | 4 | ||||
-rw-r--r-- | crypto/ess/ess_err.c | 14 | ||||
-rw-r--r-- | crypto/ess/ess_lib.c | 150 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_doit.c | 8 | ||||
-rw-r--r-- | crypto/ts/ts_rsp_verify.c | 38 | ||||
-rw-r--r-- | doc/man1/openssl-cms.pod.in | 26 | ||||
-rw-r--r-- | doc/man1/openssl-ts.pod.in | 11 | ||||
-rw-r--r-- | doc/man3/CMS_verify.pod | 4 | ||||
-rw-r--r-- | include/crypto/cms.h | 4 | ||||
-rw-r--r-- | include/crypto/ess.h | 14 | ||||
-rw-r--r-- | include/crypto/esserr.h | 2 | ||||
-rw-r--r-- | include/openssl/cms.h.in | 3 | ||||
-rw-r--r-- | include/openssl/cmserr.h | 1 | ||||
-rw-r--r-- | include/openssl/esserr.h | 6 | ||||
-rw-r--r-- | include/openssl/pkcs7.h.in | 4 | ||||
-rw-r--r-- | test/recipes/80-test_cms.t | 10 |
24 files changed, 160 insertions, 230 deletions
diff --git a/CHANGES.md b/CHANGES.md index cb074f2ff0..f6800a337d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 diff --git a/apps/cms.c b/apps/cms.c index cea1b73d88..b03e981a56 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -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; } diff --git a/crypto/cms/cms_att.c b/crypto/cms/cms_att.c index a9ef0357e5..2ac118b9e6 100644 --- a/crypto/cms/cms_att.c +++ b/crypto/cms/cms_att.c @@ -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); diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index 173e1596f6..81249ce689 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -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), diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c index b8b0076e03..5982035c45 100644 --- a/crypto/cms/cms_ess.c +++ b/crypto/cms/cms_ess.c @@ -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); diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h index 2429202fa8..0827c55a1c 100644 --- a/crypto/cms/cms_local.h +++ b/crypto/cms/cms_local.h @@ -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); diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index ac4ad2d490..3ab4cd2e6f 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -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; } } diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 53e8c4cd39..68c2ea8aa3 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -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 diff --git a/crypto/ess/ess_asn1.c b/crypto/ess/ess_asn1.c index 37bac4e707..08a0be8cc4 100644 --- a/crypto/ess/ess_asn1.c +++ b/crypto/ess/ess_asn1.c @@ -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; diff --git a/crypto/ess/ess_err.c b/crypto/ess/ess_err.c index 450c07edac..2ece3443bd 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-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 @@ -15,12 +15,24 @@ #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} }; diff --git a/crypto/ess/ess_lib.c b/crypto/ess/ess_lib.c index 7dda6adc98..ec1de943e4 100644 --- a/crypto/ess/ess_lib.c +++ b/crypto/ess/ess_lib.c @@ -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; } diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c index c9e4d719aa..c7a50ff57e 100644 --- a/crypto/pkcs7/pk7_doit.c +++ b/crypto/pkcs7/pk7_doit.c @@ -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; diff --git a/crypto/ts/ts_rsp_verify.c b/crypto/ts/ts_rsp_verify.c index 6798fc8263..4660647ffc 100644 --- a/crypto/ts/ts_rsp_verify.c +++ b/crypto/ts/ts_rsp_verify.c @@ -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; diff --git a/doc/man1/openssl-cms.pod.in b/doc/man1/openssl-cms.pod.in index 847ebaccd8..54e258a8f3 100644 --- a/doc/man1/openssl-cms.pod.in +++ b/doc/man1/openssl-cms.pod.in @@ -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 diff --git a/doc/man1/openssl-ts.pod.in b/doc/man1/openssl-ts.pod.in index 402a7a879a..c68f79c156 100644 --- a/doc/man1/openssl-ts.pod.in +++ b/doc/man1/openssl-ts.pod.in @@ -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> diff --git a/doc/man3/CMS_verify.pod b/doc/man3/CMS_verify.pod index d56540290f..89f50a2010 100644 --- a/doc/man3/CMS_verify.pod +++ b/doc/man3/CMS_verify.pod @@ -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. diff --git a/include/crypto/cms.h b/include/crypto/cms.h index f1cf6bd6bf..fe1aed0c09 100644 --- a/include/crypto/cms.h +++ b/include/crypto/cms.h @@ -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 */ diff --git a/include/crypto/ess.h b/include/crypto/ess.h index 099e3de9a5..1961e39067 100644 --- a/include/crypto/ess.h +++ b/include/crypto/ess.h @@ -13,14 +13,14 @@ /* 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); |