From 2f2e0fb8331affb168f0c5dd6b0792801bd0a8e2 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 17 Aug 2006 01:22:57 +0000 Subject: [PATCH] Base TrustEngine APIs and explicit key engine impl. --- xmltooling/Makefile.am | 6 + xmltooling/XMLToolingConfig.cpp | 5 +- xmltooling/XMLToolingConfig.h | 7 + xmltooling/security/TrustEngine.h | 118 +++++++++++++++ xmltooling/security/X509TrustEngine.h | 80 +++++++++++ .../security/impl/ExplicitKeyTrustEngine.cpp | 160 +++++++++++++++++++++ xmltooling/security/impl/TrustEngine.cpp | 62 ++++++++ xmltooling/signature/SignatureValidator.h | 36 ++++- xmltooling/xmltooling.vcproj | 28 ++++ 9 files changed, 494 insertions(+), 8 deletions(-) create mode 100644 xmltooling/security/TrustEngine.h create mode 100644 xmltooling/security/X509TrustEngine.h create mode 100644 xmltooling/security/impl/ExplicitKeyTrustEngine.cpp create mode 100644 xmltooling/security/impl/TrustEngine.cpp diff --git a/xmltooling/Makefile.am b/xmltooling/Makefile.am index cf26b0a..b882463 100644 --- a/xmltooling/Makefile.am +++ b/xmltooling/Makefile.am @@ -54,6 +54,10 @@ ioinclude_HEADERS = \ io/AbstractXMLObjectMarshaller.h \ io/AbstractXMLObjectUnmarshaller.h +secinclude_HEADERS = \ + security/TrustEngine.h \ + security/X509TrustEngine.h + siginclude_HEADERS = \ signature/CachingKeyResolver.h \ signature/ContentReference.h \ @@ -84,6 +88,8 @@ if BUILD_XMLSEC xmlsec_sources = \ encryption/impl/Decrypter.cpp \ encryption/impl/Encrypter.cpp \ + security/impl/TrustEngine.cpp \ + security/impl/ExplicitKeyTrustEngine.cpp \ signature/impl/CredentialResolver.cpp \ signature/impl/FilesystemCredentialResolver.cpp \ signature/impl/InlineKeyResolver.cpp \ diff --git a/xmltooling/XMLToolingConfig.cpp b/xmltooling/XMLToolingConfig.cpp index ae102b9..e80b136 100644 --- a/xmltooling/XMLToolingConfig.cpp +++ b/xmltooling/XMLToolingConfig.cpp @@ -25,9 +25,8 @@ #include "XMLToolingConfig.h" #include "encryption/Encryption.h" #include "impl/UnknownElement.h" +#include "security/TrustEngine.h" #include "signature/CredentialResolver.h" -#include "signature/KeyResolver.h" -#include "signature/Signature.h" #include "util/NDC.h" #include "util/XMLConstants.h" #include "validation/Validator.h" @@ -179,6 +178,7 @@ bool XMLToolingInternalConfig::init() REGISTER_EXCEPTION_FACTORY(SignatureException,xmlsignature); registerKeyResolvers(); registerCredentialResolvers(); + registerTrustEngines(); #endif } catch (const xercesc::XMLException&) { @@ -198,6 +198,7 @@ void XMLToolingInternalConfig::term() XMLToolingException::deregisterFactories(); #ifndef XMLTOOLING_NO_XMLSEC + TrustEngineManager.deregisterFactories(); CredentialResolverManager.deregisterFactories(); KeyResolverManager.deregisterFactories(); #endif diff --git a/xmltooling/XMLToolingConfig.h b/xmltooling/XMLToolingConfig.h index e2845b8..9995cdb 100644 --- a/xmltooling/XMLToolingConfig.h +++ b/xmltooling/XMLToolingConfig.h @@ -40,6 +40,8 @@ namespace xmlsignature { #endif namespace xmltooling { + + class XMLTOOL_API TrustEngine; /** * Singleton object that manages library startup/shutdown.configuration. @@ -133,6 +135,11 @@ namespace xmltooling { * Manages factories for CredentialResolver plugins. */ xmltooling::PluginManager CredentialResolverManager; + + /** + * Manages factories for TrustEngine plugins. + */ + xmltooling::PluginManager TrustEngineManager; #endif protected: diff --git a/xmltooling/security/TrustEngine.h b/xmltooling/security/TrustEngine.h new file mode 100644 index 0000000..e07d062 --- /dev/null +++ b/xmltooling/security/TrustEngine.h @@ -0,0 +1,118 @@ +/* + * Copyright 2001-2006 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 + * + * 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. + */ + +/** + * @file security/TrustEngine.h + * + * Evaluates the trustworthiness and validity of XML Signatures against + * implementation-specific requirements. + */ + +#if !defined(__xmltooling_trust_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#define __xmltooling_trust_h__ + +#include +#include + +namespace xmltooling { + + /** + * Evaluates the trustworthiness and validity of XML Signatures against + * implementation-specific requirements. + */ + class XMLTOOL_API TrustEngine { + MAKE_NONCOPYABLE(TrustEngine); + protected: + /** + * Constructor. + * + * If a DOM is supplied, the following XML content is supported: + * + *
    + *
  • <KeyResolver> elements with a type attribute + *
