io/AbstractXMLObjectUnmarshaller.h
secinclude_HEADERS = \
+ security/AbstractPKIXTrustEngine.h \
+ security/ChainingTrustEngine.h \
+ security/KeyInfoSource.h \
security/TrustEngine.h \
security/X509TrustEngine.h \
+ security/OpenSSLTrustEngine.h \
security/XSECCryptoX509CRL.h \
security/OpenSSLCryptoX509CRL.h
signature/SignatureValidator.h
soapinclude_HEADERS = \
- soap/SOAP.h
+ soap/SOAP.h \
+ soap/SOAPClient.h \
+ soap/SOAPTransport.h \
+ soap/HTTPSOAPTransport.h \
+ soap/OpenSSLSOAPTransport.h
utilinclude_HEADERS = \
util/DateTime.h \
encryption/impl/Decrypter.cpp \
encryption/impl/Encrypter.cpp \
security/impl/TrustEngine.cpp \
+ security/impl/AbstractPKIXTrustEngine.cpp \
+ security/impl/ChainingTrustEngine.cpp \
security/impl/ExplicitKeyTrustEngine.cpp \
security/impl/XSECCryptoX509CRL.cpp \
security/impl/OpenSSLCryptoX509CRL.cpp \
signature/impl/KeyInfoSchemaValidators.cpp \
soap/impl/SOAPImpl.cpp \
soap/impl/SOAPSchemaValidators.cpp \
+ soap/impl/CURLSOAPTransport.cpp \
util/DateTime.cpp \
util/NDC.cpp \
util/ParserPool.cpp \
* Representing XML QNames
*/
-#if !defined(__xmltooling_qname_h__)
+#ifndef __xmltooling_qname_h__
#define __xmltooling_qname_h__
-#include <algorithm>
#include <xmltooling/unicode.h>
+#include <algorithm>
namespace xmltooling {
#ifndef __xmltooling_xmlobj_h__
#define __xmltooling_xmlobj_h__
+#include <xmltooling/QName.h>
+#include <xmltooling/Namespace.h>
+
#include <set>
#include <list>
#include <vector>
#include <xercesc/dom/DOM.hpp>
-#include <xmltooling/QName.h>
-#include <xmltooling/Namespace.h>
using namespace xercesc;
#include "security/OpenSSLCryptoX509CRL.h"
#include "signature/CredentialResolver.h"
#include "soap/SOAP.h"
+#include "soap/SOAPTransport.h"
#include "util/NDC.h"
#include "util/ReplayCache.h"
#include "util/StorageService.h"
registerCredentialResolvers();
registerTrustEngines();
#endif
+ registerSOAPTransports();
+ initSOAPTransports();
registerStorageServices();
// Register xml:id as an ID attribute.
AttributeExtensibleXMLObject::deregisterIDAttributes();
StorageServiceManager.deregisterFactories();
+ termSOAPTransports();
+ SOAPTransportManager.deregisterFactories();
#ifndef XMLTOOLING_NO_XMLSEC
TrustEngineManager.deregisterFactories();
CredentialResolverManager.deregisterFactories();
static const XMLCh LOCAL_NAME[]
/**
+ * Begins the declaration of an XMLObject specialization with five base classes.
+ * Basic boilerplate includes a protected constructor, empty virtual destructor,
+ * and Unicode constants for the default associated element's name and prefix.
+ *
+ * @param linkage linkage specifier for the class
+ * @param cname the name of the class to declare
+ * @param base the first base class to derive from using public virtual inheritance
+ * @param base2 the second base class to derive from using public virtual inheritance
+ * @param base3 the third base class to derive from using public virtual inheritance
+ * @param base4 the fourth base class to derive from using public virtual inheritance
+ * @param base5 the fifth base class to derive from using public virtual inheritance
+ * @param desc documentation comment for class
+ */
+#define BEGIN_XMLOBJECT5(linkage,cname,base,base2,base3,base4,base5,desc) \
+ XMLTOOLING_DOXYGEN(desc) \
+ class linkage cname : public virtual base, public virtual base2, public virtual base3, public virtual base4, public virtual base5 { \
+ protected: \
+ cname() {} \
+ public: \
+ virtual ~cname() {} \
+ XMLTOOLING_DOXYGEN(Type-specific clone method.) \
+ virtual cname* clone##cname() const=0; \
+ XMLTOOLING_DOXYGEN(Element local name) \
+ static const XMLCh LOCAL_NAME[]
+
+/**
* Ends the declaration of an XMLObject specialization.
*/
#define END_XMLOBJECT }
--- /dev/null
+/*
+ * 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 xmltooling/security/AbstractPKIXTrustEngine.h
+ *
+ * A trust engine that uses X.509 trust anchors and CRLs associated with a KeyInfoSource
+ * to perform PKIX validation of signatures and certificates.
+ */
+
+#if !defined(__xmltooling_pkixtrust_h__) && !defined(XMLTOOLING_NO_XMLSEC)
+#define __xmltooling_pkixtrust_h__
+
+#include <xmltooling/security/OpenSSLTrustEngine.h>
+#include <xmltooling/security/XSECCryptoX509CRL.h>
+
+namespace xmltooling {
+
+ /**
+ * A trust engine that uses X.509 trust anchors and CRLs associated with a KeyInfoSource
+ * to perform PKIX validation of signatures and certificates.
+ */
+ class XMLTOOL_API AbstractPKIXTrustEngine : public OpenSSLTrustEngine
+ {
+ protected:
+ /**
+ * Constructor.
+ *
+ * If a DOM is supplied, the following XML content is supported:
+ *
+ * <ul>
+ * <li><KeyResolver> elements with a type attribute
+ * </ul>
+ *
+ * XML namespaces are ignored in the processing of this content.
+ *
+ * @param e DOM to supply configuration for provider
+ */
+ AbstractPKIXTrustEngine(const DOMElement* e=NULL);
+
+ /**
+ * Checks that either the ID for the entity with the given role or the key names
+ * for the given role match the subject or subject alternate names
+ * of the entity's certificate.
+ *
+ * @param certEE the credential for the entity to validate
+ * @param keyInfoSource supplies KeyInfo objects to the TrustEngine
+ *
+ * @return true the name check succeeds, false if not
+ */
+ bool checkEntityNames(X509* certEE, const KeyInfoSource& keyInfoSource) const;
+
+ /** An inline KeyResolver for extracting certificates out of a signature. */
+ xmlsignature::KeyResolver* m_inlineResolver;
+
+ public:
+ virtual ~AbstractPKIXTrustEngine();
+
+ virtual bool validate(
+ xmlsignature::Signature& sig,
+ const KeyInfoSource& keyInfoSource,
+ const xmlsignature::KeyResolver* keyResolver=NULL
+ ) const;
+
+ virtual bool validate(
+ const XMLCh* sigAlgorithm,
+ const char* sig,
+ xmlsignature::KeyInfo* keyInfo,
+ const char* in,
+ unsigned int in_len,
+ const KeyInfoSource& keyInfoSource,
+ const xmlsignature::KeyResolver* keyResolver=NULL
+ ) const;
+
+ virtual bool validate(
+ XSECCryptoX509* certEE,
+ const std::vector<XSECCryptoX509*>& certChain,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName=true,
+ const xmlsignature::KeyResolver* keyResolver=NULL
+ ) const;
+
+ virtual bool validate(
+ X509* certEE,
+ STACK_OF(X509)* certChain,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName=true,
+ const xmlsignature::KeyResolver* keyResolver=NULL
+ ) const;
+
+ /**
+ * Stateful interface that supplies PKIX validation data to the trust engine.
+ * Applications can adapt this TrustEngine to their environment by returning
+ * implementations of this interface from the getPKIXValidationInfoIterator
+ * method.
+ */
+ class XMLTOOL_API PKIXValidationInfoIterator {
+ MAKE_NONCOPYABLE(PKIXValidationInfoIterator);
+ protected:
+ PKIXValidationInfoIterator() {}
+ public:
+ virtual ~PKIXValidationInfoIterator() {}
+
+ /**
+ * Advances to the next set of information, if any.
+ *
+ * @return true iff another set of information is available
+ */
+ virtual bool next()=0;
+
+ /**
+ * Returns the allowable trust chain verification depth for the
+ * validation data in the current position.
+ *
+ * @return allowable trust chain verification depth
+ */
+ virtual int getVerificationDepth() const=0;
+
+ /**
+ * Returns the set of trust anchors for the validation data in the
+ * current position. Keeping the certificates beyond the lifetime
+ * of the iterator or after advancing to the next position requires
+ * copying them.
+ *
+ * @return set of trust anchors
+ */
+ virtual const std::vector<XSECCryptoX509*>& getTrustAnchors() const=0;
+
+ /**
+ * Returns the set of CRLs for the validation data in the
+ * current position. Keeping the CRLs beyond the lifetime
+ * of the iterator or after advancing to the next position requires
+ * copying them.
+ *
+ * @return set of CRLs
+ */
+ virtual const std::vector<XSECCryptoX509CRL*>& getCRLs() const=0;
+ };
+
+ /**
+ * Provides access to the information necessary, for the given key source, for
+ * PKIX validation of credentials. Each set of validation information returned
+ * will be tried, in turn, until one succeeds or no more remain.
+ * The caller must free the returned interface when finished with it.
+ *
+ * @return interface for obtaining validation data
+ */
+ virtual PKIXValidationInfoIterator* getPKIXValidationInfoIterator(const KeyInfoSource& pkixSource) const=0;
+ };
+};
+
+#endif /* __xmltooling_pkixtrust_h__ */
--- /dev/null
+/*
+ * 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 xmltooling/security/ChainingTrustEngine.h
+ *
+ * X509TrustEngine that uses multiple engines in sequence.
+ */
+
+#if !defined(__xmltooling_chaintrust_h__) && !defined(XMLTOOLING_NO_XMLSEC)
+#define __xmltooling_chaintrust_h__
+
+#include <xmltooling/security/X509TrustEngine.h>
+
+namespace xmltooling {
+
+ /**
+ * X509TrustEngine that uses multiple engines in sequence.
+ */
+ class XMLTOOL_API ChainingTrustEngine : public X509TrustEngine {
+ public:
+ /**
+ * Constructor.
+ *
+ * If a DOM is supplied, the following XML content is supported:
+ *
+ * <ul>
+ * <li><TrustEngine> elements with a type attribute
+ * </ul>
+ *
+ * XML namespaces are ignored in the processing of this content.
+ *
+ * @param e DOM to supply configuration for provider
+ */
+ ChainingTrustEngine(const DOMElement* e=NULL);
+
+ /**
+ * Destructor will delete any embedded engines.
+ */
+ virtual ~ChainingTrustEngine();
+
+ /**
+ * Adds a trust engine for future calls.
+ *
+ * @param newEngine trust engine to add
+ */
+ void addTrustEngine(X509TrustEngine* newEngine) {
+ m_engines.push_back(newEngine);
+ }
+
+ /**
+ * Removes a trust engine. The caller must delete the engine if necessary.
+ *
+ * @param oldEngine trust engine to remove
+ * @return the old engine
+ */
+ X509TrustEngine* removeTrustEngine(X509TrustEngine* oldEngine) {
+ for (std::vector<X509TrustEngine*>::iterator i=m_engines.begin(); i!=m_engines.end(); i++) {
+ if (oldEngine==(*i)) {
+ m_engines.erase(i);
+ return oldEngine;
+ }
+ }
+ return NULL;
+ }
+
+ virtual bool validate(
+ xmlsignature::Signature& sig,
+ const KeyInfoSource& keyInfoSource,
+ const xmlsignature::KeyResolver* keyResolver=NULL
+ ) const;
+ virtual bool validate(
+ const XMLCh* sigAlgorithm,
+ const char* sig,
+ xmlsignature::KeyInfo* keyInfo,
+ const char* in,
+ unsigned int in_len,
+ const KeyInfoSource& keyInfoSource,
+ const xmlsignature::KeyResolver* keyResolver=NULL
+ ) const;
+ virtual bool validate(
+ XSECCryptoX509* certEE,
+ const std::vector<XSECCryptoX509*>& certChain,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName=true,
+ const xmlsignature::KeyResolver* keyResolver=NULL
+ ) const;
+
+ private:
+ std::vector<X509TrustEngine*> m_engines;
+ };
+
+};
+
+#endif /* __xmltooling_chaintrust_h__ */
--- /dev/null
+/*
+ * 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 xmltooling/security/KeyInfoSource.h
+ *
+ * Interface for objects that can supply KeyInfo objects to a TrustEngine
+ * via the KeyInfoIterator interface.
+ */
+
+#if !defined(__xmltooling_keysource_h__) && !defined(XMLTOOLING_NO_XMLSEC)
+#define __xmltooling_keysource_h__
+
+#include <xmltooling/base.h>
+#include <string>
+
+namespace xmlsignature {
+ class XMLTOOL_API KeyInfo;
+};
+
+namespace xmltooling {
+
+ /**
+ * Callback interface to supply KeyInfo objects to a TrustEngine.
+ * Applications can adapt TrustEngines to their environment by supplying
+ * implementations of this interface.
+ */
+ 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;
+ };
+
+ /**
+ * Interface for objects that can supply KeyInfo objects to a TrustEngine
+ * via the KeyInfoIterator interface.
+ */
+ class XMLTOOL_API KeyInfoSource {
+ protected:
+ KeyInfoSource() {}
+ public:
+ virtual ~KeyInfoSource() {}
+
+ /**
+ * Returns the name of this source of keys, for example a peer entity name
+ * or a principal's name.
+ *
+ * @return name of key source, or empty string
+ */
+ virtual std::string getName() const=0;
+
+ /**
+ * Provides access to the KeyInfo information associated with the source.
+ * The caller must free the returned interface when finished with it.
+ *
+ * @return interface for obtaining KeyInfo data
+ */
+ virtual KeyInfoIterator* getKeyInfoIterator() const=0;
+ };
+
+};
+
+#endif /* __xmltooling_keysource_h__ */
--- /dev/null
+/*
+ * 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 xmltooling/security/OpenSSLTrustEngine.h
+ *
+ * Extended TrustEngine interface that adds validation of X.509 credentials
+ * using OpenSSL data types directly for efficiency.
+ */
+
+#if !defined(__xmltooling_openssltrust_h__) && !defined(XMLTOOLING_NO_XMLSEC)
+#define __xmltooling_openssltrust_h__
+
+#include <xmltooling/security/X509TrustEngine.h>
+
+#include <openssl/x509.h>
+
+namespace xmltooling {
+
+ /**
+ * Extended TrustEngine interface that adds validation of X.509 credentials
+ * using OpenSSL data types directly for efficiency.
+ */
+ class XMLTOOL_API OpenSSLTrustEngine : public X509TrustEngine {
+ protected:
+ /**
+ * Constructor.
+ *
+ * If a DOM is supplied, the following XML content is supported:
+ *
+ * <ul>
+ * <li><KeyResolver> elements with a type attribute
+ * </ul>
+ *
+ * XML namespaces are ignored in the processing of this content.
+ *
+ * @param e DOM to supply configuration for provider
+ */
+ OpenSSLTrustEngine(const DOMElement* e=NULL) : X509TrustEngine(e) {}
+
+ public:
+ virtual ~OpenSSLTrustEngine() {}
+
+ /**
+ * Determines whether an X.509 credential is valid with respect to the
+ * source of 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 credential.
+ *
+ * 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 stack of certificates presented for validation (includes certEE)
+ * @param keyInfoSource supplies KeyInfo objects to the TrustEngine
+ * @param checkName true iff certificate subject/name checking has <b>NOT</b> already occurred
+ * @param keyResolver optional externally supplied KeyResolver, or NULL
+ */
+ virtual bool validate(
+ X509* certEE,
+ STACK_OF(X509)* certChain,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName=true,
+ const xmlsignature::KeyResolver* keyResolver=NULL
+ ) const=0;
+ };
+
+};
+
+#endif /* __xmltooling_openssltrust_h__ */
#if !defined(__xmltooling_trust_h__) && !defined(XMLTOOLING_NO_XMLSEC)
#define __xmltooling_trust_h__
+#include <xmltooling/security/KeyInfoSource.h>
#include <xmltooling/signature/KeyResolver.h>
#include <xmltooling/signature/Signature.h>
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 an XML 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.
+ * the source of 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.
*
* <p>A custom KeyResolver can be supplied from outside the TrustEngine.
* Alternatively, one may be specified to the plugin constructor.
*/
virtual bool validate(
xmlsignature::Signature& sig,
- KeyInfoIterator& keyInfoSource,
+ const KeyInfoSource& keyInfoSource,
const xmlsignature::KeyResolver* keyResolver=NULL
) const=0;
/**
* Determines whether a raw 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.
+ * the source of 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.
*
* <p>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.
*
* <p>Note that the keyInfo parameter is not part of the implicitly trusted
- * set of key information supplied via the iterator, but rather advisory data
- * that may have accompanied the signature itself.
+ * set of key information supplied via the KeyInfoSource, but rather advisory
+ * data that may have accompanied the signature itself.
*
* @param sigAlgorithm XML Signature identifier for the algorithm used
* @param sig null-terminated base64-encoded signature value
xmlsignature::KeyInfo* keyInfo,
const char* in,
unsigned int in_len,
- KeyInfoIterator& keyInfoSource,
+ const KeyInfoSource& keyInfoSource,
const xmlsignature::KeyResolver* keyResolver=NULL
) const=0;
};
void XMLTOOL_API registerTrustEngines();
/** TrustEngine based on explicit knowledge of peer key information. */
- #define EXPLICIT_KEY_TRUSTENGINE "org.opensaml.xmlooling.security.ExplicitKeyTrustEngine"
+ #define EXPLICIT_KEY_TRUSTENGINE "org.opensaml.xmltooling.security.ExplicitKeyTrustEngine"
+
+ /** TrustEngine that tries multiple engines in sequence. */
+ #define CHAINING_TRUSTENGINE "org.opensaml.xmltooling.security.ChainingTrustEngine"
+
};
#endif /* __xmltooling_trust_h__ */
/**
* 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.
+ * source of 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 credential.
*
* A custom KeyResolver can be supplied from outside the TrustEngine.
* Alternatively, one may be specified to the plugin constructor.
virtual bool validate(
XSECCryptoX509* certEE,
const std::vector<XSECCryptoX509*>& certChain,
- TrustEngine::KeyInfoIterator& keyInfoSource,
+ const KeyInfoSource& keyInfoSource,
bool checkName=true,
const xmlsignature::KeyResolver* keyResolver=NULL
) const=0;
--- /dev/null
+/*
+ * Copyright 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.
+ */
+
+/**
+ * AbstractPKIXTrustEngine.cpp
+ *
+ * A trust engine that uses X.509 trust anchors and CRLs associated with a KeyInfoSource
+ * to perform PKIX validation of signatures and certificates.
+ */
+
+#include "internal.h"
+#include "security/AbstractPKIXTrustEngine.h"
+#include "signature/KeyInfo.h"
+
+#include <log4cpp/Category.hh>
+#include <openssl/x509_vfy.h>
+#include <openssl/x509v3.h>
+#include <xmltooling/security/OpenSSLCryptoX509CRL.h>
+#include <xmltooling/signature/SignatureValidator.h>
+#include <xmltooling/util/NDC.h>
+#include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
+
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+AbstractPKIXTrustEngine::AbstractPKIXTrustEngine(const DOMElement* e) : OpenSSLTrustEngine(e), m_inlineResolver(NULL)
+{
+ m_inlineResolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(INLINE_KEY_RESOLVER,NULL);
+}
+
+AbstractPKIXTrustEngine::~AbstractPKIXTrustEngine()
+{
+ delete m_inlineResolver;
+}
+
+namespace {
+ static int XMLTOOL_DLLLOCAL error_callback(int ok, X509_STORE_CTX* ctx)
+ {
+ if (!ok)
+ Category::getInstance("OpenSSL").error("path validation failure: %s", X509_verify_cert_error_string(ctx->error));
+ return ok;
+ }
+
+ 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;
+ }
+ #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<XSECCryptoX509*>& CAcerts = pkixInfo->getTrustAnchors();
+ for (vector<XSECCryptoX509*>::const_iterator i=CAcerts.begin(); i!=CAcerts.end(); ++i) {
+ if ((*i)->getProviderName()==DSIGConstants::s_unicodeStrPROVOpenSSL) {
+ sk_X509_push(CAstack,static_cast<OpenSSLCryptoX509*>(*i)->getOpenSSLX509());
+ }
+ }
+
+ const vector<XSECCryptoX509CRL*>& crls = pkixInfo->getCRLs();
+ for (vector<XSECCryptoX509CRL*>::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<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL())
+ );
+ }
+ }
+
+ // 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()
+ );
+ ret=0;
+ }
+ }
+
+ // Clean up...
+ X509_STORE_CTX_cleanup(&ctx);
+ X509_STORE_free(store);
+ sk_X509_free(CAstack);
+
+ if (ret==1) {
+ log.info("successfully validated certificate chain");
+ return true;
+ }
+
+ return false;
+ }
+};
+
+bool AbstractPKIXTrustEngine::checkEntityNames(X509* certEE, const KeyInfoSource& keyInfoSource) const
+{
+ Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
+
+ // Build a list of acceptable names. Transcode the possible key "names" to UTF-8.
+ // For some simple cases, this should handle UTF-8 encoded DNs in certificates.
+ vector<string> keynames;
+ auto_ptr<KeyInfoIterator> keyInfoIter(keyInfoSource.getKeyInfoIterator());
+ while (keyInfoIter->hasNext()) {
+ const KeyInfo* keyInfo = keyInfoIter->next();
+ const vector<KeyName*>& knames=keyInfo->getKeyNames();
+ for (vector<KeyName*>::const_iterator kn_i=knames.begin(); kn_i!=knames.end(); ++kn_i) {
+ const XMLCh* n=(*kn_i)->getName();
+ if (n && *n) {
+ char* kn=toUTF8(n);
+ keynames.push_back(kn);
+ delete[] kn;
+ }
+ }
+ }
+
+ string peername = keyInfoSource.getName();
+ if (!peername.empty())
+ keynames.push_back(peername);
+
+ 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;
+ BIO_flush(b);
+ while ((len = BIO_read(b, buf, 255)) > 0) {
+ buf[len] = '\0';
+ subjectstr+=buf;
+ }
+ log.infoStream() << "certificate subject: " << subjectstr << CategoryStream::ENDLINE;
+ // 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);
+ BIO_flush(b2);
+ while ((len = BIO_read(b2, buf, 255)) > 0) {
+ buf[len] = '\0';
+ subjectstr2+=buf;
+ }
+
+ // Check each keyname.
+ for (vector<string>::const_iterator n=keynames.begin(); n!=keynames.end(); n++) {
+#ifdef HAVE_STRCASECMP
+ if (!strcasecmp(n->c_str(),subjectstr.c_str()) || !strcasecmp(n->c_str(),subjectstr2.c_str())) {
+#else
+ if (!stricmp(n->c_str(),subjectstr.c_str()) || !stricmp(n->c_str(),subjectstr2.c_str())) {
+#endif
+ log.info("matched full subject DN to a key name (%s)", n->c_str());
+ BIO_free(b);
+ BIO_free(b2);
+ return true;
+ }
+ }
+ BIO_free(b);
+ 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);
+ if (altnames) {
+ int numalts = sk_GENERAL_NAME_num(altnames);
+ for (int an=0; an<numalts; an++) {
+ const GENERAL_NAME* check = sk_GENERAL_NAME_value(altnames, an);
+ if (check->type==GEN_DNS || check->type==GEN_URI) {
+ const char* altptr = (char*)ASN1_STRING_data(check->d.ia5);
+ const int altlen = ASN1_STRING_length(check->d.ia5);
+
+ for (vector<string>::const_iterator n=keynames.begin(); n!=keynames.end(); n++) {
+#ifdef HAVE_STRCASECMP
+ if ((check->type==GEN_DNS && !strncasecmp(altptr,n->c_str(),altlen))
+#else
+ if ((check->type==GEN_DNS && !strnicmp(altptr,n->c_str(),altlen))
+#endif
+ || (check->type==GEN_URI && !strncmp(altptr,n->c_str(),altlen))) {
+ log.info("matched DNS/URI subjectAltName to a key name (%s)", n->c_str());
+ GENERAL_NAMES_free(altnames);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ 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) {
+ for (vector<string>::const_iterator n=keynames.begin(); n!=keynames.end(); n++) {
+#ifdef HAVE_STRCASECMP
+ if (!strcasecmp(buf,n->c_str())) {
+#else
+ if (!stricmp(buf,n->c_str())) {
+#endif
+ log.info("matched subject CN to a key name (%s)", n->c_str());
+ return true;
+ }
+ }
+ }
+ else
+ log.warn("no common name in certificate subject");
+ }
+ else
+ log.error("certificate has no subject?!");
+
+ return false;
+}
+
+bool AbstractPKIXTrustEngine::validate(
+ X509* certEE,
+ STACK_OF(X509)* certChain,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName,
+ const KeyResolver* keyResolver
+ ) const
+{
+#ifdef _DEBUG
+ NDC ndc("validate");
+#endif
+ Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
+
+ if (!certEE) {
+ log.error("X.509 credential was NULL, unable to perform validation");
+ return false;
+ }
+
+ if (checkName) {
+ log.debug("checking that the certificate name is acceptable");
+ if (!checkEntityNames(certEE,keyInfoSource)) {
+ log.error("certificate name was not acceptable");
+ return false;
+ }
+ }
+
+ log.debug("performing certificate path validation...");
+
+ auto_ptr<PKIXValidationInfoIterator> pkix(getPKIXValidationInfoIterator(keyInfoSource));
+ while (pkix->next()) {
+ if (::validate(certEE,certChain,pkix.get())) {
+ return true;
+ }
+ }
+
+ log.error("failed to validate certificate chain using supplied PKIX information");
+ return false;
+}
+
+bool AbstractPKIXTrustEngine::validate(
+ XSECCryptoX509* certEE,
+ const vector<XSECCryptoX509*>& certChain,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName,
+ const KeyResolver* keyResolver
+ ) const
+{
+ if (!certEE) {
+#ifdef _DEBUG
+ NDC ndc("validate");
+#endif
+ Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine").error("X.509 credential was NULL, unable to perform validation");
+ return false;
+ }
+ else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
+#ifdef _DEBUG
+ NDC ndc("validate");
+#endif
+ Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine").error("only the OpenSSL XSEC provider is supported");
+ return false;
+ }
+
+ STACK_OF(X509)* untrusted=sk_X509_new_null();
+ for (vector<XSECCryptoX509*>::const_iterator i=certChain.begin(); i!=certChain.end(); ++i) {
+ sk_X509_push(untrusted,static_cast<OpenSSLCryptoX509*>(*i)->getOpenSSLX509());
+ }
+
+ bool ret = validate(static_cast<OpenSSLCryptoX509*>(certEE)->getOpenSSLX509(),untrusted,keyInfoSource,checkName,keyResolver);
+ sk_X509_free(untrusted);
+ return ret;
+}
+
+bool AbstractPKIXTrustEngine::validate(
+ Signature& sig,
+ const KeyInfoSource& keyInfoSource,
+ const KeyResolver* keyResolver
+ ) const
+{
+#ifdef _DEBUG
+ NDC ndc("validate");
+#endif
+ Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
+
+ // Pull the certificate chain out of the signature using an inline KeyResolver.
+ KeyResolver::ResolvedCertificates certs;
+ if (0==m_inlineResolver->resolveCertificates(&sig, certs)) {
+ log.error("unable to perform PKIX validation, signature does not contain any certificates");
+ return false;
+ }
+
+ log.debug("validating signature using certificate from within the signature");
+
+ // 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;
+ SignatureValidator keyValidator;
+ for (vector<XSECCryptoX509*>::const_iterator i=certs.v().begin(); !certEE && i!=certs.v().end(); ++i) {
+ try {
+ keyValidator.setKey((*i)->clonePublicKey());
+ keyValidator.validate(&sig);
+ log.info("signature verified with key inside signature, attempting certificate validation...");
+ certEE=(*i);
+ }
+ catch (ValidationException&) {
+ // trap failures
+ }
+ }
+
+ if (certEE)
+ return validate(certEE,certs.v(),keyInfoSource,true,keyResolver);
+
+ log.error("failed to verify signature with embedded certificates");
+ return false;
+}
+
+bool AbstractPKIXTrustEngine::validate(
+ const XMLCh* sigAlgorithm,
+ const char* sig,
+ KeyInfo* keyInfo,
+ const char* in,
+ unsigned int in_len,
+ const KeyInfoSource& keyInfoSource,
+ const KeyResolver* keyResolver
+ ) const
+{
+#ifdef _DEBUG
+ NDC ndc("validate");
+#endif
+ Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
+
+ // Pull the certificate chain out of the KeyInfo using an inline KeyResolver.
+ KeyResolver::ResolvedCertificates certs;
+ if (!keyInfo || 0==m_inlineResolver->resolveCertificates(keyInfo, certs)) {
+ log.error("unable to perform PKIX validation, KeyInfo does not contain any certificates");
+ return false;
+ }
+
+ log.debug("validating signature using certificate from within KeyInfo");
+
+ // 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;
+ SignatureValidator keyValidator;
+ for (vector<XSECCryptoX509*>::const_iterator i=certs.v().begin(); !certEE && i!=certs.v().end(); ++i) {
+ try {
+ auto_ptr<XSECCryptoKey> key((*i)->clonePublicKey());
+ if (Signature::verifyRawSignature(key.get(), sigAlgorithm, sig, in, in_len)) {
+ log.info("signature verified with key inside signature, attempting certificate validation...");
+ certEE=(*i);
+ }
+ }
+ catch (SignatureException&) {
+ // trap failures
+ }
+ }
+
+ if (certEE)
+ return validate(certEE,certs.v(),keyInfoSource,true,keyResolver);
+
+ log.error("failed to verify signature with embedded certificates");
+ return false;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+/**
+ * ChainingTrustEngine.cpp
+ *
+ * TrustEngine that uses multiple engines in sequence.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "security/ChainingTrustEngine.h"
+
+#include <xercesc/util/XMLUniDefs.hpp>
+
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace std;
+
+namespace xmltooling {
+ TrustEngine* XMLTOOL_DLLLOCAL ChainingTrustEngineFactory(const DOMElement* const & e)
+ {
+ return new ChainingTrustEngine(e);
+ }
+};
+
+static const XMLCh GenericTrustEngine[] = UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e);
+static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);
+
+ChainingTrustEngine::ChainingTrustEngine(const DOMElement* e) : X509TrustEngine(e) {
+ try {
+ e = e ? xmltooling::XMLHelper::getFirstChildElement(e, GenericTrustEngine) : NULL;
+ while (e) {
+ xmltooling::auto_ptr_char temp(e->getAttributeNS(NULL,type));
+ if (temp.get()) {
+ auto_ptr<TrustEngine> engine(
+ XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(temp.get(), e)
+ );
+ X509TrustEngine* x509 = dynamic_cast<X509TrustEngine*>(engine.get());
+ if (x509) {
+ m_engines.push_back(x509);
+ engine.release();
+ }
+ else {
+ throw xmltooling::UnknownExtensionException("Embedded trust engine does not support required interface.");
+ }
+ }
+ e = xmltooling::XMLHelper::getNextSiblingElement(e, GenericTrustEngine);
+ }
+ }
+ catch (xmltooling::XMLToolingException&) {
+ for_each(m_engines.begin(), m_engines.end(), xmltooling::cleanup<X509TrustEngine>());
+ throw;
+ }
+}
+
+ChainingTrustEngine::~ChainingTrustEngine() {
+ for_each(m_engines.begin(), m_engines.end(), xmltooling::cleanup<X509TrustEngine>());
+}
+
+bool ChainingTrustEngine::validate(
+ Signature& sig,
+ const KeyInfoSource& keyInfoSource,
+ const KeyResolver* keyResolver
+ ) const
+{
+ for (vector<X509TrustEngine*>::const_iterator i=m_engines.begin(); i!=m_engines.end(); ++i) {
+ if (static_cast<TrustEngine*>(*i)->validate(sig,keyInfoSource,keyResolver))
+ return true;
+ }
+ return false;
+}
+
+bool ChainingTrustEngine::validate(
+ const XMLCh* sigAlgorithm,
+ const char* sig,
+ KeyInfo* keyInfo,
+ const char* in,
+ unsigned int in_len,
+ const KeyInfoSource& keyInfoSource,
+ const KeyResolver* keyResolver
+ ) const
+{
+ for (vector<X509TrustEngine*>::const_iterator i=m_engines.begin(); i!=m_engines.end(); ++i) {
+ if (static_cast<TrustEngine*>(*i)->validate(sigAlgorithm, sig, keyInfo, in, in_len, keyInfoSource, keyResolver))
+ return true;
+ }
+ return false;
+}
+
+bool ChainingTrustEngine::validate(
+ XSECCryptoX509* certEE,
+ const vector<XSECCryptoX509*>& certChain,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName,
+ const KeyResolver* keyResolver
+ ) const
+{
+ for (vector<X509TrustEngine*>::const_iterator i=m_engines.begin(); i!=m_engines.end(); ++i) {
+ if ((*i)->validate(certEE,certChain,keyInfoSource,checkName,keyResolver))
+ return true;
+ }
+ return false;
+}
*/
#include "internal.h"
-#include "security/X509TrustEngine.h"
+#include "security/OpenSSLTrustEngine.h"
#include "signature/SignatureValidator.h"
#include "util/NDC.h"
using namespace std;
namespace xmltooling {
- class XMLTOOL_DLLLOCAL ExplicitKeyTrustEngine : public X509TrustEngine
+ class XMLTOOL_DLLLOCAL ExplicitKeyTrustEngine : public OpenSSLTrustEngine
{
public:
- ExplicitKeyTrustEngine(const DOMElement* e) : X509TrustEngine(e) {}
+ ExplicitKeyTrustEngine(const DOMElement* e) : OpenSSLTrustEngine(e) {}
virtual ~ExplicitKeyTrustEngine() {}
virtual bool validate(
Signature& sig,
- TrustEngine::KeyInfoIterator& keyInfoSource,
+ const KeyInfoSource& keyInfoSource,
+ const KeyResolver* keyResolver=NULL
+ ) const;
+ virtual bool validate(
+ const XMLCh* sigAlgorithm,
+ const char* sig,
+ KeyInfo* keyInfo,
+ const char* in,
+ unsigned int in_len,
+ const KeyInfoSource& keyInfoSource,
const KeyResolver* keyResolver=NULL
) const;
virtual bool validate(
XSECCryptoX509* certEE,
const vector<XSECCryptoX509*>& certChain,
- TrustEngine::KeyInfoIterator& keyInfoSource,
+ const KeyInfoSource& keyInfoSource,
bool checkName=true,
const KeyResolver* keyResolver=NULL
) const;
virtual bool validate(
- const XMLCh* sigAlgorithm,
- const char* sig,
- KeyInfo* keyInfo,
- const char* in,
- unsigned int in_len,
- KeyInfoIterator& keyInfoSource,
+ X509* certEE,
+ STACK_OF(X509)* certChain,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName=true,
const KeyResolver* keyResolver=NULL
) const;
};
bool ExplicitKeyTrustEngine::validate(
Signature& sig,
- TrustEngine::KeyInfoIterator& keyInfoSource,
+ const KeyInfoSource& keyInfoSource,
const KeyResolver* keyResolver
) const
{
#endif
Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
- if (!keyInfoSource.hasNext()) {
+ auto_ptr<KeyInfoIterator> keyInfoIter(keyInfoSource.getKeyInfoIterator());
+ if (!keyInfoIter->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());
+ while (keyInfoIter->hasNext()) {
+ XSECCryptoKey* key = (keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoIter->next());
if (key) {
log.debug("attempting to validate signature with public key...");
try {
KeyInfo* keyInfo,
const char* in,
unsigned int in_len,
- KeyInfoIterator& keyInfoSource,
+ const KeyInfoSource& keyInfoSource,
const KeyResolver* keyResolver
) const
{
#endif
Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
- if (!keyInfoSource.hasNext()) {
+ auto_ptr<KeyInfoIterator> keyInfoIter(keyInfoSource.getKeyInfoIterator());
+ if (!keyInfoIter->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");
- while (keyInfoSource.hasNext()) {
- auto_ptr<XSECCryptoKey> key((keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoSource.next()));
+ while (keyInfoIter->hasNext()) {
+ auto_ptr<XSECCryptoKey> key((keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoIter->next()));
if (key.get()) {
log.debug("attempting to validate signature with public key...");
try {
bool ExplicitKeyTrustEngine::validate(
XSECCryptoX509* certEE,
const vector<XSECCryptoX509*>& certChain,
- TrustEngine::KeyInfoIterator& keyInfoSource,
+ const KeyInfoSource& keyInfoSource,
+ bool checkName,
+ const KeyResolver* keyResolver
+ ) const
+{
+ if (!certEE) {
+#ifdef _DEBUG
+ NDC ndc("validate");
+#endif
+ Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine").error("unable to validate, end-entity certificate was null");
+ return false;
+ }
+ else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
+#ifdef _DEBUG
+ NDC ndc("validate");
+#endif
+ Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine").error("only the OpenSSL XSEC provider is supported");
+ return false;
+ }
+
+ return validate(static_cast<OpenSSLCryptoX509*>(certEE)->getOpenSSLX509(), NULL, keyInfoSource, checkName, keyResolver);
+}
+
+bool ExplicitKeyTrustEngine::validate(
+ X509* certEE,
+ STACK_OF(X509)* certChain,
+ const KeyInfoSource& keyInfoSource,
bool checkName,
const KeyResolver* keyResolver
) const
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()) {
+
+ auto_ptr<KeyInfoIterator> keyInfoIter(keyInfoSource.getKeyInfoIterator());
+ if (!keyInfoIter->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.
+ // The "basic" trust implementation relies solely on certificates living within the
+ // peer interface to verify the EE certificate.
log.debug("attempting to match key information from peer with end-entity certificate");
- while (keyInfoSource.hasNext()) {
+ while (keyInfoIter->hasNext()) {
KeyResolver::ResolvedCertificates resolvedCerts;
- if (0 == (keyResolver ? keyResolver : m_keyResolver)->resolveCertificates(keyInfoSource.next(),resolvedCerts)) {
+ if (0 == (keyResolver ? keyResolver : m_keyResolver)->resolveCertificates(keyInfoIter->next(),resolvedCerts)) {
log.debug("key information does not resolve to a certificate, skipping it");
continue;
}
log.error("only the OpenSSL XSEC provider is supported");
continue;
}
- else if (!X509_cmp(static_cast<OpenSSLCryptoX509*>(certEE)->getOpenSSLX509(),static_cast<OpenSSLCryptoX509*>(resolvedCerts.v().front())->getOpenSSLX509())) {
+ else if (!X509_cmp(certEE,static_cast<OpenSSLCryptoX509*>(resolvedCerts.v().front())->getOpenSSLX509())) {
log.info("end-entity certificate matches certificate from peer key information");
return true;
}
using namespace std;
namespace xmltooling {
- XMLTOOL_DLLLOCAL PluginManager<TrustEngine,const DOMElement*>::Factory ExplicitKeyTrustEngineFactory;
+ XMLTOOL_DLLLOCAL PluginManager<TrustEngine,const DOMElement*>::Factory ExplicitKeyTrustEngineFactory;
+ XMLTOOL_DLLLOCAL PluginManager<TrustEngine,const DOMElement*>::Factory ChainingTrustEngineFactory;
};
void XMLTOOL_API xmltooling::registerTrustEngines()
{
XMLToolingConfig& conf=XMLToolingConfig::getConfig();
conf.TrustEngineManager.registerFactory(EXPLICIT_KEY_TRUSTENGINE, ExplicitKeyTrustEngineFactory);
+ conf.TrustEngineManager.registerFactory(CHAINING_TRUSTENGINE, ChainingTrustEngineFactory);
}
static const XMLCh GenericKeyResolver[] = UNICODE_LITERAL_11(K,e,y,R,e,s,o,l,v,e,r);
--- /dev/null
+/*
+ * 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 xmltooling/soap/HTTPSOAPTransport.h
+ *
+ * Encapsulates HTTP SOAP transport layer.
+ */
+
+#ifndef __xmltooling_httpsoaptrans_h__
+#define __xmltooling_httpsoaptrans_h__
+
+#include <xmltooling/soap/SOAPTransport.h>
+#include <string>
+#include <vector>
+
+namespace xmltooling {
+
+ /**
+ * Encapsulates HTTP SOAP transport layer.
+ */
+ class XMLTOOL_API HTTPSOAPTransport : public virtual SOAPTransport
+ {
+ protected:
+ HTTPSOAPTransport() {}
+ public:
+ virtual ~HTTPSOAPTransport() {}
+
+ /**
+ * Sets an outgoing HTTP request header.
+ *
+ * @param name name of header, without the colon separator
+ * @param value header value to send
+ * @return true iff the header is successfully set
+ */
+ virtual bool setRequestHeader(const char* name, const char* val) const=0;
+
+ /**
+ * Returns the values of an HTTP response header.
+ *
+ * @param name name of header, without the colon separator
+ * @return reference to array of header values
+ */
+ virtual const std::vector<std::string>& getResponseHeader(const char* name) const=0;
+ };
+
+};
+
+#endif /* __xmltooling_httpsoaptrans_h__ */
--- /dev/null
+/*
+ * 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 xmltooling/soap/OpenSSLSOAPTransport.h
+ *
+ * Encapsulates OpenSSL-capable SOAP transport layer.
+ */
+
+#if !defined(__xmltooling_opensslsoaptrans_h__) && !defined(XMLTOOLING_NO_XMLSEC)
+#define __xmltooling_opensslsoaptrans_h__
+
+#include <xmltooling/signature/CredentialResolver.h>
+#include <xmltooling/soap/SOAPTransport.h>
+
+#include <openssl/ssl.h>
+
+namespace xmltooling {
+
+ /**
+ * Encapsulates OpenSSL-capable SOAP transport layer.
+ */
+ class XMLTOOL_API OpenSSLSOAPTransport : public virtual SOAPTransport
+ {
+ protected:
+ OpenSSLSOAPTransport() {}
+ public:
+ virtual ~OpenSSLSOAPTransport() {}
+
+ /** OpenSSL context callback for manipulating credentials and validation behavior. */
+ typedef bool (*ssl_ctx_callback_fn)(SSL_CTX* ssl_ctx, void* userptr);
+
+ /**
+ * Sets a callback function to invoke against the SSL_CTX before the handshake.
+ *
+ * @param fn callback function
+ * @param userptr a caller-supplied value to pass to the callback function
+ * @return true iff the callback was set
+ */
+ virtual bool setSSLCallback(ssl_ctx_callback_fn fn, void* userptr=NULL) const=0;
+ };
+
+};
+
+#endif /* __xmltooling_opensslsoaptrans_h__ */
--- /dev/null
+/*
+ * 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 xmltooling/soap/SOAPClient.h
+ *
+ * Implements SOAP 1.1 messaging over a transport.
+ */
+
+#ifndef __xmltooling_soap11client_h__
+#define __xmltooling_soap11client_h__
+
+#include <xmltooling/soap/SOAP.h>
+#include <xmltooling/soap/SOAPTransport.h>
+
+namespace soap11 {
+
+ /**
+ * Implements SOAP 1.1 messaging over a transport.
+ *
+ * In the abstract, this can be a one-way exchange, or use asynchronous
+ * transports, but this is mostly theoretical.
+ */
+ class XMLTOOL_API SOAPClient
+ {
+ MAKE_NONCOPYABLE(SOAPClient);
+ public:
+ SOAPClient() : m_response(NULL) {}
+ virtual ~SOAPClient();
+
+ /**
+ * Sends the supplied envelope to the identified recipient/endpoint.
+ *
+ * <p>The caller is responsible for freeing the outgoing envelope.
+ *
+ * <p>The client object will instantiate a transport layer object
+ * appropriate for the endpoint URL provided and supply it to the
+ * prepareTransport() method below.
+ *
+ * @param env SOAP envelope to send
+ * @param to identifier/name of party to send message to
+ * @param endpoint URL of endpoint to recieve message
+ */
+ virtual void send(const Envelope* env, const char* to, const char* endpoint);
+
+ /**
+ * Returns the response message, if any. As long as a response is
+ * "expected" but not available, NULL will be returned. If no response
+ * will be forthcoming, an exception is raised.
+ *
+ * <p>The caller is responsible for freeing the incoming envelope.
+ */
+ virtual Envelope* receive();
+
+ protected:
+ /**
+ * Allows client to supply transport-layer settings prior to sending message.
+ *
+ * @param transport reference to transport layer
+ * @return true iff transport preparation was successful
+ */
+ virtual bool prepareTransport(const xmltooling::SOAPTransport& transport) {}
+
+ /** Holds response until retrieved by caller. */
+ Envelope* m_response;
+ };
+
+};
+
+#endif /* __xmltooling_soap11client_h__ */
--- /dev/null
+/*
+ * 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 xmltooling/soap/SOAPTransport.h
+ *
+ * Encapsulates a transport layer protocol for sending/receiving messages.
+ */
+
+#ifndef __xmltooling_soaptrans_h__
+#define __xmltooling_soaptrans_h__
+
+#include <xmltooling/base.h>
+#include <iostream>
+
+namespace xmlsignature {
+ class XMLTOOL_API CredentialResolver;
+ class XMLTOOL_API KeyResolver;
+};
+
+namespace xmltooling {
+
+ class XMLTOOL_API X509TrustEngine;
+
+ /**
+ * Encapsulates a transport layer protocol for sending/receiving messages.
+ *
+ * Most of the methods are const, meaning they don't affect the transport
+ * layer until the data is sent.
+ */
+ class XMLTOOL_API SOAPTransport
+ {
+ MAKE_NONCOPYABLE(SOAPTransport);
+ protected:
+ SOAPTransport() {}
+ public:
+ virtual ~SOAPTransport() {}
+
+ /**
+ * Sets the connection timeout.
+ *
+ * @param timeout time to wait for connection to server in seconds, or -1 for no timeout
+ * @return true iff the transport supports connection timeouts
+ */
+ virtual bool setConnectTimeout(long timeout) const=0;
+
+ /**
+ * Sets the request timeout.
+ *
+ * @param timeout time to wait for a response in seconds, or -1 for no timeout
+ * @return true iff the transport supports request/response timeouts
+ */
+ virtual bool setTimeout(long timeout) const=0;
+
+ /**
+ * Common types of transport authentication that may be supported.
+ */
+ enum transport_auth_t {
+ transport_auth_none = 0,
+ transport_auth_basic = 1,
+ transport_auth_digest = 2,
+ transport_auth_ntlm = 3,
+ transport_auth_gss = 4
+ };
+
+ /**
+ * Sets a particular form of transport authentication and credentials.
+ *
+ * @param authType type of transport authentication to use
+ * @param username username for transport authentication
+ * @param password simple password/credential for transport authentication
+ * @return true iff the transport supports the indicated form of authentication
+ */
+ virtual bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL) const=0;
+
+#ifndef XMLTOOLING_NO_XMLSEC
+ /**
+ * Provides a CredentialResolver to the transport to supply transport credentials.
+ * The lifetime of the resolver must be longer than the lifetime of this object.
+ *
+ * <p>The CredentialResolver <strong>MUST</strong> be locked by the caller.
+ *
+ * @param credResolver a locked CredentialResolver instance, or NULL
+ * @return true iff the transport supports the use of a CredentialResolver
+ */
+ virtual bool setCredentialResolver(const xmlsignature::CredentialResolver* credResolver) const=0;
+
+ /**
+ * Provides a TrustEngine to the transport to authenticate the transport peer.
+ * The lifetime of the engine must be longer than the lifetime of this object.
+ *
+ * @param trustEngine a TrustEngine instance, or NULL
+ * @param keyResolver optional externally supplied KeyResolver, or NULL
+ * @return true iff the transport supports the use of a TrustEngine
+ */
+ virtual bool setTrustEngine(const X509TrustEngine* trustEngine, const xmlsignature::KeyResolver* keyResolver=NULL) const=0;
+#endif
+
+ /**
+ * Sends a stream of data over the transport, and writes the results into another.
+ *
+ * @param in input stream to send
+ * @param out output stream to write result into
+ */
+ virtual size_t send(std::istream& in, std::ostream& out)=0;
+
+ /**
+ * Returns the MIME type of the response, if any.
+ *
+ * @return MIME type of response, or an empty string
+ */
+ virtual std::string getContentType() const=0;
+ };
+
+ /**
+ * Registers SOAPTransport classes into the runtime.
+ */
+ void XMLTOOL_API registerSOAPTransports();
+
+ /**
+ * Notifies transport infrastructure to initialize.
+ */
+ void XMLTOOL_API initSOAPTransports();
+
+ /**
+ * Notifies transport infrastructure to shutdown.
+ */
+ void XMLTOOL_API termSOAPTransports();
+
+};
+
+#endif /* __xmltooling_soaptrans_h__ */
--- /dev/null
+/*
+ * 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.
+ */
+
+/**
+ * CURLSOAPTransport.cpp
+ *
+ * libcurl-based SOAPTransport implementation
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "security/OpenSSLTrustEngine.h"
+#include "signature/OpenSSLCredentialResolver.h"
+#include "soap/HTTPSOAPTransport.h"
+#include "soap/OpenSSLSOAPTransport.h"
+#include "util/NDC.h"
+#include "util/Threads.h"
+
+#include <list>
+#include <curl/curl.h>
+#include <log4cpp/Category.hh>
+#include <openssl/x509_vfy.h>
+
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace xmltooling {
+
+ // Manages cache of socket connections via CURL handles.
+ class XMLTOOL_DLLLOCAL CURLPool
+ {
+ public:
+ CURLPool() : m_size(256), m_lock(Mutex::create()),
+ m_log(Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport.CURLPool")) {}
+ ~CURLPool();
+
+ CURL* get(const string& to, const char* endpoint);
+ void put(const string& to, const char* endpoint, CURL* handle);
+
+ private:
+ typedef map<string,vector<CURL*> > poolmap_t;
+ poolmap_t m_bindingMap;
+ list< vector<CURL*>* > m_pools;
+ long m_size;
+ Mutex* m_lock;
+ Category& m_log;
+ };
+
+ static XMLTOOL_DLLLOCAL CURLPool* g_CURLPool = NULL;
+
+ class XMLTOOL_DLLLOCAL CURLSOAPTransport : public HTTPSOAPTransport, public OpenSSLSOAPTransport
+ {
+ public:
+ CURLSOAPTransport(const KeyInfoSource& peer, const char* endpoint)
+ : m_peer(peer), m_endpoint(endpoint), m_handle(NULL), m_headers(NULL),
+ m_credResolver(NULL), m_trustEngine(NULL), m_keyResolver(NULL),
+ m_ssl_callback(NULL), m_ssl_userptr(NULL) {
+ m_handle = g_CURLPool->get(peer.getName(), endpoint);
+ curl_easy_setopt(m_handle,CURLOPT_URL,endpoint);
+ curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,15);
+ curl_easy_setopt(m_handle,CURLOPT_TIMEOUT,30);
+ curl_easy_setopt(m_handle,CURLOPT_HTTPAUTH,0);
+ curl_easy_setopt(m_handle,CURLOPT_USERPWD,NULL);
+ curl_easy_setopt(m_handle,CURLOPT_HEADERDATA,this);
+ }
+
+ virtual ~CURLSOAPTransport() {
+ curl_slist_free_all(m_headers);
+ curl_easy_setopt(m_handle,CURLOPT_ERRORBUFFER,NULL);
+ g_CURLPool->put(m_peer.getName(), m_endpoint.c_str(), m_handle);
+ }
+
+ bool setConnectTimeout(long timeout) const {
+ return (curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,timeout)==CURLE_OK);
+ }
+
+ bool setTimeout(long timeout) const {
+ return (curl_easy_setopt(m_handle,CURLOPT_TIMEOUT,timeout)==CURLE_OK);
+ }
+
+ bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL) const;
+
+ bool setCredentialResolver(const CredentialResolver* credResolver) const {
+ const OpenSSLCredentialResolver* down = dynamic_cast<const OpenSSLCredentialResolver*>(credResolver);
+ if (!down) {
+ m_credResolver = NULL;
+ return (credResolver==NULL);
+ }
+ m_credResolver = down;
+ return true;
+ }
+
+ bool setTrustEngine(const X509TrustEngine* trustEngine, const KeyResolver* keyResolver=NULL) const {
+ const OpenSSLTrustEngine* down = dynamic_cast<const OpenSSLTrustEngine*>(trustEngine);
+ if (!down) {
+ m_trustEngine = NULL;
+ m_keyResolver = NULL;
+ return (trustEngine==NULL);
+ }
+ m_trustEngine = down;
+ m_keyResolver = keyResolver;
+ return true;
+ }
+
+ size_t send(istream& in, ostream& out);
+
+ string getContentType() const;
+
+ bool setRequestHeader(const char* name, const char* val) const {
+ string temp(name);
+ temp=temp + ": " + val;
+ m_headers=curl_slist_append(m_headers,temp.c_str());
+ return true;
+ }
+
+ const vector<string>& getResponseHeader(const char* val) const;
+
+ bool setSSLCallback(ssl_ctx_callback_fn fn, void* userptr=NULL) const {
+ m_ssl_callback=fn;
+ m_ssl_userptr=userptr;
+ return true;
+ }
+
+ private:
+ // per-call state
+ const KeyInfoSource& m_peer;
+ string m_endpoint;
+ CURL* m_handle;
+ mutable struct curl_slist* m_headers;
+ map<string,vector<string> > m_response_headers;
+ mutable const OpenSSLCredentialResolver* m_credResolver;
+ mutable const OpenSSLTrustEngine* m_trustEngine;
+ mutable const KeyResolver* m_keyResolver;
+ mutable ssl_ctx_callback_fn m_ssl_callback;
+ mutable void* m_ssl_userptr;
+
+ friend size_t XMLTOOL_DLLLOCAL curl_header_hook(void* ptr, size_t size, size_t nmemb, void* stream);
+ friend CURLcode XMLTOOL_DLLLOCAL xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr);
+ friend int XMLTOOL_DLLLOCAL verify_callback(X509_STORE_CTX* x509_ctx, void* arg);
+ };
+
+ // libcurl callback functions
+ size_t XMLTOOL_DLLLOCAL curl_header_hook(void* ptr, size_t size, size_t nmemb, void* stream);
+ size_t XMLTOOL_DLLLOCAL curl_write_hook(void* ptr, size_t size, size_t nmemb, void* stream);
+ size_t XMLTOOL_DLLLOCAL curl_read_hook( void *ptr, size_t size, size_t nmemb, void *stream);
+ int XMLTOOL_DLLLOCAL curl_debug_hook(CURL* handle, curl_infotype type, char* data, size_t len, void* ptr);
+ CURLcode XMLTOOL_DLLLOCAL xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr);
+ int XMLTOOL_DLLLOCAL verify_callback(X509_STORE_CTX* x509_ctx, void* arg);
+
+ SOAPTransport* CURLSOAPTransportFactory(const pair<const KeyInfoSource*,const char*>& dest)
+ {
+ return new CURLSOAPTransport(*dest.first, dest.second);
+ }
+};
+
+void xmltooling::registerSOAPTransports()
+{
+ XMLToolingConfig& conf=XMLToolingConfig::getConfig();
+ conf.SOAPTransportManager.registerFactory("http", CURLSOAPTransportFactory);
+ conf.SOAPTransportManager.registerFactory("https", CURLSOAPTransportFactory);
+}
+
+void xmltooling::initSOAPTransports()
+{
+ g_CURLPool=new CURLPool();
+}
+
+void xmltooling::termSOAPTransports()
+{
+ delete g_CURLPool;
+ g_CURLPool = NULL;
+}
+
+CURLPool::~CURLPool()
+{
+ for (poolmap_t::iterator i=m_bindingMap.begin(); i!=m_bindingMap.end(); i++) {
+ for (vector<CURL*>::iterator j=i->second.begin(); j!=i->second.end(); j++)
+ curl_easy_cleanup(*j);
+ }
+ delete m_lock;
+}
+
+CURL* CURLPool::get(const string& to, const char* endpoint)
+{
+#ifdef _DEBUG
+ xmltooling::NDC("get");
+#endif
+ m_log.debug("getting connection handle to %s", endpoint);
+ m_lock->lock();
+ poolmap_t::iterator i=m_bindingMap.find(to + "|" + endpoint);
+
+ if (i!=m_bindingMap.end()) {
+ // Move this pool to the front of the list.
+ m_pools.remove(&(i->second));
+ m_pools.push_front(&(i->second));
+
+ // If a free connection exists, return it.
+ if (!(i->second.empty())) {
+ CURL* handle=i->second.back();
+ i->second.pop_back();
+ m_size--;
+ m_lock->unlock();
+ m_log.debug("returning existing connection handle from pool");
+ return handle;
+ }
+ }
+
+ m_lock->unlock();
+ m_log.debug("nothing free in pool, returning new connection handle");
+
+ // Create a new connection and set non-varying options.
+ CURL* handle=curl_easy_init();
+ if (!handle)
+ return NULL;
+ curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
+ curl_easy_setopt(handle,CURLOPT_NOSIGNAL,1);
+ curl_easy_setopt(handle,CURLOPT_FAILONERROR,1);
+ curl_easy_setopt(handle,CURLOPT_SSLVERSION,3);
+ curl_easy_setopt(handle,CURLOPT_SSL_VERIFYHOST,2);
+ curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,&curl_header_hook);
+ curl_easy_setopt(handle,CURLOPT_READFUNCTION,&curl_read_hook);
+ curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,&curl_write_hook);
+ curl_easy_setopt(handle,CURLOPT_DEBUGFUNCTION,&curl_debug_hook);
+
+ return handle;
+}
+
+void CURLPool::put(const string& to, const char* endpoint, CURL* handle)
+{
+ string key = to + "|" + endpoint;
+ m_lock->lock();
+ poolmap_t::iterator i=m_bindingMap.find(key);
+ if (i==m_bindingMap.end())
+ m_pools.push_front(&(m_bindingMap.insert(poolmap_t::value_type(key,vector<CURL*>(1,handle))).first->second));
+ else
+ i->second.push_back(handle);
+
+ CURL* killit=NULL;
+ if (++m_size > 256) {
+ // Kick a handle out from the back of the bus.
+ while (true) {
+ vector<CURL*>* corpse=m_pools.back();
+ if (!corpse->empty()) {
+ killit=corpse->back();
+ corpse->pop_back();
+ m_size--;
+ break;
+ }
+
+ // Move an empty pool up to the front so we don't keep hitting it.
+ m_pools.pop_back();
+ m_pools.push_front(corpse);
+ }
+ }
+ m_lock->unlock();
+ if (killit) {
+ curl_easy_cleanup(killit);
+#ifdef _DEBUG
+ xmltooling::NDC("put");
+#endif
+ m_log.info("conn_pool_max limit reached, dropping an old connection");
+ }
+}
+
+bool CURLSOAPTransport::setAuth(transport_auth_t authType, const char* username, const char* password) const
+{
+ if (authType==transport_auth_none) {
+ if (curl_easy_setopt(m_handle,CURLOPT_HTTPAUTH,0)!=CURLE_OK)
+ return false;
+ return (curl_easy_setopt(m_handle,CURLOPT_USERPWD,NULL)==CURLE_OK);
+ }
+ long flag=0;
+ switch (authType) {
+ case transport_auth_basic: flag = CURLAUTH_BASIC; break;
+ case transport_auth_digest: flag = CURLAUTH_DIGEST; break;
+ case transport_auth_ntlm: flag = CURLAUTH_NTLM; break;
+ case transport_auth_gss: flag = CURLAUTH_GSSNEGOTIATE; break;
+ default: return false;
+ }
+ if (curl_easy_setopt(m_handle,CURLOPT_HTTPAUTH,flag)!=CURLE_OK)
+ return false;
+ string creds = string(username ? username : "") + ':' + (password ? password : "");
+ return (curl_easy_setopt(m_handle,CURLOPT_USERPWD,creds.c_str())==CURLE_OK);
+}
+
+const vector<string>& CURLSOAPTransport::getResponseHeader(const char* name) const
+{
+ static vector<string> emptyVector;
+
+ map<string,vector<string> >::const_iterator i=m_response_headers.find(name);
+ if (i!=m_response_headers.end())
+ return i->second;
+
+ for (map<string,vector<string> >::const_iterator j=m_response_headers.begin(); j!=m_response_headers.end(); j++) {
+#ifdef HAVE_STRCASECMP
+ if (!strcasecmp(j->first.c_str(), name))
+#else
+ if (!stricmp(j->first.c_str(), name))
+#endif
+ return j->second;
+ }
+
+ return emptyVector;
+}
+
+string CURLSOAPTransport::getContentType() const
+{
+ char* content_type=NULL;
+ curl_easy_getinfo(m_handle,CURLINFO_CONTENT_TYPE,&content_type);
+ return content_type ? content_type : "";
+}
+
+size_t CURLSOAPTransport::send(istream& in, ostream& out)
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("send");
+#endif
+ Category& log=Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport");
+ Category& log_curl=Category::getInstance(XMLTOOLING_LOGCAT".libcurl");
+
+ // By this time, the handle has been prepared with the URL to use and the
+ // caller should have executed any set functions to manipulate it.
+
+ // Setup standard per-call curl properties.
+ size_t content_length=0;
+ pair<ostream*,size_t*> output = make_pair(&out,&content_length);
+ curl_easy_setopt(m_handle,CURLOPT_POST,1);
+ curl_easy_setopt(m_handle,CURLOPT_READDATA,&in);
+ curl_easy_setopt(m_handle,CURLOPT_FILE,&output);
+ curl_easy_setopt(m_handle,CURLOPT_DEBUGDATA,&log_curl);
+
+ char curl_errorbuf[CURL_ERROR_SIZE];
+ curl_errorbuf[0]=0;
+ curl_easy_setopt(m_handle,CURLOPT_ERRORBUFFER,curl_errorbuf);
+ if (log_curl.isDebugEnabled())
+ curl_easy_setopt(m_handle,CURLOPT_VERBOSE,1);
+
+ // Set request headers (possibly appended by hooks).
+ curl_easy_setopt(m_handle,CURLOPT_HTTPHEADER,m_headers);
+
+ if (m_ssl_callback || m_credResolver || m_trustEngine) {
+ curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,xml_ssl_ctx_callback);
+ curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_DATA,this);
+ }
+ else {
+ curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,NULL);
+ curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_DATA,NULL);
+ }
+
+ // Verification of the peer is via TrustEngine only.
+ curl_easy_setopt(m_handle,CURLOPT_SSL_VERIFYPEER,0);
+
+ // Make the call.
+ log.info("sending SOAP message to %s", m_endpoint.c_str());
+ if (curl_easy_perform(m_handle) != CURLE_OK) {
+ log.error("failed communicating with SOAP endpoint: %s",
+ (curl_errorbuf[0] ? curl_errorbuf : "no further information available"));
+ throw IOException(
+ string("CURLSOAPTransport::send() failed while contacting SOAP responder: ") +
+ (curl_errorbuf[0] ? curl_errorbuf : "no further information available"));
+ }
+
+ return content_length;
+}
+
+// callback to buffer headers from server
+size_t xmltooling::curl_header_hook(void* ptr, size_t size, size_t nmemb, void* stream)
+{
+ // only handle single-byte data
+ if (size!=1)
+ return 0;
+ CURLSOAPTransport* ctx = reinterpret_cast<CURLSOAPTransport*>(stream);
+ char* buf = (char*)malloc(nmemb + 1);
+ if (buf) {
+ memset(buf,0,nmemb + 1);
+ memcpy(buf,ptr,nmemb);
+ char* sep=(char*)strchr(buf,':');
+ if (sep) {
+ *(sep++)=0;
+ while (*sep==' ')
+ *(sep++)=0;
+ char* white=buf+nmemb-1;
+ while (isspace(*white))
+ *(white--)=0;
+ ctx->m_response_headers[buf].push_back(sep);
+ }
+ free(buf);
+ return nmemb;
+ }
+ return 0;
+}
+
+// callback to send data to server
+size_t xmltooling::curl_read_hook(void* ptr, size_t size, size_t nmemb, void* stream)
+{
+ // *stream is actually an istream object
+ istream& buf=*(reinterpret_cast<istream*>(stream));
+ buf.read(reinterpret_cast<char*>(ptr),size*nmemb);
+ return buf.gcount();
+}
+
+// callback to buffer data from server
+size_t xmltooling::curl_write_hook(void* ptr, size_t size, size_t nmemb, void* stream)
+{
+ pair<ostream*,size_t*>* output = reinterpret_cast<pair<ostream*,size_t*>*>(stream);
+ size_t len = size*nmemb;
+ output->first->write(reinterpret_cast<const char*>(ptr),len);
+ *(output->second) += len;
+ return len;
+}
+
+// callback for curl debug data
+int xmltooling::curl_debug_hook(CURL* handle, curl_infotype type, char* data, size_t len, void* ptr)
+{
+ // *ptr is actually a logging object
+ if (!ptr) return 0;
+ CategoryStream log=reinterpret_cast<Category*>(ptr)->debugStream();
+ for (char* ch=data; len && (isprint(*ch) || isspace(*ch)); len--)
+ log << *ch++;
+ log << CategoryStream::ENDLINE;
+ return 0;
+}
+
+int xmltooling::verify_callback(X509_STORE_CTX* x509_ctx, void* arg)
+{
+ Category::getInstance("OpenSSL").debug("invoking X509 verify callback");
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+ CURLSOAPTransport* ctx = reinterpret_cast<CURLSOAPTransport*>(arg);
+#else
+ // Yes, this sucks. I'd use TLS, but there's no really obvious spot to put the thread key
+ // and global variables suck too. We can't access the X509_STORE_CTX depth directly because
+ // OpenSSL only copies it into the context if it's >=0, and the unsigned pointer may be
+ // negative in the SSL structure's int member.
+ CURLSOAPTransport* ctx = reinterpret_cast<CURLSOAPTransport*>(
+ SSL_get_verify_depth(
+ reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(x509_ctx,SSL_get_ex_data_X509_STORE_CTX_idx()))
+ )
+ );
+#endif
+
+ // Bypass name check (handled for us by curl).
+ if (!ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,ctx->m_peer,false,ctx->m_keyResolver)) {
+ x509_ctx->error=X509_V_ERR_APPLICATION_VERIFICATION; // generic error, check log for plugin specifics
+ return 0;
+ }
+
+ // Signal success. Hopefully it doesn't matter what's actually in the structure now.
+ return 1;
+}
+
+// callback to invoke a caller-defined SSL callback
+CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr)
+{
+ CURLSOAPTransport* conf = reinterpret_cast<CURLSOAPTransport*>(userptr);
+ if (conf->m_credResolver)
+ conf->m_credResolver->attach(ssl_ctx);
+
+ if (conf->m_trustEngine) {
+ SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL);
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+ // With 0.9.7, we can pass a callback argument directly.
+ SSL_CTX_set_cert_verify_callback(ssl_ctx,verify_callback,userptr);
+#else
+ // With 0.9.6, there's no argument, so we're going to use a really embarrassing hack and
+ // stuff the argument in the depth property where it will get copied to the context object
+ // that's handed to the callback.
+ SSL_CTX_set_cert_verify_callback(ssl_ctx,reinterpret_cast<int (*)()>(verify_callback),NULL);
+ SSL_CTX_set_verify_depth(ssl_ctx,reinterpret_cast<int>(userptr));
+#endif
+ }
+
+ if (!conf->m_ssl_callback(ssl_ctx,conf->m_ssl_userptr))
+ return CURLE_SSL_CERTPROBLEM;
+
+ return CURLE_OK;
+}
* Helper classes and types for manipulating Unicode
*/
-#if !defined(__xmltooling_unicode_h__)
+#ifndef __xmltooling_unicode_h__
#define __xmltooling_unicode_h__
+#include <xmltooling/base.h>
+
#include <string>
#include <xercesc/util/XMLString.hpp>
-#include <xmltooling/base.h>
using namespace xercesc;
/>\r
<Tool\r
Name="VCLinkerTool"\r
- AdditionalDependencies="log4cppD.lib xerces-c_2D.lib xsec_1D.lib libeay32_0_9_8D.lib ssleay32_0_9_8D.lib"\r
+ AdditionalDependencies="log4cppD.lib xerces-c_2D.lib xsec_1D.lib libeay32_0_9_8D.lib ssleay32_0_9_8D.lib libcurld_imp.lib"\r
OutputFile="$(OutDir)\$(ProjectName)_1D.dll"\r
LinkIncremental="2"\r
GenerateDebugInformation="true"\r
/>\r
<Tool\r
Name="VCLinkerTool"\r
- AdditionalDependencies="log4cpp.lib xerces-c_2.lib xsec_1.lib libeay32_0_9_8.lib ssleay32_0_9_8.lib"\r
+ AdditionalDependencies="log4cpp.lib xerces-c_2.lib xsec_1.lib libeay32_0_9_8.lib ssleay32_0_9_8.lib libcurl_imp.lib"\r
OutputFile="$(OutDir)\$(ProjectName)_1.dll"\r
LinkIncremental="2"\r
GenerateDebugInformation="true"\r
Name="impl"\r
>\r
<File\r
+ RelativePath=".\security\impl\AbstractPKIXTrustEngine.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\security\impl\ChainingTrustEngine.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\security\impl\ExplicitKeyTrustEngine.cpp"\r
>\r
</File>\r
Name="impl"\r
>\r
<File\r
+ RelativePath=".\soap\impl\CURLSOAPTransport.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\soap\impl\SOAPImpl.cpp"\r
>\r
</File>\r
Name="security"\r
>\r
<File\r
+ RelativePath=".\security\AbstractPKIXTrustEngine.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\security\ChainingTrustEngine.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\security\KeyInfoSource.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\security\OpenSSLCryptoX509CRL.h"\r
>\r
</File>\r
<File\r
+ RelativePath=".\security\OpenSSLTrustEngine.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\security\TrustEngine.h"\r
>\r
</File>\r
Name="soap"\r
>\r
<File\r
+ RelativePath=".\soap\HTTPSOAPTransport.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\soap\OpenSSLSOAPTransport.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\soap\SOAP.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath=".\soap\SOAPClient.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\soap\SOAPTransport.h"\r
+ >\r
+ </File>\r
</Filter>\r
</Filter>\r
<Filter\r
--- /dev/null
+/*
+ * 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 XMLToolingConfig.h
+ *
+ * Library configuration
+ */
+
+#ifndef __xmltooling_config_h__
+#define __xmltooling_config_h__
+
+#include <xmltooling/Lockable.h>
+#include <xmltooling/PluginManager.h>
+#include <xmltooling/util/ParserPool.h>
+
+#ifndef XMLTOOLING_NO_XMLSEC
+namespace xmlsignature {
+ class XMLTOOL_API CredentialResolver;
+ class XMLTOOL_API KeyResolver;
+};
+#endif
+
+#if defined (_MSC_VER)
+ #pragma warning( push )
+ #pragma warning( disable : 4251 )
+#endif
+
+namespace xmltooling {
+
+ class XMLTOOL_API ReplayCache;
+ class XMLTOOL_API SOAPTransport;
+ class XMLTOOL_API StorageService;
+ class XMLTOOL_API TemplateEngine;
+ class XMLTOOL_API TrustEngine;
+ class XMLTOOL_API KeyInfoSource;
+ class XMLTOOL_API XSECCryptoX509CRL;
+
+ /**
+ * Singleton object that manages library startup/shutdown.configuration.
+ *
+ * A locking interface is supplied as a convenience for code that wants to
+ * obtain a global system lock, but the actual configuration itself is not
+ * synchronized.
+ */
+ class XMLTOOL_API XMLToolingConfig : public Lockable
+ {
+ MAKE_NONCOPYABLE(XMLToolingConfig);
+ protected:
+ XMLToolingConfig() : m_replayCache(NULL), clock_skew_secs(180) {}
+
+ /** Global ReplayCache instance. */
+ ReplayCache* m_replayCache;
+
+ /** Global TemplateEngine instance. */
+ TemplateEngine* m_templateEngine;
+ public:
+ virtual ~XMLToolingConfig() {}
+
+ /**
+ * Returns the global configuration object for the library.
+ *
+ * @return reference to the global library configuration object
+ */
+ static XMLToolingConfig& getConfig();
+
+ /**
+ * Initializes library
+ *
+ * Each process using the library MUST call this function exactly once
+ * before using any library classes except for the LogConfig method.
+ *
+ * @return true iff initialization was successful
+ */
+ virtual bool init()=0;
+
+ /**
+ * Shuts down library
+ *
+ * Each process using the library SHOULD call this function exactly once
+ * before terminating itself
+ */
+ virtual void term()=0;
+
+ /**
+ * Loads a shared/dynamic library extension.
+ *
+ * Extension libraries are managed using a pair of "C" linkage functions:<br>
+ * extern "C" int xmltooling_extension_init(void* context);<br>
+ * extern "C" void xmltooling_extension_term();
+ *
+ * This method is internally synchronized.
+ *
+ * @param path pathname of shared library to load into process
+ * @param context arbitrary data to pass to library initialization hook
+ * @return true iff library was loaded successfully
+ */
+ virtual bool load_library(const char* path, void* context=NULL)=0;
+
+ /**
+ * Configure logging system.
+ *
+ * May be called first, before initializing the library. Other calls to it
+ * must be externally synchronized.
+ *
+ * @param config either a logging configuration file, or a level from the set
+ * (DEBUG, INFO, NOTICE, WARN, ERROR, CRIT, ALERT, FATAL, EMERG)
+ * @return true iff configuration was successful
+ */
+ virtual bool log_config(const char* config=NULL)=0;
+
+ /**
+ * Obtains a non-validating parser pool.
+ * Library must be initialized first.
+ *
+ * @return reference to a non-validating parser pool.
+ */
+ virtual ParserPool& getParser() const=0;
+
+ /**
+ * Obtains a validating parser pool.
+ * Library must be initialized first. Schema/catalog registration must be
+ * externally synchronized.
+ *
+ * @return reference to a validating parser pool.
+ */
+ virtual ParserPool& getValidatingParser() const=0;
+
+ /**
+ * Sets the global ReplayCache instance.
+ * This method must be externally synchronized with any code that uses the object.
+ * Any previously set object is destroyed.
+ *
+ * @param replayCache new ReplayCache instance to store
+ */
+ void setReplayCache(ReplayCache* replayCache);
+
+ /**
+ * Returns the global ReplayCache instance.
+ *
+ * @return global ReplayCache or NULL
+ */
+ ReplayCache* getReplayCache() const {
+ return m_replayCache;
+ }
+
+ /**
+ * Sets the global TemplateEngine instance.
+ * This method must be externally synchronized with any code that uses the object.
+ * Any previously set object is destroyed.
+ *
+ * @param templateEngine new TemplateEngine instance to store
+ */
+ void setTemplateEngine(TemplateEngine* templateEngine);
+
+ /**
+ * Returns the global TemplateEngine instance.
+ *
+ * @return global TemplateEngine or NULL
+ */
+ TemplateEngine* getTemplateEngine() const {
+ return m_templateEngine;
+ }
+
+ /**
+ * List of catalog files to load into validating parser pool at initialization time.
+ * Like other path settings, the separator depends on the platform
+ * (semicolon on Windows, colon otherwise).
+ */
+ std::string catalog_path;
+
+ /**
+ * Adjusts any clock comparisons to be more liberal/permissive by the
+ * indicated number of seconds.
+ */
+ unsigned int clock_skew_secs;
+
+#ifndef XMLTOOLING_NO_XMLSEC
+ /**
+ * Returns an X.509 CRL implementation object.
+ */
+ virtual XSECCryptoX509CRL* X509CRL() const=0;
+
+ /**
+ * Manages factories for KeyResolver plugins.
+ */
+ PluginManager<xmlsignature::KeyResolver,const DOMElement*> KeyResolverManager;
+
+ /**
+ * Manages factories for CredentialResolver plugins.
+ */
+ PluginManager<xmlsignature::CredentialResolver,const DOMElement*> CredentialResolverManager;
+
+ /**
+ * Manages factories for TrustEngine plugins.
+ */
+ PluginManager<TrustEngine,const DOMElement*> TrustEngineManager;
+#endif
+
+ /**
+ * Manages factories for SOAPTransport plugins.
+ */
+ PluginManager<SOAPTransport,std::pair<const KeyInfoSource*,const char*>> SOAPTransportManager;
+
+ /**
+ * Manages factories for StorageService plugins.
+ */
+ PluginManager<StorageService,const DOMElement*> StorageServiceManager;
+ };
+
+};
+
+#if defined (_MSC_VER)
+ #pragma warning( pop )
+#endif
+
+#endif /* __xmltooling_config_h__ */