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 /crypto/ess | |
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)
Diffstat (limited to 'crypto/ess')
-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 |
3 files changed, 80 insertions, 88 deletions
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; } |