+ * + * XML namespaces are ignored in the processing of this content. + * + * @param e DOM to supply configuration for provider + */ + TrustEngine(const DOMElement* e=NULL); + + /** Default KeyResolver instance. */ + xmlsignature::KeyResolver* m_keyResolver; + + public: + virtual ~TrustEngine(); + + /** + * Callback interface to supply KeyInfo objects to a TrustEngine. + * Applications can adapt TrustEngines to their environment by supplying + * implementations of this interface, or create specialized TrustEngine APIs + * by combining a KeyInfoIterator with a delegated TrustEngine. + */ + class XMLTOOL_API KeyInfoIterator { + MAKE_NONCOPYABLE(KeyInfoIterator); + protected: + KeyInfoIterator() {} + public: + virtual ~KeyInfoIterator() {} + + /** + * Indicates whether additional KeyInfo objects are available. + * + * @return true iff another KeyInfo object can be fetched + */ + virtual bool hasNext() const=0; + + /** + * Returns the next KeyInfo object available. + * + * @return the next KeyInfo object, or NULL if none are left + */ + virtual const xmlsignature::KeyInfo* next()=0; + }; + + /** + * Determines whether a signature is correct and valid with respect to the + * KeyInfo data supplied. It is the responsibility of the application to + * ensure that the KeyInfo information supplied is in fact associated with + * the peer who created the signature. + * + * A custom KeyResolver can be supplied from outside the TrustEngine. + * Alternatively, one may be specified to the plugin constructor. + * A non-caching, inline resolver will be used as a fallback. + * + * @param sig reference to a signature object to validate + * @param keyInfoSource supplies KeyInfo objects to the TrustEngine + * @param keyResolver optional externally supplied KeyResolver, or NULL + */ + virtual bool validate( + xmlsignature::Signature& sig, + KeyInfoIterator& keyInfoSource, + const xmlsignature::KeyResolver* keyResolver=NULL + )=0; + }; + + /** + * Registers TrustEngine classes into the runtime. + */ + void XMLTOOL_API registerTrustEngines(); + + /** TrustEngine based on explicit knowledge of peer key information. */ + #define EXPLICIT_KEY_TRUSTENGINE "org.opensaml.xmlooling.security.ExplicitKeyTrustEngine" +}; + +#endif /* __xmltooling_trust_h__ */ diff --git a/xmltooling/security/X509TrustEngine.h b/xmltooling/security/X509TrustEngine.h new file mode 100644 index 0000000..b36ff8f --- /dev/null +++ b/xmltooling/security/X509TrustEngine.h @@ -0,0 +1,80 @@ +/* + * Copyright 2001-2006 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 + * + * 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. + */ + +/** + * @file security/X509TrustEngine.h + * + * Extended TrustEngine interface that adds validation of X.509 credentials. + */ + +#if !defined(__xmltooling_x509trust_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#define __xmltooling_x509trust_h__ + +#include + +namespace xmltooling { + + /** + * Extended TrustEngine interface that adds validation of X.509 credentials. + */ + class XMLTOOL_API X509TrustEngine : public TrustEngine { + protected: + /** + * Constructor. + * + * If a DOM is supplied, the following XML content is supported: + * + *
    + *
  • <KeyResolver> elements with a type attribute + *
