X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=xmltooling%2Fsecurity%2Fimpl%2FAbstractPKIXTrustEngine.cpp;h=5554fb9b058366feb52c6908f883efd85d61c7da;hb=b23c5dab38620c14e0c3277c840994a11175d59b;hp=69e24f3225b3f761119fb54df6cfd507e4cc5c4a;hpb=eee7b43b039e9fb920fd5c8a94d7934147701f40;p=shibboleth%2Fcpp-xmltooling.git diff --git a/xmltooling/security/impl/AbstractPKIXTrustEngine.cpp b/xmltooling/security/impl/AbstractPKIXTrustEngine.cpp index 69e24f3..5554fb9 100644 --- a/xmltooling/security/impl/AbstractPKIXTrustEngine.cpp +++ b/xmltooling/security/impl/AbstractPKIXTrustEngine.cpp @@ -1,17 +1,21 @@ -/* - * Copyright 2001-2007 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. * - * http://www.apache.org/licenses/LICENSE-2.0 + * UCAID licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the + * License at * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. */ /** @@ -25,165 +29,225 @@ #include "logging.h" #include "security/AbstractPKIXTrustEngine.h" #include "signature/KeyInfo.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "signature/Signature.h" +#include "security/CredentialCriteria.h" +#include "security/CredentialResolver.h" +#include "security/KeyInfoResolver.h" +#include "security/OpenSSLCryptoX509CRL.h" +#include "security/OpenSSLPathValidator.h" +#include "security/PKIXPathValidatorParams.h" +#include "security/SecurityHelper.h" +#include "security/X509Credential.h" +#include "signature/SignatureValidator.h" +#include "util/NDC.h" +#include "util/PathResolver.h" + +#include +#include #include using namespace xmlsignature; using namespace xmltooling::logging; using namespace xmltooling; using namespace std; +using boost::ptr_vector; - -namespace { - static int XMLTOOL_DLLLOCAL error_callback(int ok, X509_STORE_CTX* ctx) +namespace xmltooling { + // Adapter between TrustEngine and PathValidator + class XMLTOOL_DLLLOCAL PKIXParams : public PKIXPathValidatorParams { - if (!ok) - Category::getInstance("OpenSSL").error("path validation failure: %s", X509_verify_cert_error_string(ctx->error)); - return ok; - } + const AbstractPKIXTrustEngine& m_trust; + const AbstractPKIXTrustEngine::PKIXValidationInfoIterator& m_pkixInfo; + vector m_crls; + public: + PKIXParams( + const AbstractPKIXTrustEngine& t, + const AbstractPKIXTrustEngine::PKIXValidationInfoIterator& pkixInfo, + const vector* inlineCRLs + ) : m_trust(t), m_pkixInfo(pkixInfo) { + if (inlineCRLs && !inlineCRLs->empty()) { + m_crls = *inlineCRLs; + m_crls.insert(m_crls.end(), pkixInfo.getCRLs().begin(), pkixInfo.getCRLs().end()); + } + } - static bool XMLTOOL_DLLLOCAL validate( - X509* EE, STACK_OF(X509)* untrusted, AbstractPKIXTrustEngine::PKIXValidationInfoIterator* pkixInfo - ) - { - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine"); - - // First we build a stack of CA certs. These objects are all referenced in place. - log.debug("building CA list from PKIX Validation information"); - - // We need this for CRL support. - X509_STORE* store=X509_STORE_new(); - if (!store) { - log_openssl(); - return false; + virtual ~PKIXParams() {} + + int getVerificationDepth() const { + return m_pkixInfo.getVerificationDepth(); } - #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) - X509_STORE_set_flags(store,X509_V_FLAG_CRL_CHECK_ALL); - #endif - - STACK_OF(X509)* CAstack = sk_X509_new_null(); - - // This contains the state of the validate operation. - X509_STORE_CTX ctx; - - const vector& CAcerts = pkixInfo->getTrustAnchors(); - for (vector::const_iterator i=CAcerts.begin(); i!=CAcerts.end(); ++i) { - if ((*i)->getProviderName()==DSIGConstants::s_unicodeStrPROVOpenSSL) { - sk_X509_push(CAstack,static_cast(*i)->getOpenSSLX509()); - } + bool isAnyPolicyInhibited() const { + return m_trust.m_anyPolicyInhibit; + } + bool isPolicyMappingInhibited() const { + return m_trust.m_policyMappingInhibit; + } + const set& getPolicies() const { + return m_trust.m_policyOIDs; } + const vector& getTrustAnchors() const { + return m_pkixInfo.getTrustAnchors(); + } + PKIXPathValidatorParams::revocation_t getRevocationChecking() const { + if (m_trust.m_checkRevocation.empty() || m_trust.m_checkRevocation == "off") + return PKIXPathValidatorParams::REVOCATION_OFF; + else if (m_trust.m_checkRevocation == "entityOnly") + return PKIXPathValidatorParams::REVOCATION_ENTITYONLY; + else if (m_trust.m_checkRevocation == "fullChain") + return PKIXPathValidatorParams::REVOCATION_FULLCHAIN; + return PKIXPathValidatorParams::REVOCATION_OFF; + } + const vector& getCRLs() const { + return m_crls.empty() ? m_pkixInfo.getCRLs() : m_crls; + } + }; + - const vector& crls = pkixInfo->getCRLs(); - for (vector::const_iterator j=crls.begin(); j!=crls.end(); ++j) { - if ((*j)->getProviderName()==DSIGConstants::s_unicodeStrPROVOpenSSL) { - // owned by store - X509_STORE_add_crl(store, X509_CRL_dup(static_cast(*j)->getOpenSSLX509CRL())); + static XMLCh fullCRLChain[] = UNICODE_LITERAL_12(f,u,l,l,C,R,L,C,h,a,i,n); + static XMLCh checkRevocation[] = UNICODE_LITERAL_15(c,h,e,c,k,R,e,v,o,c,a,t,i,o,n); + static XMLCh policyMappingInhibit[] = UNICODE_LITERAL_20(p,o,l,i,c,y,M,a,p,p,i,n,g,I,n,h,i,b,i,t); + static XMLCh anyPolicyInhibit[] = UNICODE_LITERAL_16(a,n,y,P,o,l,i,c,y,I,n,h,i,b,i,t); + static XMLCh _PathValidator[] = UNICODE_LITERAL_13(P,a,t,h,V,a,l,i,d,a,t,o,r); + static XMLCh PolicyOID[] = UNICODE_LITERAL_9(P,o,l,i,c,y,O,I,D); + static XMLCh TrustedName[] = UNICODE_LITERAL_11(T,r,u,s,t,e,d,N,a,m,e); + static XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e); +}; + +AbstractPKIXTrustEngine::PKIXValidationInfoIterator::PKIXValidationInfoIterator() +{ +} + +AbstractPKIXTrustEngine::PKIXValidationInfoIterator::~PKIXValidationInfoIterator() +{ +} + +AbstractPKIXTrustEngine::AbstractPKIXTrustEngine(const xercesc::DOMElement* e) + : TrustEngine(e), + m_checkRevocation(XMLHelper::getAttrString(e, nullptr, checkRevocation)), + m_fullCRLChain(XMLHelper::getAttrBool(e, false, fullCRLChain)), + m_policyMappingInhibit(XMLHelper::getAttrBool(e, false, policyMappingInhibit)), + m_anyPolicyInhibit(XMLHelper::getAttrBool(e, false, anyPolicyInhibit)) +{ + if (m_fullCRLChain) { + Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX").warn( + "fullCRLChain option is deprecated, setting checkRevocation to \"fullChain\"" + ); + m_checkRevocation = "fullChain"; + } + else if (m_checkRevocation == "fullChain") { + m_fullCRLChain = true; // in case anything's using this + } + + xercesc::DOMElement* c = XMLHelper::getFirstChildElement(e); + while (c) { + if (c->hasChildNodes()) { + auto_ptr_char v(c->getTextContent()); + if (v.get() && *v.get()) { + if (XMLString::equals(c->getLocalName(), PolicyOID)) + m_policyOIDs.insert(v.get()); + else if (XMLString::equals(c->getLocalName(), TrustedName)) + m_trustedNames.insert(v.get()); } } - - // AFAICT, EE and untrusted are passed in but not owned by the ctx. - #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) - if (X509_STORE_CTX_init(&ctx,store,EE,untrusted)!=1) { - log_openssl(); - log.error("unable to initialize X509_STORE_CTX"); - sk_X509_free(CAstack); - X509_STORE_free(store); - return false; - } - #else - X509_STORE_CTX_init(&ctx,store,EE,untrusted); - #endif - - // Seems to be most efficient to just pass in the CA stack. - X509_STORE_CTX_trusted_stack(&ctx,CAstack); - X509_STORE_CTX_set_depth(&ctx,100); // we check the depth down below - X509_STORE_CTX_set_verify_cb(&ctx,error_callback); - - int ret=X509_verify_cert(&ctx); - if (ret==1) { - // Now see if the depth was acceptable by counting the number of intermediates. - int depth=sk_X509_num(ctx.chain)-2; - if (pkixInfo->getVerificationDepth() < depth) { - log.error( - "certificate chain was too long (%d intermediates, only %d allowed)", - (depth==-1) ? 0 : depth, - pkixInfo->getVerificationDepth() + else if (XMLString::equals(c->getLocalName(), _PathValidator)) { + try { + string t = XMLHelper::getAttrString(c, nullptr, type); + if (!t.empty()) { + Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX").info( + "building PathValidator of type %s", t.c_str() + ); + PathValidator* pv = XMLToolingConfig::getConfig().PathValidatorManager.newPlugin(t.c_str(), c); + OpenSSLPathValidator* ospv = dynamic_cast(pv); + if (!ospv) { + delete pv; + throw XMLSecurityException("PathValidator doesn't support OpenSSL interface."); + } + m_pathValidators.push_back(ospv); + } + } + catch (exception& ex) { + Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX").error( + "error building PathValidator: %s", ex.what() ); - ret=0; } } - - // Clean up... - X509_STORE_CTX_cleanup(&ctx); - X509_STORE_free(store); - sk_X509_free(CAstack); - - if (ret==1) { - log.debug("successfully validated certificate chain"); - return true; - } - - return false; + c = XMLHelper::getNextSiblingElement(c); } -}; + + if (m_pathValidators.empty()) { + m_pathValidators.push_back( + dynamic_cast( + XMLToolingConfig::getConfig().PathValidatorManager.newPlugin(PKIX_PATHVALIDATOR, e) + ) + ); + } +} + +AbstractPKIXTrustEngine::~AbstractPKIXTrustEngine() +{ +} bool AbstractPKIXTrustEngine::checkEntityNames( X509* certEE, const CredentialResolver& credResolver, const CredentialCriteria& criteria ) const { - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX"); + Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX"); // We resolve to a set of trusted credentials. vector creds; credResolver.resolve(creds,&criteria); // Build a list of acceptable names. - set trustednames; - trustednames.insert(criteria.getPeerName()); - for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) + set trustednames = m_trustedNames; + if (log.isDebugEnabled()) { + for (set::const_iterator n=m_trustedNames.begin(); n!=m_trustedNames.end(); n++) { + log.debug("adding to list of trusted names (%s)", n->c_str()); + } + } + if (criteria.getPeerName()) { + trustednames.insert(criteria.getPeerName()); + log.debug("adding to list of trusted names (%s)", criteria.getPeerName()); + } + for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) { trustednames.insert((*cred)->getKeyNames().begin(), (*cred)->getKeyNames().end()); + if (log.isDebugEnabled()) { + for (set::const_iterator n=(*cred)->getKeyNames().begin(); n!=(*cred)->getKeyNames().end(); n++) { + log.debug("adding to list of trusted names (%s)", n->c_str()); + } + } + } - char buf[256]; X509_NAME* subject=X509_get_subject_name(certEE); if (subject) { // One way is a direct match to the subject DN. // Seems that the way to do the compare is to write the X509_NAME into a BIO. BIO* b = BIO_new(BIO_s_mem()); BIO* b2 = BIO_new(BIO_s_mem()); - BIO_set_mem_eof_return(b, 0); - BIO_set_mem_eof_return(b2, 0); // The flags give us LDAP order instead of X.500, with a comma separator. - int len=X509_NAME_print_ex(b,subject,0,XN_FLAG_RFC2253); - string subjectstr,subjectstr2; + X509_NAME_print_ex(b,subject,0,XN_FLAG_RFC2253); BIO_flush(b); - while ((len = BIO_read(b, buf, 255)) > 0) { - buf[len] = '\0'; - subjectstr+=buf; - } - log.debugStream() << "certificate subject: " << subjectstr << logging::eol; // The flags give us LDAP order instead of X.500, with a comma plus space separator. - len=X509_NAME_print_ex(b2,subject,0,XN_FLAG_RFC2253 + XN_FLAG_SEP_CPLUS_SPC - XN_FLAG_SEP_COMMA_PLUS); + X509_NAME_print_ex(b2,subject,0,XN_FLAG_RFC2253 + XN_FLAG_SEP_CPLUS_SPC - XN_FLAG_SEP_COMMA_PLUS); BIO_flush(b2); - while ((len = BIO_read(b2, buf, 255)) > 0) { - buf[len] = '\0'; - subjectstr2+=buf; + + BUF_MEM* bptr=nullptr; + BUF_MEM* bptr2=nullptr; + BIO_get_mem_ptr(b, &bptr); + BIO_get_mem_ptr(b2, &bptr2); + + if (bptr && bptr->length > 0 && log.isDebugEnabled()) { + string subjectstr(bptr->data, bptr->length); + log.debug("certificate subject: %s", subjectstr.c_str()); } // Check each keyname. - for (set::const_iterator n=trustednames.begin(); n!=trustednames.end(); n++) { + for (set::const_iterator n=trustednames.begin(); bptr && bptr2 && n!=trustednames.end(); n++) { #ifdef HAVE_STRCASECMP - if (!strcasecmp(n->c_str(),subjectstr.c_str()) || !strcasecmp(n->c_str(),subjectstr2.c_str())) { + if ((n->length() == bptr->length && !strncasecmp(n->c_str(), bptr->data, bptr->length)) || + (n->length() == bptr2->length && !strncasecmp(n->c_str(), bptr2->data, bptr2->length))) { #else - if (!stricmp(n->c_str(),subjectstr.c_str()) || !stricmp(n->c_str(),subjectstr2.c_str())) { + if ((n->length() == bptr->length && !strnicmp(n->c_str(), bptr->data, bptr->length)) || + (n->length() == bptr2->length && !strnicmp(n->c_str(), bptr2->data, bptr2->length))) { #endif log.debug("matched full subject DN to a key name (%s)", n->c_str()); BIO_free(b); @@ -195,7 +259,7 @@ bool AbstractPKIXTrustEngine::checkEntityNames( BIO_free(b2); log.debug("unable to match DN, trying TLS subjectAltName match"); - STACK_OF(GENERAL_NAME)* altnames=(STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(certEE, NID_subject_alt_name, NULL, NULL); + STACK_OF(GENERAL_NAME)* altnames=(STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(certEE, NID_subject_alt_name, nullptr, nullptr); if (altnames) { int numalts = sk_GENERAL_NAME_num(altnames); for (int an=0; and.ia5); for (set::const_iterator n=trustednames.begin(); n!=trustednames.end(); n++) { #ifdef HAVE_STRCASECMP - if ((check->type==GEN_DNS && !strncasecmp(altptr,n->c_str(),altlen)) + if ((check->type==GEN_DNS && n->length()==altlen && !strncasecmp(altptr,n->c_str(),altlen)) #else - if ((check->type==GEN_DNS && !strnicmp(altptr,n->c_str(),altlen)) + if ((check->type==GEN_DNS && n->length()==altlen && !strnicmp(altptr,n->c_str(),altlen)) #endif - || (check->type==GEN_URI && !strncmp(altptr,n->c_str(),altlen))) { + || (check->type==GEN_URI && n->length()==altlen && !strncmp(altptr,n->c_str(),altlen))) { log.debug("matched DNS/URI subjectAltName to a key name (%s)", n->c_str()); GENERAL_NAMES_free(altnames); return true; @@ -221,39 +285,68 @@ bool AbstractPKIXTrustEngine::checkEntityNames( GENERAL_NAMES_free(altnames); log.debug("unable to match subjectAltName, trying TLS CN match"); - memset(buf,0,sizeof(buf)); - if (X509_NAME_get_text_by_NID(subject,NID_commonName,buf,255)>0) { + + // Fetch the last CN RDN. + char* peer_CN = nullptr; + int j,i = -1; + while ((j=X509_NAME_get_index_by_NID(subject, NID_commonName, i)) >= 0) + i = j; + if (i >= 0) { + ASN1_STRING* tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i)); + // Copied in from libcurl. + /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input + is already UTF-8 encoded. We check for this case and copy the raw + string manually to avoid the problem. */ + if(tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { + j = ASN1_STRING_length(tmp); + if(j >= 0) { + peer_CN = (char*)OPENSSL_malloc(j + 1); + memcpy(peer_CN, ASN1_STRING_data(tmp), j); + peer_CN[j] = '\0'; + } + } + else /* not a UTF8 name */ { + j = ASN1_STRING_to_UTF8(reinterpret_cast(&peer_CN), tmp); + } + for (set::const_iterator n=trustednames.begin(); n!=trustednames.end(); n++) { #ifdef HAVE_STRCASECMP - if (!strcasecmp(buf,n->c_str())) { + if (n->length() == j && !strncasecmp(peer_CN, n->c_str(), j)) { #else - if (!stricmp(buf,n->c_str())) { + if (n->length() == j && !strnicmp(peer_CN, n->c_str(), j)) { #endif log.debug("matched subject CN to a key name (%s)", n->c_str()); + if(peer_CN) + OPENSSL_free(peer_CN); return true; } } + if(peer_CN) + OPENSSL_free(peer_CN); } - else + else { log.warn("no common name in certificate subject"); + } } - else + else { log.error("certificate has no subject?!"); + } return false; } -bool AbstractPKIXTrustEngine::validate( +bool AbstractPKIXTrustEngine::validateWithCRLs( X509* certEE, STACK_OF(X509)* certChain, const CredentialResolver& credResolver, - CredentialCriteria* criteria + CredentialCriteria* criteria, + const vector* inlineCRLs ) const { #ifdef _DEBUG - NDC ndc("validate"); + NDC ndc("validateWithCRLs"); #endif - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX"); + Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX"); if (!certEE) { log.error("X.509 credential was NULL, unable to perform validation"); @@ -262,20 +355,32 @@ bool AbstractPKIXTrustEngine::validate( if (criteria && criteria->getPeerName() && *(criteria->getPeerName())) { log.debug("checking that the certificate name is acceptable"); - if (criteria->getUsage()==Credential::UNSPECIFIED_CREDENTIAL) + if (criteria && criteria->getUsage()==Credential::UNSPECIFIED_CREDENTIAL) criteria->setUsage(Credential::SIGNING_CREDENTIAL); if (!checkEntityNames(certEE,credResolver,*criteria)) { log.error("certificate name was not acceptable"); return false; } } + else if (!m_trustedNames.empty()) { + log.debug("checking that the certificate name is acceptable"); + CredentialCriteria cc; + cc.setUsage(Credential::SIGNING_CREDENTIAL); + if (!checkEntityNames(certEE,credResolver,cc)) { + log.error("certificate name was not acceptable"); + return false; + } + } log.debug("performing certificate path validation..."); auto_ptr pkix(getPKIXValidationInfoIterator(credResolver, criteria)); while (pkix->next()) { - if (::validate(certEE,certChain,pkix.get())) { - return true; + PKIXParams params(*this, *pkix.get(), inlineCRLs); + for (ptr_vector::const_iterator v = m_pathValidators.begin(); v != m_pathValidators.end(); ++v) { + if (v->validate(certEE, certChain, params)) { + return true; + } } } @@ -284,6 +389,16 @@ bool AbstractPKIXTrustEngine::validate( } bool AbstractPKIXTrustEngine::validate( + X509* certEE, + STACK_OF(X509)* certChain, + const CredentialResolver& credResolver, + CredentialCriteria* criteria + ) const +{ + return validateWithCRLs(certEE,certChain,credResolver,criteria); +} + +bool AbstractPKIXTrustEngine::validate( XSECCryptoX509* certEE, const vector& certChain, const CredentialResolver& credResolver, @@ -294,11 +409,11 @@ bool AbstractPKIXTrustEngine::validate( NDC ndc("validate"); #endif if (!certEE) { - Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX").error("X.509 credential was NULL, unable to perform validation"); + Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX").error("X.509 credential was NULL, unable to perform validation"); return false; } else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { - Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX").error("only the OpenSSL XSEC provider is supported"); + Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX").error("only the OpenSSL XSEC provider is supported"); return false; } @@ -320,7 +435,7 @@ bool AbstractPKIXTrustEngine::validate( #ifdef _DEBUG NDC ndc("validate"); #endif - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX"); + Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX"); const KeyInfoResolver* inlineResolver = m_keyInfoResolver; if (!inlineResolver) @@ -332,7 +447,7 @@ bool AbstractPKIXTrustEngine::validate( // Pull the certificate chain out of the signature. X509Credential* x509cred; - auto_ptr cred(inlineResolver->resolve(&sig,X509Credential::RESOLVE_CERTS)); + auto_ptr cred(inlineResolver->resolve(&sig,X509Credential::RESOLVE_CERTS|X509Credential::RESOLVE_CRLS)); if (!cred.get() || !(x509cred=dynamic_cast(cred.get()))) { log.error("unable to perform PKIX validation, signature does not contain any certificates"); return false; @@ -347,7 +462,7 @@ bool AbstractPKIXTrustEngine::validate( // Find and save off a pointer to the certificate that unlocks the object. // Most of the time, this will be the first one anyway. - XSECCryptoX509* certEE=NULL; + XSECCryptoX509* certEE=nullptr; SignatureValidator keyValidator; for (vector::const_iterator i=certs.begin(); !certEE && i!=certs.end(); ++i) { try { @@ -362,11 +477,22 @@ bool AbstractPKIXTrustEngine::validate( } } - if (certEE) - return validate(certEE,certs,credResolver,criteria); - - log.debug("failed to verify signature with embedded certificates"); - return false; + if (!certEE) { + log.debug("failed to verify signature with embedded certificates"); + return false; + } + else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { + log.error("only the OpenSSL XSEC provider is supported"); + return false; + } + + STACK_OF(X509)* untrusted=sk_X509_new_null(); + for (vector::const_iterator i=certs.begin(); i!=certs.end(); ++i) + sk_X509_push(untrusted,static_cast(*i)->getOpenSSLX509()); + const vector& crls = x509cred->getCRLs(); + bool ret = validateWithCRLs(static_cast(certEE)->getOpenSSLX509(), untrusted, credResolver, criteria, &crls); + sk_X509_free(untrusted); + return ret; } bool AbstractPKIXTrustEngine::validate( @@ -382,7 +508,7 @@ bool AbstractPKIXTrustEngine::validate( #ifdef _DEBUG NDC ndc("validate"); #endif - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX"); + Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine.PKIX"); if (!keyInfo) { log.error("unable to perform PKIX validation, KeyInfo not present"); @@ -414,7 +540,7 @@ bool AbstractPKIXTrustEngine::validate( // Find and save off a pointer to the certificate that unlocks the object. // Most of the time, this will be the first one anyway. - XSECCryptoX509* certEE=NULL; + XSECCryptoX509* certEE=nullptr; for (vector::const_iterator i=certs.begin(); !certEE && i!=certs.end(); ++i) { try { auto_ptr key((*i)->clonePublicKey()); @@ -427,10 +553,21 @@ bool AbstractPKIXTrustEngine::validate( log.debug(ex.what()); } } - - if (certEE) - return validate(certEE,certs,credResolver,criteria); - - log.debug("failed to verify signature with embedded certificates"); - return false; + + if (!certEE) { + log.debug("failed to verify signature with embedded certificates"); + return false; + } + else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { + log.error("only the OpenSSL XSEC provider is supported"); + return false; + } + + STACK_OF(X509)* untrusted=sk_X509_new_null(); + for (vector::const_iterator i=certs.begin(); i!=certs.end(); ++i) + sk_X509_push(untrusted,static_cast(*i)->getOpenSSLX509()); + const vector& crls = x509cred->getCRLs(); + bool ret = validateWithCRLs(static_cast(certEE)->getOpenSSLX509(), untrusted, credResolver, criteria, &crls); + sk_X509_free(untrusted); + return ret; }