From a2fea2de54835fa92be326ac6cd89dd47c66ac5d Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Wed, 30 Jun 2021 20:44:58 +0300 Subject: [PATCH] Fetch Issuer certificate from AIA extension when not found from TSL (#404) IB-6883 Signed-off-by: Raul Metsma --- src/SignatureXAdES_LT.cpp | 7 ++-- src/crypto/X509CertStore.cpp | 65 ++++++++++++++---------------------- src/crypto/X509CertStore.h | 1 + 3 files changed, 30 insertions(+), 43 deletions(-) diff --git a/src/SignatureXAdES_LT.cpp b/src/SignatureXAdES_LT.cpp index fc9b95b80..aba4f1f26 100644 --- a/src/SignatureXAdES_LT.cpp +++ b/src/SignatureXAdES_LT.cpp @@ -58,7 +58,7 @@ SignatureXAdES_LT::SignatureXAdES_LT(istream &sigdata, ASiContainer *bdoc, bool THROW("Could not find certificate issuer '%s' in certificate store.", cert.issuerName().c_str()); - OCSP ocsp(cert, issuer, vector(), bdoc->mediaType(), false); + OCSP ocsp(cert, issuer, {}, bdoc->mediaType(), false); addOCSPValue(id().replace(0, 1, "N"), ocsp); } } catch(const Exception &) { @@ -224,7 +224,9 @@ void SignatureXAdES_LT::extendSignatureProfile(const std::string &profile) X509Cert cert = signingCertificate(); X509Cert issuer = X509CertStore::instance()->findIssuer(cert, X509CertStore::CA); if(!issuer) - THROW("Could not find certificate issuer '%s' in certificate store.", + issuer = X509CertStore::instance()->issuerFromAIA(cert); + if(!issuer) + THROW("Could not find certificate issuer '%s' in certificate store or from AIA.", cert.issuerName().c_str()); OCSP ocsp(cert, issuer, nonce, bdoc->mediaType(), profile.find(ASiC_E::ASIC_TM_PROFILE) != string::npos); @@ -305,7 +307,6 @@ OCSP SignatureXAdES_LT::getOCSPResponseValue() const for(const OCSPValuesType::EncapsulatedOCSPValueType &resp: t.oCSPValues()->encapsulatedOCSPValue()) { try { - vector data(resp.begin(), resp.end()); OCSP ocsp((const unsigned char*)resp.data(), resp.size()); ocsp.verifyResponse(signingCertificate()); return ocsp; diff --git a/src/crypto/X509CertStore.cpp b/src/crypto/X509CertStore.cpp index 708fcd598..236edfbc4 100644 --- a/src/crypto/X509CertStore.cpp +++ b/src/crypto/X509CertStore.cpp @@ -21,6 +21,7 @@ #include "Conf.h" #include "log.h" +#include "crypto/Connect.h" #include "crypto/OpenSSLHelpers.h" #include "crypto/TSL.h" #include "util/DateTime.h" @@ -122,12 +123,6 @@ X509CertStore* X509CertStore::instance() return &INSTANCE; } - -/** - * Return STACK_OF(X509) containing all certs loaded from directory - * @return STACK_OF(X509) all certs in store. - * throws IOException - */ vector X509CertStore::certs(const set &type) const { vector certs; @@ -139,41 +134,41 @@ vector X509CertStore::certs(const set &type) const return certs; } -/** - * Searches certificate by subject and returns a copy of it if found. - * If not found returns NULL. - * NB! The returned certificate must be freed with OpenSSL function X509_free(X509* cert). - * - * @param subject certificate subject. - * @return returns copy of found certificate or NULL if certificate was not found. - * @throws IOException exception is thrown if copying certificate failed. - */ X509Cert X509CertStore::findIssuer(const X509Cert &cert, const set &type) const { activate(cert.issuerName("C")); - SCOPE(AUTHORITY_KEYID, akid, X509_get_ext_d2i(cert.handle(), NID_authority_key_identifier, nullptr, nullptr)); for(const TSL::Service &s: *d) { if(type.find(s.type) == type.cend()) continue; for(const X509Cert &i: s.certs) { - if(!akid || !akid->keyid) - { - if(X509_NAME_cmp(X509_get_subject_name(i.handle()), X509_get_issuer_name(cert.handle()))) - return i; - } - else - { - SCOPE(ASN1_OCTET_STRING, skid, X509_get_ext_d2i(i.handle(), NID_subject_key_identifier, nullptr, nullptr)); - if(skid && ASN1_OCTET_STRING_cmp(akid->keyid, skid.get()) == 0) - return i; - } + if(X509_check_issued(i.handle(), cert.handle()) == X509_V_OK) + return i; } } return X509Cert(); } +X509Cert X509CertStore::issuerFromAIA(const X509Cert &cert) const +{ + SCOPE(AUTHORITY_INFO_ACCESS, aia, X509_get_ext_d2i(cert.handle(), NID_info_access, nullptr, nullptr)); + if(!aia) + return X509Cert(); + string url; + for(int i = 0; i < sk_ACCESS_DESCRIPTION_num(aia.get()); ++i) + { + ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(aia.get(), i); + if(ad->location->type == GEN_URI && + OBJ_obj2nid(ad->method) == NID_ad_ca_issuers) + url.assign((const char*)ad->location->d.uniformResourceIdentifier->data, ad->location->d.uniformResourceIdentifier->length); + } + if(url.empty()) + return X509Cert(); + Connect::Result result = Connect(url, "GET", 0, {}).exec(); + return X509Cert((const unsigned char*)result.content.c_str(), result.content.size()); +} + X509_STORE* X509CertStore::createStore(const set &type, const time_t *t) { SCOPE(X509_STORE, store, X509_STORE_new()); @@ -205,25 +200,15 @@ int X509CertStore::validate(int ok, X509_STORE_CTX *ctx, const set &type case X509_V_ERR_CERT_UNTRUSTED: { X509 *x509 = X509_STORE_CTX_get0_cert(ctx); - SCOPE(AUTHORITY_KEYID, akid, X509_get_ext_d2i(x509, NID_authority_key_identifier, nullptr, nullptr)); for(const TSL::Service &s: *instance()->d) { if(type.find(s.type) == type.cend()) continue; - if(!any_of(s.certs.cbegin(), s.certs.cend(), [&](const X509Cert &issuer){ + if(none_of(s.certs.cbegin(), s.certs.cend(), [&](const X509Cert &issuer){ if(issuer == x509) return true; - if(!akid || !akid->keyid) - { - if(X509_NAME_cmp(X509_get_subject_name(issuer.handle()), X509_get_issuer_name(x509)) != 0) - return false; - } - else - { - SCOPE(ASN1_OCTET_STRING, skid, X509_get_ext_d2i(issuer.handle(), NID_subject_key_identifier, nullptr, nullptr)); - if(!skid || ASN1_OCTET_STRING_cmp(akid->keyid, skid.get()) != 0) - return false; - } + if(X509_check_issued(issuer.handle(), x509) != X509_V_OK) + return false; SCOPE(EVP_PKEY, pub, X509_get_pubkey(issuer.handle())); if(X509_verify(x509, pub.get()) == 1) return true; diff --git a/src/crypto/X509CertStore.h b/src/crypto/X509CertStore.h index 500698a3e..983b566ab 100644 --- a/src/crypto/X509CertStore.h +++ b/src/crypto/X509CertStore.h @@ -41,6 +41,7 @@ namespace digidoc void activate(const std::string &territory) const; std::vector certs(const std::set &type) const; X509Cert findIssuer(const X509Cert &cert, const std::set &type) const; + X509Cert issuerFromAIA(const X509Cert &cert) const; static X509_STORE* createStore(const std::set &type, const time_t *t = nullptr); bool verify(const X509Cert &cert, bool qscd) const;