+ * + * XML namespaces are ignored in the processing of this content. + * + * @param e DOM to supply configuration for provider + */ + X509TrustEngine(const DOMElement* e=NULL) : TrustEngine(e) {} + + public: + virtual ~X509TrustEngine() {} + + /** + * Determines whether an X.509 credential is valid with respect to the + * KeyInfo data supplied. It is the responsibility of the application to + * ensure that the KeyInfo information supplied is in fact associated with + * the peer who presented the signature. + * + * A custom KeyResolver can be supplied from outside the TrustEngine. + * Alternatively, one may be specified to the plugin constructor. + * A non-caching, inline resolver will be used as a fallback. + * + * @param certEE end-entity certificate to validate + * @param certChain the complete set of certificates presented for validation (includes certEE) + * @param keyInfoSource supplies KeyInfo objects to the TrustEngine + * @param checkName true iff certificate subject/name checking has NOT already occurred + * @param keyResolver optional externally supplied KeyResolver, or NULL + */ + virtual bool validate( + XSECCryptoX509* certEE, + const std::vector& certChain, + TrustEngine::KeyInfoIterator& keyInfoSource, + bool checkName=true, + const xmlsignature::KeyResolver* keyResolver=NULL + )=0; + }; + +}; + +#endif /* __xmltooling_x509trust_h__ */ diff --git a/xmltooling/security/impl/ExplicitKeyTrustEngine.cpp b/xmltooling/security/impl/ExplicitKeyTrustEngine.cpp new file mode 100644 index 0000000..b6fc513 --- /dev/null +++ b/xmltooling/security/impl/ExplicitKeyTrustEngine.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2001-2005 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 + * + * 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. + */ + +/** + * ExplicitKeyTrustEngine.cpp + * + * TrustEngine based on explicit knowledge of peer key information. + */ + +#include "internal.h" +#include "security/X509TrustEngine.h" +#include "signature/SignatureValidator.h" +#include "util/NDC.h" + +#include +#include +#include + +using namespace xmlsignature; +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +namespace xmltooling { + class XMLTOOL_DLLLOCAL ExplicitKeyTrustEngine : public X509TrustEngine + { + public: + ExplicitKeyTrustEngine(const DOMElement* e) : X509TrustEngine(e) {} + virtual ~ExplicitKeyTrustEngine() {} + + virtual bool validate( + Signature& sig, + TrustEngine::KeyInfoIterator& keyInfoSource, + const KeyResolver* keyResolver=NULL + ); + virtual bool validate( + XSECCryptoX509* certEE, + const vector& certChain, + TrustEngine::KeyInfoIterator& keyInfoSource, + bool checkName=true, + const KeyResolver* keyResolver=NULL + ); + + private: + }; + + TrustEngine* XMLTOOL_DLLLOCAL ExplicitKeyTrustEngineFactory(const DOMElement* const & e) + { + return new ExplicitKeyTrustEngine(e); + } +}; + +bool ExplicitKeyTrustEngine::validate( + Signature& sig, + TrustEngine::KeyInfoIterator& keyInfoSource, + const KeyResolver* keyResolver + ) +{ +#ifdef _DEBUG + NDC ndc("validate"); +#endif + Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine"); + + if (!keyInfoSource.hasNext()) { + log.warn("unable to validate signature, no key information available for peer"); + return false; + } + + log.debug("attempting to validate signature with the key information for peer"); + SignatureValidator sigValidator; + while (keyInfoSource.hasNext()) { + XSECCryptoKey* key = (keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoSource.next()); + if (key) { + log.debug("attempting to validate signature with public key..."); + try { + sigValidator.setKey(key); // key now owned by validator + sigValidator.validate(&sig); + log.info("signature validated with public key"); + return true; + } + catch (ValidationException& e) { + if (log.isDebugEnabled()) { + log.debug("public key did not validate signature: %s", e.what()); + } + } + } + else { + log.debug("key information does not resolve to a public key, skipping it"); + } + } + + log.error("no peer key information validated the signature"); + return false; +} + +bool ExplicitKeyTrustEngine::validate( + XSECCryptoX509* certEE, + const vector& certChain, + TrustEngine::KeyInfoIterator& keyInfoSource, + bool checkName, + const KeyResolver* keyResolver + ) +{ +#ifdef _DEBUG + NDC ndc("validate"); +#endif + Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine"); + + if (!certEE) { + log.error("unable to validate, end-entity certificate was null"); + return false; + } + else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { + log.error("only the OpenSSL XSEC provider is supported"); + return false; + } + else if (!keyInfoSource.hasNext()) { + log.warn("unable to validate, no key information available for peer"); + return false; + } + + // The new "basic" trust implementation relies solely on certificates living within the + // role interface to verify the EE certificate. + + log.debug("attempting to match key information from peer with end-entity certificate"); + vector resolvedCerts; + while (keyInfoSource.hasNext()) { + resolvedCerts.clear(); + if (0 == (keyResolver ? keyResolver : m_keyResolver)->resolveCertificates(keyInfoSource.next(),resolvedCerts)) { + log.debug("key information does not resolve to a certificate, skipping it"); + continue; + } + + log.debug("checking if certificates contained within key information match end-entity certificate"); + if (resolvedCerts.front()->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { + log.error("only the OpenSSL XSEC provider is supported"); + continue; + } + else if (!X509_cmp(static_cast(certEE)->getOpenSSLX509(),static_cast(resolvedCerts.front())->getOpenSSLX509())) { + log.info("end-entity certificate matches certificate from peer key information"); + return true; + } + } + + log.debug("no certificates within this peer's key information matched the given end-entity certificate"); + return false; +} diff --git a/xmltooling/security/impl/TrustEngine.cpp b/xmltooling/security/impl/TrustEngine.cpp new file mode 100644 index 0000000..3158fb8 --- /dev/null +++ b/xmltooling/security/impl/TrustEngine.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2001-2006 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 + * + * 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. + */ + +/** + * TrustEngine.cpp + * + * Registration of factories for built-in engines + */ + +#include "internal.h" +#include "security/TrustEngine.h" + +#include + +using namespace xmltooling; +using namespace std; + +namespace xmltooling { + XMLTOOL_DLLLOCAL PluginManager::Factory ExplicitKeyTrustEngineFactory; +}; + +void XMLTOOL_API xmltooling::registerTrustEngines() +{ + XMLToolingConfig& conf=XMLToolingConfig::getConfig(); + conf.TrustEngineManager.registerFactory(EXPLICIT_KEY_TRUSTENGINE, ExplicitKeyTrustEngineFactory); +} + +static const XMLCh GenericKeyResolver[] = UNICODE_LITERAL_11(K,e,y,R,e,s,o,l,v,e,r); +static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e); + +TrustEngine::TrustEngine(const DOMElement* e) : m_keyResolver(NULL) +{ + DOMElement* child = e ? XMLHelper::getFirstChildElement(e,GenericKeyResolver) : NULL; + if (child) { + auto_ptr_char t(child->getAttributeNS(NULL,type)); + if (t.get()) + m_keyResolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(t.get(),child); + else + throw UnknownExtensionException(" element found with no type attribute"); + } + else if (!m_keyResolver) { + m_keyResolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(INLINE_KEY_RESOLVER, child); + } +} + +TrustEngine::~TrustEngine() +{ + delete m_keyResolver; +} diff --git a/xmltooling/signature/SignatureValidator.h b/xmltooling/signature/SignatureValidator.h index 16dd084..7f7fa7d 100644 --- a/xmltooling/signature/SignatureValidator.h +++ b/xmltooling/signature/SignatureValidator.h @@ -30,38 +30,62 @@ namespace xmlsignature { /** - * Validator for signatures based on a KeyResolver + * Validator for signatures based on a Key or a KeyResolver */ - class XMLTOOL_API SignatureValidator : public virtual xmltooling::Validator + class XMLTOOL_API SignatureValidator : public xmltooling::Validator { public: /** - * Constructor + * Constructor using a KeyResolver * - * @param resolver the key resolver to use, will be freed by Validator + * @param resolver the key resolver to use, will be freed by Validator */ - SignatureValidator(KeyResolver* resolver) : m_resolver(resolver) { + SignatureValidator(KeyResolver* resolver) : m_key(NULL), m_resolver(resolver) { + } + + /** + * Constructor using a Key + * + * @param key the verification key to use, will be freed by Validator + */ + SignatureValidator(XSECCryptoKey* key=NULL) : m_key(key), m_resolver(NULL) { } virtual ~SignatureValidator() { + delete m_key; delete m_resolver; } - void validate(const xmltooling::XMLObject* xmlObject) const; + virtual void validate(const xmltooling::XMLObject* xmlObject) const; virtual void validate(const Signature* signature) const; /** + * Replace the current Key, if any, with a new one. + * + * @param key the Key to attach + */ + void setKey(XSECCryptoKey* key) { + delete m_key; + delete m_resolver; + m_resolver=NULL; + m_key=key; + } + + /** * Replace the current KeyResolver, if any, with a new one. * * @param resolver the KeyResolver to attach */ void setKeyResolver(KeyResolver* resolver) { + delete m_key; delete m_resolver; + m_key=NULL; m_resolver=resolver; } protected: + XSECCryptoKey* m_key; KeyResolver* m_resolver; }; diff --git a/xmltooling/xmltooling.vcproj b/xmltooling/xmltooling.vcproj index 9860bce..f897226 100644 --- a/xmltooling/xmltooling.vcproj +++ b/xmltooling/xmltooling.vcproj @@ -349,6 +349,22 @@ + + + + + + + + + + + + + +