From 6505807a62569ce65803b448b07a6872c6af2512 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 26 Mar 2007 05:59:49 +0000 Subject: [PATCH] Major revamp of credential and trust handling code, PKIX engine still needs work. --- .cdtproject | 12 +- xmltooling/AbstractXMLObject.cpp | 3 +- xmltooling/AbstractXMLObject.h | 6 + xmltooling/Makefile.am | 21 +- xmltooling/Namespace.h | 11 +- xmltooling/QName.h | 11 +- xmltooling/XMLObject.h | 8 + xmltooling/XMLToolingConfig.cpp | 14 +- xmltooling/XMLToolingConfig.h | 33 +- xmltooling/encryption/Decrypter.h | 61 ++- xmltooling/encryption/EncryptedKeyResolver.h | 8 +- xmltooling/encryption/Encrypter.h | 55 +-- xmltooling/encryption/impl/Decrypter.cpp | 186 +++++--- .../encryption/impl/EncryptedKeyResolver.cpp | 44 ++ xmltooling/encryption/impl/Encrypter.cpp | 66 +-- xmltooling/impl/UnknownElement.cpp | 7 +- xmltooling/impl/UnknownElement.h | 2 + xmltooling/io/AbstractXMLObjectMarshaller.cpp | 58 ++- xmltooling/io/AbstractXMLObjectMarshaller.h | 19 +- xmltooling/io/AbstractXMLObjectUnmarshaller.cpp | 9 + xmltooling/security/AbstractPKIXTrustEngine.h | 67 ++- xmltooling/security/BasicX509Credential.h | 122 +++++ xmltooling/security/CachingKeyResolver.h | 45 -- xmltooling/security/ChainingTrustEngine.h | 18 +- xmltooling/security/Credential.h | 97 ++++ xmltooling/security/CredentialCriteria.h | 184 ++++++++ xmltooling/security/CredentialResolver.h | 43 +- xmltooling/security/KeyInfoResolver.h | 100 ++++ xmltooling/security/KeyInfoSource.h | 92 ---- xmltooling/security/KeyResolver.h | 248 ---------- ...SSLCredentialResolver.h => OpenSSLCredential.h} | 24 +- xmltooling/security/OpenSSLTrustEngine.h | 32 +- xmltooling/security/TrustEngine.h | 80 ++-- xmltooling/security/X509Credential.h | 67 +++ xmltooling/security/X509TrustEngine.h | 27 +- .../security/impl/AbstractPKIXTrustEngine.cpp | 148 +++--- xmltooling/security/impl/BasicX509Credential.cpp | 114 +++++ xmltooling/security/impl/ChainingTrustEngine.cpp | 30 +- xmltooling/security/impl/Credential.cpp | 66 +++ .../security/impl/ExplicitKeyTrustEngine.cpp | 156 ++++--- .../security/impl/FilesystemCredentialResolver.cpp | 290 +++++++----- xmltooling/security/impl/InlineKeyResolver.cpp | 501 ++++++++------------- xmltooling/security/impl/KeyInfoResolver.cpp | 58 +++ xmltooling/security/impl/KeyResolver.cpp | 94 ---- xmltooling/security/impl/TrustEngine.cpp | 19 +- xmltooling/signature/Signature.h | 4 +- xmltooling/signature/SignatureValidator.h | 53 +-- xmltooling/signature/impl/SignatureValidator.cpp | 15 +- xmltooling/signature/impl/XMLSecSignatureImpl.cpp | 37 +- xmltooling/soap/SOAPClient.h | 14 +- xmltooling/soap/SOAPTransport.h | 29 +- xmltooling/soap/impl/CURLSOAPTransport.cpp | 83 ++-- xmltooling/soap/impl/SOAPClient.cpp | 4 +- xmltooling/util/XMLHelper.h | 18 + xmltooling/xmltooling.vcproj | 36 +- xmltoolingtest/EncryptionTest.h | 20 +- xmltoolingtest/FilesystemCredentialResolverTest.h | 8 +- xmltoolingtest/InlineKeyResolverTest.h | 21 +- xmltoolingtest/SignatureTest.h | 32 +- 59 files changed, 2177 insertions(+), 1553 deletions(-) create mode 100644 xmltooling/encryption/impl/EncryptedKeyResolver.cpp create mode 100644 xmltooling/security/BasicX509Credential.h delete mode 100644 xmltooling/security/CachingKeyResolver.h create mode 100644 xmltooling/security/Credential.h create mode 100644 xmltooling/security/CredentialCriteria.h create mode 100644 xmltooling/security/KeyInfoResolver.h delete mode 100644 xmltooling/security/KeyInfoSource.h delete mode 100644 xmltooling/security/KeyResolver.h rename xmltooling/security/{OpenSSLCredentialResolver.h => OpenSSLCredential.h} (55%) create mode 100644 xmltooling/security/X509Credential.h create mode 100644 xmltooling/security/impl/BasicX509Credential.cpp create mode 100644 xmltooling/security/impl/Credential.cpp create mode 100644 xmltooling/security/impl/KeyInfoResolver.cpp delete mode 100644 xmltooling/security/impl/KeyResolver.cpp diff --git a/.cdtproject b/.cdtproject index 93032dc..874457c 100644 --- a/.cdtproject +++ b/.cdtproject @@ -55,19 +55,19 @@ - - - - - - + + + + + + diff --git a/xmltooling/AbstractXMLObject.cpp b/xmltooling/AbstractXMLObject.cpp index 63d3b73..3eee63a 100644 --- a/xmltooling/AbstractXMLObject.cpp +++ b/xmltooling/AbstractXMLObject.cpp @@ -30,7 +30,7 @@ using namespace xmltooling; AbstractXMLObject::AbstractXMLObject(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType) - : m_log(log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".XMLObject")), m_schemaLocation(NULL), + : m_log(log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".XMLObject")), m_schemaLocation(NULL), m_noNamespaceSchemaLocation(NULL), m_parent(NULL), m_elementQname(nsURI, localName, prefix), m_typeQname(NULL) { addNamespace(Namespace(nsURI, prefix)); @@ -42,6 +42,7 @@ AbstractXMLObject::AbstractXMLObject(const XMLCh* nsURI, const XMLCh* localName, AbstractXMLObject::AbstractXMLObject(const AbstractXMLObject& src) : m_namespaces(src.m_namespaces), m_log(src.m_log), m_schemaLocation(XMLString::replicate(src.m_schemaLocation)), + m_noNamespaceSchemaLocation(XMLString::replicate(src.m_noNamespaceSchemaLocation)), m_parent(NULL), m_elementQname(src.m_elementQname), m_typeQname(NULL) { if (src.m_typeQname) diff --git a/xmltooling/AbstractXMLObject.h b/xmltooling/AbstractXMLObject.h index 4df58e4..576a7d0 100644 --- a/xmltooling/AbstractXMLObject.h +++ b/xmltooling/AbstractXMLObject.h @@ -48,6 +48,7 @@ namespace xmltooling { virtual ~AbstractXMLObject() { delete m_typeQname; XMLString::release(&m_schemaLocation); + XMLString::release(&m_noNamespaceSchemaLocation); } void detach(); @@ -201,6 +202,11 @@ namespace xmltooling { */ XMLCh* m_schemaLocation; + /** + * Stores off xsi:noNamespaceSchemaLocation attribute. + */ + XMLCh* m_noNamespaceSchemaLocation; + private: XMLObject* m_parent; QName m_elementQname; diff --git a/xmltooling/Makefile.am b/xmltooling/Makefile.am index c3f76e2..2b26988 100644 --- a/xmltooling/Makefile.am +++ b/xmltooling/Makefile.am @@ -58,13 +58,15 @@ ioinclude_HEADERS = \ secinclude_HEADERS = \ security/AbstractPKIXTrustEngine.h \ - security/CachingKeyResolver.h \ + security/BasicX509Credential.h \ security/ChainingTrustEngine.h \ + security/Credential.h \ + security/CredentialCriteria.h \ security/CredentialResolver.h \ - security/KeyInfoSource.h \ - security/KeyResolver.h \ - security/OpenSSLCredentialResolver.h \ + security/KeyInfoResolver.h \ + security/OpenSSLCredential.h \ security/TrustEngine.h \ + security/X509Credential.h \ security/X509TrustEngine.h \ security/OpenSSLTrustEngine.h \ security/XSECCryptoX509CRL.h \ @@ -107,17 +109,20 @@ noinst_HEADERS = \ if BUILD_XMLSEC xmlsec_sources = \ encryption/impl/Decrypter.cpp \ + encryption/impl/EncryptedKeyResolver.cpp \ encryption/impl/Encrypter.cpp \ - security/impl/TrustEngine.cpp \ security/impl/AbstractPKIXTrustEngine.cpp \ + security/impl/BasicX509Credential.cpp \ security/impl/ChainingTrustEngine.cpp \ + security/impl/Credential.cpp \ security/impl/CredentialResolver.cpp \ + security/impl/ExplicitKeyTrustEngine.cpp \ security/impl/FilesystemCredentialResolver.cpp \ security/impl/InlineKeyResolver.cpp \ - security/impl/ExplicitKeyTrustEngine.cpp \ - security/impl/KeyResolver.cpp \ - security/impl/XSECCryptoX509CRL.cpp \ + security/impl/KeyInfoResolver.cpp \ security/impl/OpenSSLCryptoX509CRL.cpp \ + security/impl/TrustEngine.cpp \ + security/impl/XSECCryptoX509CRL.cpp \ signature/impl/SignatureValidator.cpp \ signature/impl/XMLSecSignatureImpl.cpp else diff --git a/xmltooling/Namespace.h b/xmltooling/Namespace.h index eafa000..9a1b55a 100644 --- a/xmltooling/Namespace.h +++ b/xmltooling/Namespace.h @@ -26,7 +26,12 @@ #include namespace xmltooling { - + +#if defined (_MSC_VER) + #pragma warning( push ) + #pragma warning( disable : 4251 ) +#endif + /** * A data structure for encapsulating XML Namespace attributes */ @@ -115,6 +120,10 @@ namespace xmltooling { #endif }; +#if defined (_MSC_VER) + #pragma warning( pop ) +#endif + /** * Returns true iff op1's namespace lexically compares less than op2's namespace, * or if equal, iff op1's prefix lexically compares less than op2's prefix. diff --git a/xmltooling/QName.h b/xmltooling/QName.h index 67d1d40..bb672f1 100644 --- a/xmltooling/QName.h +++ b/xmltooling/QName.h @@ -27,7 +27,12 @@ #include namespace xmltooling { - + +#if defined (_MSC_VER) + #pragma warning( push ) + #pragma warning( disable : 4251 ) +#endif + /** * A data structure for encapsulating XML QNames. * The Xerces class is too limited to use at the moment. @@ -168,6 +173,10 @@ namespace xmltooling { #endif }; +#if defined (_MSC_VER) + #pragma warning( pop ) +#endif + /** * Returns true iff op1's namespace lexically compares less than op2's namespace, * or if equal, iff op1's prefix lexically compares less than op2's prefix. diff --git a/xmltooling/XMLObject.h b/xmltooling/XMLObject.h index 1d86737..6dd887f 100644 --- a/xmltooling/XMLObject.h +++ b/xmltooling/XMLObject.h @@ -46,6 +46,10 @@ namespace xmlsignature { namespace xmltooling { +#ifndef XMLTOOLING_NO_XMLSEC + class XMLTOOL_API Credential; +#endif + /** * Object that represents an XML Element that has been unmarshalled into this C++ object. */ @@ -261,6 +265,7 @@ namespace xmltooling { * * @param document the DOM document the marshalled element will be placed in, or NULL * @param sigs ordered array of signatures to create after marshalling is complete + * @param credential optional credential to supply signing key and related info * @return the DOM element representing this XMLObject * * @throws MarshallingException thrown if there is a problem marshalling the given object @@ -270,6 +275,7 @@ namespace xmltooling { DOMDocument* document=NULL #ifndef XMLTOOLING_NO_XMLSEC ,const std::vector* sigs=NULL + ,const Credential* credential=NULL #endif ) const=0; @@ -281,6 +287,7 @@ namespace xmltooling { * * @param parentElement the parent element to append the resulting DOM tree * @param sigs ordered array of signatures to create after marshalling is complete + * @param credential optional credential to supply signing key and related info * @return the marshalled element tree * @throws MarshallingException thrown if the given XMLObject can not be marshalled. @@ -290,6 +297,7 @@ namespace xmltooling { DOMElement* parentElement #ifndef XMLTOOLING_NO_XMLSEC ,const std::vector* sigs=NULL + ,const Credential* credential=NULL #endif ) const=0; diff --git a/xmltooling/XMLToolingConfig.cpp b/xmltooling/XMLToolingConfig.cpp index 5b245d2..4a00d2a 100644 --- a/xmltooling/XMLToolingConfig.cpp +++ b/xmltooling/XMLToolingConfig.cpp @@ -28,6 +28,8 @@ #include "security/TrustEngine.h" #include "security/OpenSSLCryptoX509CRL.h" #include "security/CredentialResolver.h" +#include "security/KeyInfoResolver.h" +#include "signature/Signature.h" #include "soap/SOAP.h" #include "soap/SOAPTransport.h" #include "util/NDC.h" @@ -234,8 +236,6 @@ bool XMLToolingInternalConfig::init() registerEncryptionClasses(); registerSOAPClasses(); - m_urlEncoder = new URLEncoder(); - REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling); REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling); REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MarshallingException,xmltooling); @@ -250,7 +250,7 @@ bool XMLToolingInternalConfig::init() REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLSecurityException,xmltooling); REGISTER_XMLTOOLING_EXCEPTION_FACTORY(SignatureException,xmlsignature); REGISTER_XMLTOOLING_EXCEPTION_FACTORY(EncryptionException,xmlencryption); - registerKeyResolvers(); + registerKeyInfoResolvers(); registerCredentialResolvers(); registerTrustEngines(); #endif @@ -258,6 +258,9 @@ bool XMLToolingInternalConfig::init() initSOAPTransports(); registerStorageServices(); + m_urlEncoder = new URLEncoder(); + m_keyInfoResolver = KeyInfoResolverManager.newPlugin(INLINE_KEYINFO_RESOLVER,NULL); + // Register xml:id as an ID attribute. static const XMLCh xmlid[] = UNICODE_LITERAL_2(i,d); AttributeExtensibleXMLObject::registerIDAttribute(QName(xmlconstants::XML_NS, xmlid)); @@ -297,9 +300,12 @@ void XMLToolingInternalConfig::term() #ifndef XMLTOOLING_NO_XMLSEC TrustEngineManager.deregisterFactories(); CredentialResolverManager.deregisterFactories(); - KeyResolverManager.deregisterFactories(); + KeyInfoResolverManager.deregisterFactories(); #endif + delete m_keyInfoResolver; + m_keyInfoResolver = NULL; + delete m_replayCache; m_replayCache = NULL; diff --git a/xmltooling/XMLToolingConfig.h b/xmltooling/XMLToolingConfig.h index cd04d71..a16b806 100644 --- a/xmltooling/XMLToolingConfig.h +++ b/xmltooling/XMLToolingConfig.h @@ -31,7 +31,7 @@ namespace xmltooling { class XMLTOOL_API CredentialResolver; class XMLTOOL_API KeyInfoSource; - class XMLTOOL_API KeyResolver; + class XMLTOOL_API KeyInfoResolver; class XMLTOOL_API TrustEngine; class XMLTOOL_API XSECCryptoX509CRL; }; @@ -61,8 +61,11 @@ namespace xmltooling { { MAKE_NONCOPYABLE(XMLToolingConfig); protected: - XMLToolingConfig() : m_replayCache(NULL), m_templateEngine(NULL), m_urlEncoder(NULL), clock_skew_secs(180) {} + XMLToolingConfig() : m_keyInfoResolver(NULL), m_replayCache(NULL), m_templateEngine(NULL), m_urlEncoder(NULL), clock_skew_secs(180) {} + /** Global KeyInfoResolver instance. */ + KeyInfoResolver* m_keyInfoResolver; + /** Global ReplayCache instance. */ ReplayCache* m_replayCache; @@ -145,6 +148,24 @@ namespace xmltooling { virtual ParserPool& getValidatingParser() const=0; /** + * Sets the global KeyInfoResolver instance. + * This method must be externally synchronized with any code that uses the object. + * Any previously set object is destroyed. + * + * @param keyInfoResolver new KeyInfoResolver instance to store + */ + void setKeyInfoResolver(KeyInfoResolver* keyInfoResolver); + + /** + * Returns the global KeyInfoResolver instance. + * + * @return global KeyInfoResolver or NULL + */ + const KeyInfoResolver* getKeyInfoResolver() const { + return m_keyInfoResolver; + } + + /** * Sets the global ReplayCache instance. * This method must be externally synchronized with any code that uses the object. * Any previously set object is destroyed. @@ -218,9 +239,9 @@ namespace xmltooling { virtual XSECCryptoX509CRL* X509CRL() const=0; /** - * Manages factories for KeyResolver plugins. + * Manages factories for KeyInfoResolver plugins. */ - PluginManager KeyResolverManager; + PluginManager KeyInfoResolverManager; /** * Manages factories for CredentialResolver plugins. @@ -235,8 +256,10 @@ namespace xmltooling { /** * Manages factories for SOAPTransport plugins. + * + *

The factory interface takes a peer name/endpoint pair. */ - PluginManager > SOAPTransportManager; + PluginManager > SOAPTransportManager; /** * Manages factories for StorageService plugins. diff --git a/xmltooling/encryption/Decrypter.h b/xmltooling/encryption/Decrypter.h index 0d5f27c..e23156a 100644 --- a/xmltooling/encryption/Decrypter.h +++ b/xmltooling/encryption/Decrypter.h @@ -28,12 +28,14 @@ #include namespace xmltooling { + class XMLTOOL_API CredentialCriteria; class XMLTOOL_API CredentialResolver; - class XMLTOOL_API KeyResolver; }; namespace xmlencryption { + class XMLTOOL_API EncryptedKeyResolver; + /** * Wrapper API for XML Decryption functionality. */ @@ -43,34 +45,57 @@ namespace xmlencryption { /** * Constructor. * - * @param KEKresolver locked credential resolver to supply key decryption key - * @param resolver directly or indirectly resolves the data decryption key + * @param credResolver locked credential resolver to supply decryption keys + * @param criteria optional external criteria to use with resolver + * @param EKresolver locates an EncryptedKey pertaining to the EncryptedData */ - Decrypter(const xmltooling::CredentialResolver* KEKresolver=NULL, const xmltooling::KeyResolver* resolver=NULL) - : m_cipher(NULL), m_KEKresolver(KEKresolver), m_resolver(resolver) { + Decrypter( + const xmltooling::CredentialResolver* credResolver=NULL, + xmltooling::CredentialCriteria* criteria=NULL, + const EncryptedKeyResolver* EKResolver=NULL + ) : m_cipher(NULL), m_credResolver(credResolver), m_criteria(criteria), m_EKResolver(EKResolver) { } ~Decrypter(); /** - * Replace the current data encryption KeyResolver interface, if any, with a new one. + * Replace the current EncryptedKeyResolver interface, if any, with a new one. * - * @param resolver the KeyResolver to attach + * @param EKresolver the EncryptedKeyResolver to attach */ - void setKeyResolver(const xmltooling::KeyResolver* resolver) { - m_resolver=resolver; + void setEncryptedKeyResolver(const EncryptedKeyResolver* EKResolver) { + m_EKResolver=EKResolver; } /** - * Replace the current key encryption CredentialResolver interface, if any, with a new one. + * Replace the current CredentialResolver interface, if any, with a new one. * - * @param resolver the locked CredentialResolver to attach + * @param resolver the locked CredentialResolver to attach, or NULL to clear + * @param criteria optional external criteria to use with resolver */ - void setKEKResolver(const xmltooling::CredentialResolver* resolver) { - m_KEKresolver=resolver; + void setKEKResolver(const xmltooling::CredentialResolver* resolver, xmltooling::CredentialCriteria* criteria) { + m_credResolver=resolver; + m_criteria=criteria; } /** + * Decrypts the supplied information using the supplied key, and returns + * the resulting as a DOM fragment owned by the document associated with the + * marshalled EncryptedData object. + * + * Note that the DOM nodes will be invalidated once that document + * is released. The caller should therefore process the DOM fragment as + * required and drop all references to it before that happens. The usual + * approach should be to unmarshall the DOM and then release it, or the + * DOM can also be imported into a separately owned document. + * + * @param encryptedData the data to decrypt + * @param key the decryption key to use (it will not be freed internally) + * @return the decrypted DOM fragment + */ + DOMDocumentFragment* decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key); + + /** * Decrypts the supplied information and returns the resulting as a DOM * fragment owned by the document associated with the marshalled EncryptedData * object. @@ -82,9 +107,10 @@ namespace xmlencryption { * DOM can also be imported into a separately owned document. * * @param encryptedData the data to decrypt + * @param recipient identifier of decrypting entity for use in identifying multi-cast keys * @return the decrypted DOM fragment */ - DOMDocumentFragment* decryptData(EncryptedData& encryptedData); + DOMDocumentFragment* decryptData(const EncryptedData& encryptedData, const XMLCh* recipient=NULL); /** * Decrypts the supplied information and returns the resulting key. @@ -96,12 +122,13 @@ namespace xmlencryption { * @param algorithm the algorithm associated with the decrypted key * @return the decrypted key */ - XSECCryptoKey* decryptKey(EncryptedKey& encryptedKey, const XMLCh* algorithm); + XSECCryptoKey* decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm); private: XENCCipher* m_cipher; - const xmltooling::CredentialResolver* m_KEKresolver; - const xmltooling::KeyResolver* m_resolver; + const xmltooling::CredentialResolver* m_credResolver; + xmltooling::CredentialCriteria* m_criteria; + const EncryptedKeyResolver* m_EKResolver; }; DECL_XMLTOOLING_EXCEPTION(DecryptionException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlencryption,xmltooling::XMLToolingException,Exceptions in decryption processing); diff --git a/xmltooling/encryption/EncryptedKeyResolver.h b/xmltooling/encryption/EncryptedKeyResolver.h index 73dccb3..440c465 100644 --- a/xmltooling/encryption/EncryptedKeyResolver.h +++ b/xmltooling/encryption/EncryptedKeyResolver.h @@ -24,24 +24,26 @@ #define __xmltooling_enckeyres_h__ #include -#include namespace xmlencryption { /** * An API for resolving encrypted decryption keys. */ - class XMLTOOL_API EncryptedKeyResolver : public xmltooling::KeyResolver { + class XMLTOOL_API EncryptedKeyResolver { + MAKE_NONCOPYABLE(EncryptedKeyResolver); public: + EncryptedKeyResolver() {} virtual ~EncryptedKeyResolver() {} /** * Returns an encrypted key based on the supplied object's KeyInfo information. * * @param encryptedData an encrypted object + * @param recipient identifier of recipient of encrypted key * @return the resolved EncryptedKey object */ - virtual EncryptedKey* resolveKey(EncryptedData& encryptedData) const=0; + virtual const EncryptedKey* resolveKey(const EncryptedData& encryptedData, const XMLCh* recipient=NULL) const; }; }; diff --git a/xmltooling/encryption/Encrypter.h b/xmltooling/encryption/Encrypter.h index c562a22..1bf6945 100644 --- a/xmltooling/encryption/Encrypter.h +++ b/xmltooling/encryption/Encrypter.h @@ -28,6 +28,10 @@ #include #include +namespace xmltooling { + class XMLTOOL_API Credential; +}; + namespace xmlencryption { /** @@ -60,34 +64,33 @@ namespace xmlencryption { /** * Constructor. + * * The algorithm constant and key buffer MUST be accessible for the life of - * the structure. The other objects will be destroyed if need be when the structure is destroyed. + * the structure. * - * @param algorithm the XML Encryption key wrapping or transport algorithm constant + * @param algorithm the XML Encryption algorithm constant * @param keyBuffer buffer containing the raw key information * @param keyBufferSize the size of the raw key buffer in bytes - * @param key the key encryption key to use, or NULL - * @param keyInfo a KeyInfo object to place within the EncryptedData structure + * @param credential optional Credential supplying the encryption key + * @param compact true iff the encrypted representation should be made as small as possible */ EncryptionParams( const XMLCh* algorithm=DSIGConstants::s_unicodeStrURIAES256_CBC, const unsigned char* keyBuffer=NULL, unsigned int keyBufferSize=0, - XSECCryptoKey* key=NULL, - xmlsignature::KeyInfo* keyInfo=NULL - ) : m_keyBuffer(keyBuffer), m_keyBufferSize(keyBufferSize), m_key(key), m_keyInfo(keyInfo), m_algorithm(algorithm) { + const xmltooling::Credential* credential=NULL, + bool compact=false + ) : m_algorithm(algorithm), m_keyBuffer(keyBuffer), m_keyBufferSize(keyBufferSize), + m_credential(credential), m_compact(compact) { } - ~EncryptionParams() { - delete m_key; - delete m_keyInfo; - } + ~EncryptionParams() {} private: + const XMLCh* m_algorithm; const unsigned char* m_keyBuffer; unsigned int m_keyBufferSize; - XSECCryptoKey* m_key; - xmlsignature::KeyInfo* m_keyInfo; - const XMLCh* m_algorithm; + const xmltooling::Credential* m_credential; + bool m_compact; friend class Encrypter; }; @@ -99,32 +102,23 @@ namespace xmlencryption { /** * Constructor. - * The algorithm and recipient constants MUST be accessible for the life of the - * structure. Using a static constant suffices for this. The other objects will be destroyed if - * when the structure is destroyed. * + * @param credential a Credential supplying the key encryption key * @param algorithm the XML Encryption key wrapping or transport algorithm constant - * @param key the key encryption key to use * @param recipient optional name of recipient of encrypted key - * @param keyInfo a KeyInfo object to place within the EncryptedKey structure that describes the KEK */ KeyEncryptionParams( + const xmltooling::Credential& credential, const XMLCh* algorithm, - XSECCryptoKey* key, - const XMLCh* recipient=NULL, - xmlsignature::KeyInfo* keyInfo=NULL - ) : m_algorithm(algorithm), m_key(key), m_recipient(recipient), m_keyInfo(keyInfo) { + const XMLCh* recipient=NULL + ) : m_credential(credential), m_algorithm(algorithm), m_recipient(recipient) { } - ~KeyEncryptionParams() { - delete m_key; - delete m_keyInfo; - } + ~KeyEncryptionParams() {} private: + const xmltooling::Credential& m_credential; const XMLCh* m_algorithm; - XSECCryptoKey* m_key; const XMLCh* m_recipient; - xmlsignature::KeyInfo* m_keyInfo; friend class Encrypter; }; @@ -190,9 +184,10 @@ namespace xmlencryption { * @param keyBuffer raw key material to encrypt * @param keyBufferSize size in bytes of raw key material * @param kencParams key encryption settings + * @param compact true iff the encrypted representation should be made as small as possible * @return a stand-alone EncryptedKey object, unconnected to any DOM */ - EncryptedKey* encryptKey(const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams); + EncryptedKey* encryptKey(const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact=false); private: void checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams); diff --git a/xmltooling/encryption/impl/Decrypter.cpp b/xmltooling/encryption/impl/Decrypter.cpp index 2f2afe2..aaeed9d 100644 --- a/xmltooling/encryption/impl/Decrypter.cpp +++ b/xmltooling/encryption/impl/Decrypter.cpp @@ -23,6 +23,8 @@ #include "internal.h" #include "encryption/Decrypter.h" #include "encryption/EncryptedKeyResolver.h" +#include "security/Credential.h" +#include "security/CredentialCriteria.h" #include "security/CredentialResolver.h" #include @@ -44,11 +46,11 @@ Decrypter::~Decrypter() XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); } -DOMDocumentFragment* Decrypter::decryptData(EncryptedData& encryptedData) +DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key) { if (encryptedData.getDOM()==NULL) throw DecryptionException("The object must be marshalled before decryption."); - + // We can reuse the cipher object if the document hasn't changed. if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) { @@ -58,56 +60,9 @@ DOMDocumentFragment* Decrypter::decryptData(EncryptedData& encryptedData) if (!m_cipher) m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); - - try { - // Resolve decryption key. - XSECCryptoKey* key=NULL; - if (m_resolver) - key=m_resolver->resolveKey(encryptedData.getKeyInfo()); - - if (!key && m_KEKresolver) { - // See if there's an encrypted key available. We'll need the algorithm... - const XMLCh* algorithm= - encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL; - if (!algorithm) - throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed."); - - if (encryptedData.getKeyInfo()) { - const vector& others=const_cast(encryptedData.getKeyInfo())->getUnknownXMLObjects(); - for (vector::const_iterator i=others.begin(); i!=others.end(); i++) { - EncryptedKey* encKey=dynamic_cast(*i); - if (encKey) { - try { - key=decryptKey(*encKey, algorithm); - } - catch (DecryptionException& e) { - log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(e.what()); - } - } - } - } - - if (!key) { - // Check for a non-trivial resolver. - const EncryptedKeyResolver* ekr=dynamic_cast(m_resolver); - if (ekr) { - EncryptedKey* encKey=ekr->resolveKey(encryptedData); - if (encKey) { - try { - key=decryptKey(*encKey, algorithm); - } - catch (DecryptionException& e) { - log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(e.what()); - } - } - } - } - } - if (!key) - throw DecryptionException("Unable to resolve a decryption key."); - - m_cipher->setKey(key); + try { + m_cipher->setKey(key->clone()); DOMNode* ret=m_cipher->decryptElementDetached(encryptedData.getDOM()); if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) { ret->release(); @@ -124,8 +79,78 @@ DOMDocumentFragment* Decrypter::decryptData(EncryptedData& encryptedData) } } -XSECCryptoKey* Decrypter::decryptKey(EncryptedKey& encryptedKey, const XMLCh* algorithm) +DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const XMLCh* recipient) { + if (!m_credResolver) + throw DecryptionException("No CredentialResolver supplied to provide decryption keys."); + + // Resolve a decryption key directly. + vector creds; + if (m_criteria) { + m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); + m_criteria->setKeyInfo(encryptedData.getKeyInfo()); + const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); + if (meth) { + auto_ptr_char alg(meth->getAlgorithm()); + m_criteria->setKeyAlgorithm(alg.get()); + } + m_credResolver->resolve(creds,m_criteria); + } + else { + CredentialCriteria criteria; + criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); + criteria.setKeyInfo(encryptedData.getKeyInfo()); + const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); + if (meth) { + auto_ptr_char alg(meth->getAlgorithm()); + criteria.setKeyAlgorithm(alg.get()); + } + m_credResolver->resolve(creds,&criteria); + } + + // Loop over them and try each one. + XSECCryptoKey* key; + for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) { + try { + key = (*cred)->getPrivateKey(); + if (!key) + continue; + return decryptData(encryptedData, key); + } + catch(DecryptionException& ex) { + log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what()); + } + } + + // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm... + const XMLCh* algorithm= + encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL; + if (!algorithm) + throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed."); + + // Check for external resolver. + const EncryptedKey* encKey=NULL; + if (m_EKResolver) + encKey = m_EKResolver->resolveKey(encryptedData, recipient); + else { + EncryptedKeyResolver ekr; + encKey = ekr.resolveKey(encryptedData, recipient); + } + + if (!encKey) + throw DecryptionException("Unable to locate an encrypted key."); + + auto_ptr keywrapper(decryptKey(*encKey, algorithm)); + if (!keywrapper.get()) + throw DecryptionException("Unable to decrypt the encrypted key."); + return decryptData(encryptedData, keywrapper.get()); +} + +XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm) +{ + if (!m_credResolver) + throw DecryptionException("No CredentialResolver supplied to provide decryption keys."); + if (encryptedKey.getDOM()==NULL) throw DecryptionException("The object must be marshalled before decryption."); @@ -139,31 +164,52 @@ XSECCryptoKey* Decrypter::decryptKey(EncryptedKey& encryptedKey, const XMLCh* al if (!m_cipher) m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument()); + // Resolve key decryption key. We can't loop over possible credentials because + // we can't tell a valid decrypt from an invalid one. + const Credential* cred=NULL; + if (m_criteria) { + m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); + m_criteria->setKeyInfo(encryptedKey.getKeyInfo()); + const EncryptionMethod* meth = encryptedKey.getEncryptionMethod(); + if (meth) { + auto_ptr_char alg(meth->getAlgorithm()); + m_criteria->setKeyAlgorithm(alg.get()); + } + cred = m_credResolver->resolve(m_criteria); + } + else { + CredentialCriteria criteria; + criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); + criteria.setKeyInfo(encryptedKey.getKeyInfo()); + const EncryptionMethod* meth = encryptedKey.getEncryptionMethod(); + if (meth) { + auto_ptr_char alg(meth->getAlgorithm()); + criteria.setKeyAlgorithm(alg.get()); + } + cred = m_credResolver->resolve(&criteria); + } + if (!cred || !cred->getPrivateKey()) + throw DecryptionException("Unable to resolve a key decryption key."); + try { - // Resolve key decryption key. - XSECCryptoKey* key=NULL; - if (m_KEKresolver) - key=m_KEKresolver->getKey(encryptedKey.getKeyInfo()); - if (!key) - throw DecryptionException("Unable to resolve a key decryption key."); - m_cipher->setKEK(key); - + m_cipher->setKEK(cred->getPrivateKey()->clone()); XMLByte buffer[1024]; + memset(buffer,0,sizeof(buffer)); int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024); - if (keySize > 0) { - // Try to map the key. - XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm); - if (handler != NULL) - return handler->createKeyForURI(algorithm, buffer, keySize); - throw DecryptionException("Unrecognized algorithm, could not build object around decrypted key."); - } - throw DecryptionException("Unable to decrypt key."); + if (keySize<=0) + throw DecryptionException("Unable to decrypt key."); + + // Try to map the key. + XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm); + if (handler != NULL) + return handler->createKeyForURI(algorithm, buffer, keySize); + throw DecryptionException("Unrecognized algorithm, could not build object around decrypted key."); } catch(XSECException& e) { auto_ptr_char temp(e.getMsg()); - throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get()); + throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get()); } catch(XSECCryptoException& e) { - throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg()); + throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg()); } } diff --git a/xmltooling/encryption/impl/EncryptedKeyResolver.cpp b/xmltooling/encryption/impl/EncryptedKeyResolver.cpp new file mode 100644 index 0000000..5afe82e --- /dev/null +++ b/xmltooling/encryption/impl/EncryptedKeyResolver.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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. + */ + +/** + * EncryptedKeyResolver.cpp + * + * Resolves encrypted keys based on EncryptedData information or other external factors. + */ + +#include "internal.h" +#include "encryption/EncryptedKeyResolver.h" + +using namespace xmlencryption; +using namespace xmlsignature; +using namespace xmltooling; +using namespace std; + +const EncryptedKey* EncryptedKeyResolver::resolveKey(const EncryptedData& encryptedData, const XMLCh* recipient) const +{ + if (!encryptedData.getKeyInfo()) + return NULL; + + const vector& others=const_cast(encryptedData.getKeyInfo())->getUnknownXMLObjects(); + for (vector::const_iterator i=others.begin(); i!=others.end(); i++) { + EncryptedKey* encKey=dynamic_cast(*i); + if (encKey && (!recipient || !encKey->getRecipient() || XMLString::equals(recipient,encKey->getRecipient()))) + return encKey; + } + + return NULL; +} diff --git a/xmltooling/encryption/impl/Encrypter.cpp b/xmltooling/encryption/impl/Encrypter.cpp index 1a5563c..45e9e07 100644 --- a/xmltooling/encryption/impl/Encrypter.cpp +++ b/xmltooling/encryption/impl/Encrypter.cpp @@ -22,6 +22,7 @@ #include "internal.h" #include "encryption/Encrypter.h" +#include "security/Credential.h" #include #include @@ -44,11 +45,11 @@ Encrypter::~Encrypter() void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams) { if (encParams.m_keyBufferSize==0) { - if (encParams.m_key) { + if (encParams.m_credential) { if (kencParams) throw EncryptionException("Generating EncryptedKey inline requires the encryption key in raw form."); } - else if (!encParams.m_key) { + else if (!encParams.m_credential) { if (!kencParams) throw EncryptionException("Using a generated encryption key requires a KeyEncryptionParams object."); @@ -60,20 +61,27 @@ void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* ke } } - if (!encParams.m_key) { + XSECCryptoKey* key=NULL; + if (encParams.m_credential) { + key = encParams.m_credential->getPrivateKey(); + if (!key) + throw EncryptionException("Credential in EncryptionParams structure did not supply a private/secret key."); + // Set the encryption key. + m_cipher->setKey(key->clone()); + } + else { // We have to have a raw key now, so we need to build a wrapper around it. XSECAlgorithmHandler* handler =XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(encParams.m_algorithm); if (handler != NULL) - encParams.m_key = handler->createKeyForURI( + key = handler->createKeyForURI( encParams.m_algorithm,const_cast(encParams.m_keyBuffer),encParams.m_keyBufferSize ); - if (!encParams.m_key) + if (!key) throw EncryptionException("Unable to build wrapper for key, unknown algorithm?"); + // Set the encryption key. + m_cipher->setKey(key); } - - // Set the encryption key. - m_cipher->setKey(encParams.m_key->clone()); } EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams) @@ -151,8 +159,7 @@ EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encPar checkParams(encParams,kencParams); StreamInputSource::StreamBinInputStream xstream(input); m_cipher->encryptBinInputStream(&xstream, ENCRYPT_NONE, encParams.m_algorithm); - EncryptedData* xmlEncData = decorateAndUnmarshall(encParams, kencParams); - return xmlEncData; + return decorateAndUnmarshall(encParams, kencParams); } catch(XSECException& e) { auto_ptr_char temp(e.getMsg()); @@ -179,14 +186,17 @@ EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, Key xmlEncData->releaseThisAndChildrenDOM(); // KeyInfo? - if (encParams.m_keyInfo) { - xmlEncData->setKeyInfo(encParams.m_keyInfo); - encParams.m_keyInfo=NULL; // transfer ownership - } + const KeyInfo* kinfo = encParams.m_credential ? encParams.m_credential->getKeyInfo(encParams.m_compact) : NULL; + if (kinfo) + xmlEncData->setKeyInfo(kinfo->cloneKeyInfo()); // Are we doing a key encryption? if (kencParams) { - m_cipher->setKEK(kencParams->m_key->clone()); + XSECCryptoKey* kek = kencParams->m_credential.getPublicKey(); + if (!kek) + throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key."); + + m_cipher->setKEK(kek->clone()); // ownership of this belongs to us, for some reason... auto_ptr encKey( m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm) @@ -203,12 +213,11 @@ EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, Key xmlEncKey->setRecipient(kencParams->m_recipient); // KeyInfo? - if (kencParams->m_keyInfo) { - xmlEncKey->setKeyInfo(kencParams->m_keyInfo); - kencParams->m_keyInfo=NULL; // transfer ownership - } + kinfo = kencParams->m_credential.getKeyInfo(encParams.m_compact); + if (kinfo) + xmlEncKey->setKeyInfo(kinfo->cloneKeyInfo()); - // Add the EncryptedKey. + // Add the EncryptedKey inline. if (!xmlEncData->getKeyInfo()) xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo()); xmlEncData->getKeyInfo()->getUnknownXMLObjects().push_back(xmlEncKey); @@ -219,7 +228,7 @@ EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, Key return xmlEncData; } -EncryptedKey* Encrypter::encryptKey(const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams) +EncryptedKey* Encrypter::encryptKey(const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact) { // Get a fresh cipher object and document. @@ -227,14 +236,18 @@ EncryptedKey* Encrypter::encryptKey(const unsigned char* keyBuffer, unsigned int XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); m_cipher=NULL; } - + + XSECCryptoKey* kek = kencParams.m_credential.getPublicKey(); + if (!kek) + throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key."); + DOMDocument* doc=NULL; try { doc=XMLToolingConfig::getConfig().getParser().newDocument(); XercesJanitor janitor(doc); m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc); m_cipher->setExclusiveC14nSerialisation(false); - m_cipher->setKEK(kencParams.m_key->clone()); + m_cipher->setKEK(kek->clone()); auto_ptr encKey(m_cipher->encryptKey(keyBuffer, keyBufferSize, ENCRYPT_NONE, kencParams.m_algorithm)); EncryptedKey* xmlEncKey=NULL; @@ -249,10 +262,9 @@ EncryptedKey* Encrypter::encryptKey(const unsigned char* keyBuffer, unsigned int xmlEncKey->setRecipient(kencParams.m_recipient); // KeyInfo? - if (kencParams.m_keyInfo) { - xmlEncKey->setKeyInfo(kencParams.m_keyInfo); - kencParams.m_keyInfo=NULL; // transfer ownership - } + const KeyInfo* kinfo = kencParams.m_credential.getKeyInfo(compact); + if (kinfo) + xmlEncKey->setKeyInfo(kinfo->cloneKeyInfo()); xmlObjectKey.release(); return xmlEncKey; diff --git a/xmltooling/impl/UnknownElement.cpp b/xmltooling/impl/UnknownElement.cpp index bf5ed9c..83ba6b8 100644 --- a/xmltooling/impl/UnknownElement.cpp +++ b/xmltooling/impl/UnknownElement.cpp @@ -34,6 +34,7 @@ using namespace xmltooling; using namespace log4cpp; using namespace std; +using xmlsignature::Signature; void UnknownElementImpl::releaseDOM() const { @@ -73,7 +74,8 @@ void UnknownElementImpl::serialize(string& s) const DOMElement* UnknownElementImpl::marshall( DOMDocument* document #ifndef XMLTOOLING_NO_XMLSEC - ,const std::vector* sigs + ,const vector* sigs + ,const Credential* credential #endif ) const { @@ -140,7 +142,8 @@ DOMElement* UnknownElementImpl::marshall( DOMElement* UnknownElementImpl::marshall( DOMElement* parentElement #ifndef XMLTOOLING_NO_XMLSEC - ,const std::vector* sigs + ,const vector* sigs + ,const Credential* credential #endif ) const { diff --git a/xmltooling/impl/UnknownElement.h b/xmltooling/impl/UnknownElement.h index aa4cd31..e9aee3c 100644 --- a/xmltooling/impl/UnknownElement.h +++ b/xmltooling/impl/UnknownElement.h @@ -61,6 +61,7 @@ namespace xmltooling { DOMDocument* document=NULL #ifndef XMLTOOLING_NO_XMLSEC ,const std::vector* sigs=NULL + ,const Credential* credential=NULL #endif ) const; @@ -68,6 +69,7 @@ namespace xmltooling { DOMElement* parentElement #ifndef XMLTOOLING_NO_XMLSEC ,const std::vector* sigs=NULL + ,const Credential* credential=NULL #endif ) const; XMLObject* unmarshall(DOMElement* element, bool bindDocument=false); diff --git a/xmltooling/io/AbstractXMLObjectMarshaller.cpp b/xmltooling/io/AbstractXMLObjectMarshaller.cpp index 3ef702a..87e0087 100644 --- a/xmltooling/io/AbstractXMLObjectMarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectMarshaller.cpp @@ -24,6 +24,7 @@ #include "exceptions.h" #include "io/AbstractXMLObjectMarshaller.h" #ifndef XMLTOOLING_NO_XMLSEC + #include "security/Credential.h" #include "signature/Signature.h" #endif #include "util/NDC.h" @@ -44,7 +45,8 @@ using namespace std; DOMElement* AbstractXMLObjectMarshaller::marshall( DOMDocument* document #ifndef XMLTOOLING_NO_XMLSEC - ,const std::vector* sigs + ,const vector* sigs + ,const Credential* credential #endif ) const { @@ -91,7 +93,7 @@ DOMElement* AbstractXMLObjectMarshaller::marshall( ); setDocumentElement(document, domElement); #ifndef XMLTOOLING_NO_XMLSEC - marshallInto(domElement, sigs); + marshallInto(domElement, sigs, credential); #else marshallInto(domElement); #endif @@ -107,7 +109,8 @@ DOMElement* AbstractXMLObjectMarshaller::marshall( DOMElement* AbstractXMLObjectMarshaller::marshall( DOMElement* parentElement #ifndef XMLTOOLING_NO_XMLSEC - ,const std::vector* sigs + ,const vector* sigs + ,const Credential* credential #endif ) const { @@ -146,7 +149,7 @@ DOMElement* AbstractXMLObjectMarshaller::marshall( ); parentElement->appendChild(domElement); #ifndef XMLTOOLING_NO_XMLSEC - marshallInto(domElement, sigs); + marshallInto(domElement, sigs, credential); #else marshallInto(domElement); #endif @@ -162,28 +165,45 @@ DOMElement* AbstractXMLObjectMarshaller::marshall( void AbstractXMLObjectMarshaller::marshallInto( DOMElement* targetElement #ifndef XMLTOOLING_NO_XMLSEC - ,const std::vector* sigs + ,const vector* sigs + ,const Credential* credential #endif ) const { if (getElementQName().hasPrefix()) targetElement->setPrefix(getElementQName().getPrefix()); - if (m_schemaLocation) { - static const XMLCh schemaLocation[]= UNICODE_LITERAL_14(s,c,h,e,m,a,L,o,c,a,t,i,o,n); - if (targetElement->getParentNode()==NULL || targetElement->getParentNode()->getNodeType()==DOMNode::DOCUMENT_NODE) - targetElement->setAttributeNS(XSI_NS,schemaLocation,m_schemaLocation); + if (m_schemaLocation || m_noNamespaceSchemaLocation) { + static const XMLCh schemaLocation[] = { + chLatin_x, chLatin_s, chLatin_i, chColon, + chLatin_s, chLatin_c, chLatin_h, chLatin_e, chLatin_m, chLatin_a, + chLatin_L, chLatin_o, chLatin_c, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull + }; + static const XMLCh noNamespaceSchemaLocation[] = { + chLatin_x, chLatin_s, chLatin_i, chColon, + chLatin_n, chLatin_o, chLatin_N, chLatin_a, chLatin_m, chLatin_e, chLatin_s, chLatin_p, chLatin_a, chLatin_c, chLatin_e, + chLatin_S, chLatin_c, chLatin_h, chLatin_e, chLatin_m, chLatin_a, + chLatin_L, chLatin_o, chLatin_c, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull + }; + if (targetElement->getParentNode()==NULL || targetElement->getParentNode()->getNodeType()==DOMNode::DOCUMENT_NODE) { + if (m_schemaLocation) + targetElement->setAttributeNS(XSI_NS,schemaLocation,m_schemaLocation); + if (m_noNamespaceSchemaLocation) + targetElement->setAttributeNS(XSI_NS,noNamespaceSchemaLocation,m_noNamespaceSchemaLocation); + } } marshallElementType(targetElement); marshallNamespaces(targetElement); marshallAttributes(targetElement); - marshallContent(targetElement); #ifndef XMLTOOLING_NO_XMLSEC + marshallContent(targetElement,credential); if (sigs) { - for_each(sigs->begin(),sigs->end(),mem_fun(&Signature::sign)); + for_each(sigs->begin(),sigs->end(),bind2nd(mem_fun1(&Signature::sign),credential)); } +#else + marshallContent(targetElement); #endif } @@ -216,7 +236,7 @@ void AbstractXMLObjectMarshaller::marshallElementType(DOMElement* domElement) co if (xsivalue != typeLocalName) XMLString::release(&xsivalue); - m_log.debug("Adding XSI namespace to list of namespaces used by XMLObject"); + m_log.debug("adding XSI namespace to list of namespaces used by XMLObject"); addNamespace(Namespace(XSI_NS, XSI_PREFIX)); } } @@ -287,7 +307,12 @@ void AbstractXMLObjectMarshaller::marshallNamespaces(DOMElement* domElement) con for_each(namespaces.begin(),namespaces.end(),bind1st(_addns(),domElement)); } -void AbstractXMLObjectMarshaller::marshallContent(DOMElement* domElement) const +void AbstractXMLObjectMarshaller::marshallContent( + DOMElement* domElement +#ifndef XMLTOOLING_NO_XMLSEC + ,const Credential* credential +#endif + ) const { m_log.debug("marshalling text and child elements for XMLObject"); @@ -298,8 +323,13 @@ void AbstractXMLObjectMarshaller::marshallContent(DOMElement* domElement) const val = getTextContent(pos); if (val && *val) domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val)); - if (*i) + if (*i) { +#ifndef XMLTOOLING_NO_XMLSEC + (*i)->marshall(domElement,NULL,credential); +#else (*i)->marshall(domElement); +#endif + } } val = getTextContent(pos); if (val && *val) diff --git a/xmltooling/io/AbstractXMLObjectMarshaller.h b/xmltooling/io/AbstractXMLObjectMarshaller.h index d4c574d..2eaedaf 100644 --- a/xmltooling/io/AbstractXMLObjectMarshaller.h +++ b/xmltooling/io/AbstractXMLObjectMarshaller.h @@ -44,6 +44,7 @@ namespace xmltooling { DOMDocument* document=NULL #ifndef XMLTOOLING_NO_XMLSEC ,const std::vector* sigs=NULL + ,const Credential* credential=NULL #endif ) const; @@ -51,6 +52,7 @@ namespace xmltooling { DOMElement* parentElement #ifndef XMLTOOLING_NO_XMLSEC ,const std::vector* sigs=NULL + ,const Credential* credential=NULL #endif ) const; @@ -79,11 +81,14 @@ namespace xmltooling { * * @param targetElement the Element into which the XMLObject is marshalled into * @param sigs optional array of signatures to create after marshalling + * @param credential optional credential to supply signing key and related info * * @throws MarshallingException thrown if there is a problem marshalling the object * @throws SignatureException thrown if a problem occurs during signature creation */ - void marshallInto(DOMElement* targetElement, const std::vector* sigs) const; + void marshallInto( + DOMElement* targetElement, const std::vector* sigs, const Credential* credential=NULL + ) const; #else /** * Marshalls the XMLObject into the given DOM Element. @@ -113,6 +118,17 @@ namespace xmltooling { */ void marshallNamespaces(DOMElement* domElement) const; +#ifndef XMLTOOLING_NO_XMLSEC + /** + * Marshalls the text content and/or child elements of the XMLObject. + * + * @param domElement the DOM element that will recieved the marshalled children + * @param credential optional credential to supply signing key and related info + * + * @throws MarshallingException thrown if there is a problem marshalling a child element + */ + void marshallContent(DOMElement* domElement, const Credential* credential) const; +#else /** * Marshalls the text content and/or child elements of the XMLObject. * @@ -121,6 +137,7 @@ namespace xmltooling { * @throws MarshallingException thrown if there is a problem marshalling a child element */ void marshallContent(DOMElement* domElement) const; +#endif /** * Marshalls the attributes from the XMLObject into the given DOM element. diff --git a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp index 8a98bbd..75f5e4e 100644 --- a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp +++ b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp @@ -110,6 +110,7 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl else if (XMLString::equals(nsuri,XSI_NS)) { static const XMLCh type[]= UNICODE_LITERAL_4(t,y,p,e); static const XMLCh schemaLocation[]= UNICODE_LITERAL_14(s,c,h,e,m,a,L,o,c,a,t,i,o,n); + static const XMLCh noNamespaceSchemaLocation[]= UNICODE_LITERAL_25(n,o,N,a,m,e,s,p,a,c,e,S,c,h,e,m,a,L,o,c,a,t,i,o,n); if (XMLString::equals(attribute->getLocalName(),type)) { m_log.debug("skipping xsi:type declaration"); continue; @@ -121,6 +122,14 @@ void AbstractXMLObjectUnmarshaller::unmarshallAttributes(const DOMElement* domEl m_schemaLocation=XMLString::replicate(attribute->getValue()); continue; } + else if (XMLString::equals(attribute->getLocalName(),noNamespaceSchemaLocation)) { + m_log.debug("storing off xsi:noNamespaceSchemaLocation attribute"); + if (m_noNamespaceSchemaLocation) + XMLString::release(&m_noNamespaceSchemaLocation); + m_schemaLocation=XMLString::replicate(attribute->getValue()); + m_noNamespaceSchemaLocation=XMLString::replicate(attribute->getValue()); + continue; + } } else if (nsuri && !XMLString::equals(nsuri,XML_NS)) { m_log.debug("found namespace-qualified attribute, adding prefix to the list of namespaces on the XMLObject"); diff --git a/xmltooling/security/AbstractPKIXTrustEngine.h b/xmltooling/security/AbstractPKIXTrustEngine.h index f0a98c5..02f692c 100644 --- a/xmltooling/security/AbstractPKIXTrustEngine.h +++ b/xmltooling/security/AbstractPKIXTrustEngine.h @@ -17,8 +17,8 @@ /** * @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. + * A trust engine that uses X.509 trust anchors and CRLs associated with a peer + * to perform PKIX validation of signatures and credentials. */ #if !defined(__xmltooling_pkixtrust_h__) && !defined(XMLTOOLING_NO_XMLSEC) @@ -30,8 +30,8 @@ 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. + * A trust engine that uses X.509 trust anchors and CRLs associated with a peer + * to perform PKIX validation of signatures and credentials. */ class XMLTOOL_API AbstractPKIXTrustEngine : public OpenSSLTrustEngine { @@ -42,37 +42,34 @@ namespace xmltooling { * If a DOM is supplied, the following XML content is supported: * *

    - *
  • <KeyResolver> elements with a type attribute + *
  • <KeyInfoResolver> elements with a type attribute *
* * XML namespaces are ignored in the processing of this content. * * @param e DOM to supply configuration for provider */ - AbstractPKIXTrustEngine(const DOMElement* e=NULL); + AbstractPKIXTrustEngine(const DOMElement* e=NULL) : OpenSSLTrustEngine(e) {} /** - * 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. + * Checks that either the name of the peer with the given credentials or the names + * of the credentials match the subject or subject alternate names of the certificate. * * @param certEE the credential for the entity to validate - * @param keyInfoSource supplies KeyInfo objects to the TrustEngine + * @param credResolver source of credentials + * @param criteria criteria for selecting credentials, including the peer name * * @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. */ - KeyResolver* m_inlineResolver; + bool checkEntityNames(X509* certEE, const CredentialResolver& credResolver, const CredentialCriteria& criteria) const; public: - virtual ~AbstractPKIXTrustEngine(); + virtual ~AbstractPKIXTrustEngine() {} virtual bool validate( xmlsignature::Signature& sig, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; virtual bool validate( @@ -81,24 +78,22 @@ namespace xmltooling { xmlsignature::KeyInfo* keyInfo, const char* in, unsigned int in_len, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; virtual bool validate( XSECCryptoX509* certEE, const std::vector& certChain, - const KeyInfoSource& keyInfoSource, - bool checkName=true, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; virtual bool validate( X509* certEE, STACK_OF(X509)* certChain, - const KeyInfoSource& keyInfoSource, - bool checkName=true, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; /** @@ -110,15 +105,7 @@ namespace xmltooling { class XMLTOOL_API PKIXValidationInfoIterator { MAKE_NONCOPYABLE(PKIXValidationInfoIterator); protected: - /** Reference to KeyResolver to use. */ - const KeyResolver& m_keyResolver; - - /** - * Constructor - * - * @param keyResolver reference to KeyResolver to use - */ - PKIXValidationInfoIterator(const KeyResolver& keyResolver) : m_keyResolver(keyResolver) {} + PKIXValidationInfoIterator() {} public: virtual ~PKIXValidationInfoIterator() {} @@ -160,18 +147,20 @@ namespace xmltooling { }; /** - * Provides access to the information necessary, for the given key source, for + * Provides access to the information necessary, for the given credential 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. * - * @param pkixSource the peer for which validation rules are required - * @param keyResolver reference to KeyResolver to use for any KeyInfo operations + * @param pkixSource the peer for which validation rules are required + * @param criteria criteria for selecting validation rules + * @param keyInfoResolver custom KeyInfoResolver to use for KeyInfo extraction * @return interface for obtaining validation data */ virtual PKIXValidationInfoIterator* getPKIXValidationInfoIterator( - const KeyInfoSource& pkixSource, - const KeyResolver& keyResolver + const CredentialResolver& pkixSource, + CredentialCriteria* criteria=NULL, + const KeyInfoResolver* keyInfoResolver=NULL ) const=0; }; }; diff --git a/xmltooling/security/BasicX509Credential.h b/xmltooling/security/BasicX509Credential.h new file mode 100644 index 0000000..6225f69 --- /dev/null +++ b/xmltooling/security/BasicX509Credential.h @@ -0,0 +1,122 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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/BasicX509Credential.h + * + * Wraps an X.509-based Credential by storing key/cert objects inside. + */ + +#if !defined(__xmltooling_basicx509cred_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#define __xmltooling_basicx509cred_h__ + +#include + +#include + +namespace xmlsignature { + class XMLTOOL_API KeyInfo; +}; + +namespace xmltooling { + + /** + * Wraps an X.509-based Credential by storing key/cert objects inside. + */ + class XMLTOOL_API BasicX509Credential : public virtual X509Credential + { + protected: + BasicX509Credential(bool ownCerts) : m_key(NULL), m_ownCerts(ownCerts), m_crl(NULL), m_keyInfo(NULL), m_compactKeyInfo(NULL) { + } + + /** + * Constructor. + * + * @param key key pair or secret key + * @param certs array of X.509 certificates, the first entry being the entity certificate + * @param crl optional CRL + */ + BasicX509Credential(XSECCryptoKey* key, const std::vector& certs, XSECCryptoX509CRL* crl=NULL) + : m_key(key), m_xseccerts(certs), m_ownCerts(true), m_crl(crl), m_keyInfo(NULL), m_compactKeyInfo(NULL) { + } + + /** The private/secret key/keypair. */ + XSECCryptoKey* m_key; + + /** The X.509 certificate chain. */ + std::vector m_xseccerts; + + /** Indicates whether to destroy certificates. */ + bool m_ownCerts; + + /** The X.509 CRL. */ + XSECCryptoX509CRL* m_crl; + + /** The KeyInfo object representing the information. */ + xmlsignature::KeyInfo* m_keyInfo; + + /** The KeyInfo object representing the information in compact form. */ + xmlsignature::KeyInfo* m_compactKeyInfo; + + /** + * Initializes (or reinitializes) a ds:KeyInfo to represent the Credential. + */ + void initKeyInfo(); + + public: + virtual ~BasicX509Credential(); + + XSECCryptoKey* getPrivateKey() const { + if (m_key) { + XSECCryptoKey::KeyType type = m_key->getKeyType(); + if (type!=XSECCryptoKey::KEY_RSA_PUBLIC && type!=XSECCryptoKey::KEY_DSA_PUBLIC) + return m_key; + } + return NULL; + } + + XSECCryptoKey* getPublicKey() const { + if (m_key) { + XSECCryptoKey::KeyType type = m_key->getKeyType(); + if (type!=XSECCryptoKey::KEY_RSA_PRIVATE && type!=XSECCryptoKey::KEY_DSA_PRIVATE) + return m_key; + } + return NULL; + } + + std::vector::size_type getKeyNames(std::vector& results) const; + + const xmlsignature::KeyInfo* getKeyInfo(bool compact=false) const { + return compact ? m_compactKeyInfo : (m_keyInfo ? m_keyInfo : m_compactKeyInfo); + } + + /** + * Gets an immutable collection of certificates in the entity's trust chain. The entity certificate is contained + * within this list. No specific ordering of the certificates is guaranteed. + * + * @return a certificate chain + */ + const std::vector& getEntityCertificateChain() const { + return m_xseccerts; + } + + XSECCryptoX509CRL* getCRL() const { + return m_crl; + } + }; +}; + +#endif /* __xmltooling_basicx509cred_h__ */ diff --git a/xmltooling/security/CachingKeyResolver.h b/xmltooling/security/CachingKeyResolver.h deleted file mode 100644 index fe30bc7..0000000 --- a/xmltooling/security/CachingKeyResolver.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2001-2007 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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/CachingKeyResolver.h - * - * A KeyResolver that caches content across method calls. - */ - -#if !defined(__xmltooling_cachekeyres_h__) && !defined(XMLTOOLING_NO_XMLSEC) -#define __xmltooling_cachekeyres_h__ - -#include - -namespace xmltooling { - - /** - * An API for resolving encrypted decryption keys. - */ - class XMLTOOL_API CachingKeyResolver : public KeyResolver { - public: - virtual ~CachingKeyResolver() {} - - /** - * Clears any cache state. - */ - virtual void clearCache()=0; - }; - -}; - -#endif /* __xmltooling_cachekeyres_h__ */ diff --git a/xmltooling/security/ChainingTrustEngine.h b/xmltooling/security/ChainingTrustEngine.h index d273c1e..65f972b 100644 --- a/xmltooling/security/ChainingTrustEngine.h +++ b/xmltooling/security/ChainingTrustEngine.h @@ -79,8 +79,8 @@ namespace xmltooling { bool validate( xmlsignature::Signature& sig, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; bool validate( const XMLCh* sigAlgorithm, @@ -88,22 +88,20 @@ namespace xmltooling { xmlsignature::KeyInfo* keyInfo, const char* in, unsigned int in_len, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; bool validate( XSECCryptoX509* certEE, const std::vector& certChain, - const KeyInfoSource& keyInfoSource, - bool checkName=true, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; bool validate( X509* certEE, STACK_OF(X509)* certChain, - const KeyInfoSource& keyInfoSource, - bool checkName=true, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; private: std::vector m_engines; diff --git a/xmltooling/security/Credential.h b/xmltooling/security/Credential.h new file mode 100644 index 0000000..c8d7756 --- /dev/null +++ b/xmltooling/security/Credential.h @@ -0,0 +1,97 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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/Credential.h + * + * Wraps keys and related functionality. + */ + +#if !defined(__xmltooling_cred_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#define __xmltooling_cred_h__ + +#include + +#include + +namespace xmlsignature { + class XMLTOOL_API KeyInfo; +}; + +namespace xmltooling { + + /** + * Wraps keys and related functionality. + * + *

Shared credential implementations should implement reference counting + * and honor any locking parameters to ensure appropriate synchronization. + */ + class XMLTOOL_API Credential + { + MAKE_NONCOPYABLE(Credential); + protected: + Credential() {} + + public: + virtual ~Credential() {} + + enum ResolveTypes { + RESOLVE_KEYS = 1 + }; + + /** + * Returns a secret or private key to use for signing or decryption operations. + * + * @return a secret or private key + */ + virtual XSECCryptoKey* getPrivateKey() const=0; + + /** + * Returns a secret or public key to use for verification or encryption operations. + * + * @return a secret or public key + */ + virtual XSECCryptoKey* getPublicKey() const=0; + + /** + * Returns names representing the Credential, generally when the Credential itself merely + * points to a Credential rather than containing one. + * + * @param results array to populate with names + * @return the number of names returned + */ + virtual std::vector::size_type getKeyNames(std::vector& results) const=0; + + /** + * Returns a ds:KeyInfo object representing the Credential for use in + * communicating with other entities. + * + * @param compact true iff the communication medium is such that only compact forms should be included + * @return reference to a KeyInfo object + */ + virtual const xmlsignature::KeyInfo* getKeyInfo(bool compact=false) const=0; + + /** + * Compares the public key inside the Credential to a second public key. + * + * @param key the public key to compare + * @return true iff the keys are equal + */ + virtual bool isEqual(XSECCryptoKey& key) const; + }; +}; + +#endif /* __xmltooling_cred_h__ */ diff --git a/xmltooling/security/CredentialCriteria.h b/xmltooling/security/CredentialCriteria.h new file mode 100644 index 0000000..6777bd4 --- /dev/null +++ b/xmltooling/security/CredentialCriteria.h @@ -0,0 +1,184 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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/CredentialCriteria.h + * + * Class for specifying criteria by which a CredentialResolver should resolve credentials. + */ + +#if !defined(__xmltooling_credcrit_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#define __xmltooling_credcrit_h__ + +#include +#include +#include + +#include +#include +#include + +namespace xmltooling { + + /** + * Class for specifying criteria by which a CredentialResolver should resolve credentials. + */ + class XMLTOOL_API CredentialCriteria + { + MAKE_NONCOPYABLE(CredentialCriteria); + public: + CredentialCriteria() : m_keyUsage(UNSPECIFIED_CREDENTIAL), m_keyInfo(NULL), m_nativeKeyInfo(NULL) {} + virtual ~CredentialCriteria() {} + + enum UsageType { + UNSPECIFIED_CREDENTIAL, + SIGNING_CREDENTIAL, + TLS_CREDENTIAL, + ENCRYPTION_CREDENTIAL + }; + + /** + * Get the key usage criteria. + * + * @return the usage. + */ + UsageType getUsage() const { + return m_keyUsage; + } + + /** + * Set the key usage criteria. + * + * @param usage the usage to set + */ + void setUsage(UsageType usage) { + m_keyUsage = usage; + } + + /** + * Get the peer name criteria. + * + * @return the peer name + */ + const char* getPeerName() const { + return m_peerName.c_str(); + } + + /** + * Set the peer name criteria. + * + * @param peerName peer name to set + */ + void setPeerName(const char* peerName) { + m_peerName.erase(); + if (peerName) + m_peerName = peerName; + } + + /** + * Get the key algorithm criteria. + * + * @return returns the keyAlgorithm. + */ + const char* getKeyAlgorithm() const { + return m_keyAlgorithm.c_str(); + } + + /** + * Set the key algorithm criteria. + * + * @param keyAlgorithm The keyAlgorithm to set. + */ + void setKeyAlgorithm(const char* keyAlgorithm) { + m_keyAlgorithm.erase(); + if (keyAlgorithm) + m_keyAlgorithm = keyAlgorithm; + } + + /** + * Get the key name criteria. + * + * @return the key name + */ + const char* getKeyName() const { + return m_keyName.c_str(); + } + + /** + * Set the key name criteria. + * + * @param keyName key name to set + */ + void setKeyName(const char* keyName) { + m_keyName.erase(); + if (keyName) + m_keyName = keyName; + } + + /** + * Gets the KeyInfo criteria. + * + * @return the KeyInfo criteria + */ + const xmlsignature::KeyInfo* getKeyInfo() const { + return m_keyInfo; + } + + /** + * Sets the KeyInfo criteria. + * + * @param keyInfo the KeyInfo criteria + */ + void setKeyInfo(const xmlsignature::KeyInfo* keyInfo) { + m_keyInfo = keyInfo; + } + + /** + * Gets the native KeyInfo criteria. + * + * @return the native KeyInfo criteria + */ + DSIGKeyInfoList* getNativeKeyInfo() const { + return m_nativeKeyInfo; + } + + /** + * Sets the KeyInfo criteria. + * + * @param keyInfo the KeyInfo criteria + */ + void setNativeKeyInfo(DSIGKeyInfoList* keyInfo) { + m_nativeKeyInfo = keyInfo; + } + + void setSignature(const xmlsignature::Signature& sig) { + xmlsignature::KeyInfo* k = sig.getKeyInfo(); + if (k) + return setKeyInfo(k); + DSIGSignature* dsig = sig.getXMLSignature(); + if (dsig) + setNativeKeyInfo(dsig->getKeyInfoList()); + } + + private: + UsageType m_keyUsage; + std::string m_peerName,m_keyAlgorithm,m_keyName; + const xmlsignature::KeyInfo* m_keyInfo; + DSIGKeyInfoList* m_nativeKeyInfo; + }; +}; + +#endif /* __xmltooling_credcrit_h__ */ diff --git a/xmltooling/security/CredentialResolver.h b/xmltooling/security/CredentialResolver.h index a9324ee..68d675f 100644 --- a/xmltooling/security/CredentialResolver.h +++ b/xmltooling/security/CredentialResolver.h @@ -15,9 +15,9 @@ */ /** - * @file xmltooling/signature/CredentialResolver.h + * @file xmltooling/security/CredentialResolver.h * - * Resolves keys and certificates "owned" by an entity + * An API for resolving keys and certificates based on application criteria. */ #if !defined(__xmltooling_credres_h__) && !defined(XMLTOOLING_NO_XMLSEC) @@ -25,20 +25,15 @@ #include -#include -#include -#include - -namespace xmlsignature { - class XMLTOOL_API KeyInfo; -}; - namespace xmltooling { + class XMLTOOL_API Credential; + class XMLTOOL_API CredentialCriteria; + /** - * An API for resolving local/owned keys and certificates + * An API for resolving keys and certificates based on application criteria. */ - class XMLTOOL_API CredentialResolver : public Lockable + class XMLTOOL_API CredentialResolver : public virtual Lockable { MAKE_NONCOPYABLE(CredentialResolver); protected: @@ -48,21 +43,23 @@ namespace xmltooling { virtual ~CredentialResolver() {} /** - * Returns a secret or private key to use for signing or decryption operations. - * The caller is responsible for deleting the key when finished with it. + * Returns a single Credential according to the supplied criteria. * - * @param keyInfo optional material identifying a decryption key - * @return a secret or private key + * @param criteria an optional CredentialCriteria object + * @return a Credential, or NULL if none could be found */ - virtual XSECCryptoKey* getKey(const xmlsignature::KeyInfo* keyInfo=NULL) const=0; - + virtual const Credential* resolve(const CredentialCriteria* criteria=NULL) const=0; + /** - * Returns a set of certificates to publish during signing operations. - * The certificates must be cloned if kept beyond the scope of a lock. + * Returns all matching Credentials according to the supplied criteria. * - * @return a set of certificates + * @param results array to store matching Credentials + * @param criteria an optional CredentialCriteria object + * @return number of credentials found */ - virtual const std::vector& getCertificates() const=0; + virtual std::vector::size_type resolve( + std::vector& results, const CredentialCriteria* criteria=NULL + ) const=0; }; /** @@ -70,7 +67,7 @@ namespace xmltooling { */ void XMLTOOL_API registerCredentialResolvers(); - /** CredentialResolver based on local files */ + /** CredentialResolver based on local files with no criteria support. */ #define FILESYSTEM_CREDENTIAL_RESOLVER "File" }; diff --git a/xmltooling/security/KeyInfoResolver.h b/xmltooling/security/KeyInfoResolver.h new file mode 100644 index 0000000..61c5bf2 --- /dev/null +++ b/xmltooling/security/KeyInfoResolver.h @@ -0,0 +1,100 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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/KeyInfoResolver.h + * + * Resolves credentials from KeyInfo information. + */ + +#if !defined(__xmltooling_keyres_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#define __xmltooling_keyres_h__ + +#include + +namespace xmlsignature { + class XMLTOOL_API KeyInfo; + class XMLTOOL_API Signature; +}; + +namespace xmltooling { + + class XMLTOOL_API Credential; + class XMLTOOL_API CredentialCriteria; + + /** + * Resolves credentials from KeyInfo information. + * + *

Credential-specific bitmasks can be provided to control what to resolve. + */ + class XMLTOOL_API KeyInfoResolver { + MAKE_NONCOPYABLE(KeyInfoResolver); + protected: + KeyInfoResolver() {} + public: + virtual ~KeyInfoResolver() {} + + /** + * Returns a credential based on the supplied KeyInfo information. + * The caller must release the credential when done with it. + * + * @param keyInfo the key information + * @param types types of credentials to resolve, or 0 for any/all + * @return the resolved credential, or NULL + */ + virtual Credential* resolve(const xmlsignature::KeyInfo* keyInfo, int types=0) const=0; + + /** + * Returns a credential based on the supplied KeyInfo information. + * The caller must release the credential when done with it. + * + * @param keyInfo the key information + * @param types types of credentials to resolve, or 0 for any/all + * @return the resolved credential, or NULL + */ + virtual Credential* resolve(DSIGKeyInfoList* keyInfo, int types=0) const=0; + + /** + * Returns a credential based on the supplied KeyInfo information. + * The caller must release the credential when done with it. + * + * @param sig signature containing the key information + * @param types types of credentials to resolve, or 0 for any/all + * @return the resolved credential, or NULL + */ + Credential* resolve(const xmlsignature::Signature* sig, int types=0) const; + + /** + * Returns a credential based on the KeyInfo information in the supplied + * criteria. The caller must release the credential when done with it. + * + * @param criteria criteria containing the key information + * @param types types of credentials to resolve, or 0 for any/all + * @return the resolved credential, or NULL + */ + Credential* resolve(const CredentialCriteria& criteria, int types=0) const; + }; + + /** + * Registers KeyInfoResolver classes into the runtime. + */ + void XMLTOOL_API registerKeyInfoResolvers(); + + /** KeyInfoResolver based on extracting by value directly out of a KeyInfo */ + #define INLINE_KEYINFO_RESOLVER "Inline" +}; + +#endif /* __xmltooling_keyres_h__ */ diff --git a/xmltooling/security/KeyInfoSource.h b/xmltooling/security/KeyInfoSource.h deleted file mode 100644 index dc4ab0e..0000000 --- a/xmltooling/security/KeyInfoSource.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2001-2007 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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 -#include - -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__ */ diff --git a/xmltooling/security/KeyResolver.h b/xmltooling/security/KeyResolver.h deleted file mode 100644 index 6d7762c..0000000 --- a/xmltooling/security/KeyResolver.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright 2001-2007 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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/KeyResolver.h - * - * Resolves public keys and certificates based on KeyInfo information or - * external factors. - */ - -#if !defined(__xmltooling_keyres_h__) && !defined(XMLTOOLING_NO_XMLSEC) -#define __xmltooling_keyres_h__ - -#include - -#include -#include -#include - -#include -#include - -namespace xmlsignature { - class XMLTOOL_API KeyInfo; - class XMLTOOL_API Signature; -}; - -namespace xmltooling { - - /** - * An API for resolving keys. The default/simple implementation - * allows a hard-wired key to be supplied. This is mostly - * useful for testing, or to adapt another mechanism for supplying - * keys to this interface. - */ - class XMLTOOL_API KeyResolver { - MAKE_NONCOPYABLE(KeyResolver); - public: - /** - * Constructor based on a single externally supplied key. - * The key will be destroyed when the resolver is. - * - * @param key external key - */ - KeyResolver(XSECCryptoKey* key=NULL) : m_key(key) {} - - virtual ~KeyResolver() { - delete m_key; - } - - /** - * Returns a key based on the supplied KeyInfo information. - * The caller must delete the key when done with it. - * - * @param keyInfo the key information - * @return the resolved key - */ - virtual XSECCryptoKey* resolveKey(const xmlsignature::KeyInfo* keyInfo) const { - return m_key ? m_key->clone() : NULL; - } - - /** - * Returns a key based on the supplied KeyInfo information. - * The caller must delete the key when done with it. - * - * @param keyInfo the key information - * @return the resolved key - */ - virtual XSECCryptoKey* resolveKey(DSIGKeyInfoList* keyInfo) const { - return m_key ? m_key->clone() : NULL; - } - - /** - * Returns a key based on the supplied KeyInfo information. - * The caller must delete the key when done with it. - * - * @param sig signature containing the key information - * @return the resolved key - */ - XSECCryptoKey* resolveKey(const xmlsignature::Signature* sig) const; - - /** - * A wrapper that handles disposal of certificates when required. - */ - class XMLTOOL_API ResolvedCertificates { - MAKE_NONCOPYABLE(ResolvedCertificates); - bool m_owned; - std::vector m_certs; - public: - ResolvedCertificates() : m_owned(false) {} - - ~ResolvedCertificates() { - clear(); - } - - /** - * Empties the container and frees any held resources. - */ - void clear() { - if (m_owned) { - std::for_each(m_certs.begin(), m_certs.end(), xmltooling::cleanup()); - m_owned = false; - } - m_certs.clear(); - } - - /** - * Transfers ownership of certificates outside wrapper. - * - * @param writeTo a container into which to move the certificates - * @return true iff the certificates must be freed by caller - */ - bool release(std::vector& writeTo) { - writeTo.assign(m_certs.begin(),m_certs.end()); - m_certs.clear(); - if (m_owned) { - m_owned=false; - return true; - } - return false; - } - - /** - * Accesses the underlying array of certificates. - * - * @return reference to certificate container - */ - const std::vector& v() const { - return m_certs; - } - - friend class XMLTOOL_API KeyResolver; - }; - - /** - * Returns a set of certificates based on the supplied KeyInfo information. - * The certificates must be cloned if kept beyond the lifetime of the KeyInfo source. - * - * @param keyInfo the key information - * @param certs reference to object to hold certificates - * @return number of certificates returned - */ - virtual std::vector::size_type resolveCertificates( - const xmlsignature::KeyInfo* keyInfo, ResolvedCertificates& certs - ) const; - - /** - * Returns a set of certificates based on the supplied KeyInfo information. - * The certificates must be cloned if kept beyond the lifetime of the KeyInfo source. - * - * @param keyInfo the key information - * @param certs reference to object to hold certificates - * @return number of certificates returned - */ - virtual std::vector::size_type resolveCertificates( - DSIGKeyInfoList* keyInfo, ResolvedCertificates& certs - ) const; - - /** - * Returns a set of certificates based on the supplied KeyInfo information. - * The certificates must be cloned if kept beyond the lifetime of the KeyInfo source. - * - * @param sig signature containing the key information - * @param certs reference to object to hold certificates - * @return number of certificates returned - */ - std::vector::size_type resolveCertificates( - const xmlsignature::Signature* sig, ResolvedCertificates& certs - ) const; - - /** - * Returns a CRL based on the supplied KeyInfo information. - * The caller must delete the CRL when done with it. - * - * @param keyInfo the key information - * @return the resolved CRL - */ - virtual XSECCryptoX509CRL* resolveCRL(const xmlsignature::KeyInfo* keyInfo) const; - - /** - * Returns a CRL based on the supplied KeyInfo information. - * The caller must delete the CRL when done with it. - * - * @param keyInfo the key information - * @return the resolved CRL - */ - virtual XSECCryptoX509CRL* resolveCRL(DSIGKeyInfoList* keyInfo) const; - - /** - * Returns a CRL based on the supplied KeyInfo information. - * The caller must delete the CRL when done with it. - * - * @param sig signature containing the key information - * @return the resolved CRL - */ - XSECCryptoX509CRL* resolveCRL(const xmlsignature::Signature* sig) const; - - protected: - /** Stores an explicit key. */ - XSECCryptoKey* m_key; - - /** - * Accessor for certificate vector from derived KeyResolver classes. - * - * @param certs certificate wrapper to access - * @return modifiable reference to vector inside wrapper - */ - std::vector& accessCertificates(ResolvedCertificates& certs) const { - return certs.m_certs; - } - - /** - * Accessor for certificate ownership flag from derived KeyResolver classes. - * - * @param certs certificate wrapper to access - * @return modifiable reference to ownership flag inside wrapper - */ - bool& accessOwned(ResolvedCertificates& certs) const { - return certs.m_owned; - } - }; - - /** - * Registers KeyResolver classes into the runtime. - */ - void XMLTOOL_API registerKeyResolvers(); - - /** KeyResolver based on hard-wired key */ - #define FILESYSTEM_KEY_RESOLVER "File" - - /** KeyResolver based on extracting information directly out of a KeyInfo */ - #define INLINE_KEY_RESOLVER "Inline" -}; - -#endif /* __xmltooling_keyres_h__ */ diff --git a/xmltooling/security/OpenSSLCredentialResolver.h b/xmltooling/security/OpenSSLCredential.h similarity index 55% rename from xmltooling/security/OpenSSLCredentialResolver.h rename to xmltooling/security/OpenSSLCredential.h index 7e9ace5..73915dc 100644 --- a/xmltooling/security/OpenSSLCredentialResolver.h +++ b/xmltooling/security/OpenSSLCredential.h @@ -15,34 +15,34 @@ */ /** - * @file xmltooling/security/OpenSSLCredentialResolver.h + * @file xmltooling/security/OpenSSLCredential.h * - * OpenSSL-specific credential resolver + * OpenSSL-specific credential */ -#if !defined(__xmltooling_opensslcredres_h__) && !defined(XMLTOOLING_NO_XMLSEC) -#define __xmltooling_opensslcredres_h__ +#if !defined(__xmltooling_opensslcred_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#define __xmltooling_opensslcred_h__ -#include +#include #include namespace xmltooling { /** - * An OpenSSL-specific API for resolving local/owned keys and certificates + * An OpenSSL-specific credential */ - class XMLTOOL_API OpenSSLCredentialResolver : public CredentialResolver + class XMLTOOL_API OpenSSLCredential : public virtual X509Credential { protected: - OpenSSLCredentialResolver() {} + OpenSSLCredential() {} public: - virtual ~OpenSSLCredentialResolver() {} + virtual ~OpenSSLCredential() {} /** - * Attaches credentials to an OpenSSL SSL context object. - * The resolver MUST be unlockable after attachment. + * Attaches credential to an OpenSSL SSL context object. + * The credential MUST be disposable after attachment. * * @param ctx an SSL context */ @@ -51,4 +51,4 @@ namespace xmltooling { }; -#endif /* __xmltooling_opensslcredres_h__ */ +#endif /* __xmltooling_opensslcred_h__ */ diff --git a/xmltooling/security/OpenSSLTrustEngine.h b/xmltooling/security/OpenSSLTrustEngine.h index b343449..a44cd56 100644 --- a/xmltooling/security/OpenSSLTrustEngine.h +++ b/xmltooling/security/OpenSSLTrustEngine.h @@ -42,7 +42,7 @@ namespace xmltooling { * If a DOM is supplied, the following XML content is supported: * *

    - *
  • <KeyResolver> elements with a type attribute + *
  • <KeyInfoResolver> elements with a type attribute *
* * XML namespaces are ignored in the processing of this content. @@ -56,26 +56,26 @@ namespace xmltooling { /** * 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. + * source of credentials supplied. * - * 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. + *

It is the responsibility of the application to ensure that the credentials + * supplied are in fact associated with the peer who presented the credential. + * + *

If criteria with a peer name are supplied, the "name" of the EE certificate + * may also be checked to ensure that it identifies the intended peer. + * The peer name itself or implementation-specific rules based on the content of the + * peer credentials may be applied. Implementations may omit this check if they + * deem it unnecessary. * * @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 NOT already occurred - * @param keyResolver optional externally supplied KeyResolver, or NULL + * @param certChain the complete set of certificates presented for validation (includes certEE) + * @param credResolver a locked resolver to supply trusted peer credentials to the TrustEngine + * @param criteria criteria for selecting peer credentials */ virtual bool validate( - X509* certEE, - STACK_OF(X509)* certChain, - const KeyInfoSource& keyInfoSource, - bool checkName=true, - const KeyResolver* keyResolver=NULL + X509* certEE, STACK_OF(X509)* certChain, + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const=0; }; diff --git a/xmltooling/security/TrustEngine.h b/xmltooling/security/TrustEngine.h index 35382b5..cf4c257 100644 --- a/xmltooling/security/TrustEngine.h +++ b/xmltooling/security/TrustEngine.h @@ -17,19 +17,26 @@ /** * @file xmltooling/security/TrustEngine.h * - * Evaluates the trustworthiness and validity of XML Signatures against + * Evaluates the trustworthiness and validity of signatures against * implementation-specific requirements. */ #if !defined(__xmltooling_trust_h__) && !defined(XMLTOOLING_NO_XMLSEC) #define __xmltooling_trust_h__ -#include -#include -#include +#include + +namespace xmlsignature { + class XMLTOOL_API KeyInfo; + class XMLTOOL_API Signature; +}; namespace xmltooling { + class XMLTOOL_API CredentialCriteria; + class XMLTOOL_API CredentialResolver; + class XMLTOOL_API KeyInfoResolver; + /** * Evaluates the trustworthiness and validity of XML or raw Signatures against * implementation-specific requirements. @@ -43,7 +50,7 @@ namespace xmltooling { * If a DOM is supplied, the following XML content is supported: * *

    - *
  • <KeyResolver> elements with a type attribute + *
  • <KeyInfoResolver> elements with a type attribute *
* * XML namespaces are ignored in the processing of this content. @@ -52,45 +59,60 @@ namespace xmltooling { */ TrustEngine(const DOMElement* e=NULL); - /** Default KeyResolver instance. */ - KeyResolver* m_keyResolver; + /** Custom KeyInfoResolver instance. */ + KeyInfoResolver* m_keyInfoResolver; public: virtual ~TrustEngine(); - + + /** + * Supplies a KeyInfoResolver instance. + *

This method must be externally synchronized with any code that uses the object. + * Any previously set object is destroyed. + * + * @param keyInfoResolver new KeyInfoResolver instance to use + */ + void setKeyInfoResolver(KeyInfoResolver* keyInfoResolver); + /** * Determines whether an XML signature is correct and 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 created the signature. + * the source of credentials supplied. + * + *

It is the responsibility of the application to ensure that the credentials + * supplied are 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. + *

If criteria with a peer name are supplied, the "name" of the Credential that verifies + * the signature may also be checked to ensure that it identifies the intended peer. + * The peer name itself or implementation-specific rules based on the content of the + * peer credentials may be applied. Implementations may omit this check if they + * deem it unnecessary. * * @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 + * @param credResolver a locked resolver to supply trusted peer credentials to the TrustEngine + * @param criteria criteria for selecting peer credentials * @return true iff the signature validates */ virtual bool validate( xmlsignature::Signature& sig, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const=0; /** * Determines whether a raw signature is correct and 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 created the signature. + * the source of credentials supplied. * - *

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. + *

It is the responsibility of the application to ensure that the Credentials + * supplied are in fact associated with the peer who created the signature. * + *

If criteria with a peer name are supplied, the "name" of the Credential that verifies + * the signature may also be checked to ensure that it identifies the intended peer. + * The peer name itself or implementation-specific rules based on the content of the + * peer credentials may be applied. Implementations may omit this check if they + * deem it unnecessary. + * *

Note that the keyInfo parameter is not part of the implicitly trusted - * set of key information supplied via the KeyInfoSource, but rather advisory + * set of information supplied via the CredentialResolver, but rather advisory * data that may have accompanied the signature itself. * * @param sigAlgorithm XML Signature identifier for the algorithm used @@ -98,8 +120,8 @@ namespace xmltooling { * @param keyInfo KeyInfo object accompanying the signature, if any * @param in the input data over which the signature was created * @param in_len size of input data in bytes - * @param keyInfoSource supplies KeyInfo objects to the TrustEngine - * @param keyResolver optional externally supplied KeyResolver, or NULL + * @param credResolver a locked resolver to supply trusted peer credentials to the TrustEngine + * @param criteria criteria for selecting peer credentials * @return true iff the signature validates */ virtual bool validate( @@ -108,8 +130,8 @@ namespace xmltooling { xmlsignature::KeyInfo* keyInfo, const char* in, unsigned int in_len, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const=0; }; diff --git a/xmltooling/security/X509Credential.h b/xmltooling/security/X509Credential.h new file mode 100644 index 0000000..764d82f --- /dev/null +++ b/xmltooling/security/X509Credential.h @@ -0,0 +1,67 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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/X509Credential.h + * + * Wraps an X.509-based Credential. + */ + +#if !defined(__xmltooling_x509cred_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#define __xmltooling_x509cred_h__ + +#include +#include + +#include +#include + +namespace xmltooling { + + /** + * Wraps an X.509-based Credential. + */ + class XMLTOOL_API X509Credential : public virtual Credential + { + protected: + X509Credential() {} + + public: + virtual ~X509Credential() {} + + enum ResolveTypes { + RESOLVE_CERTS = 2, + RESOLVE_CRLS = 4 + }; + + /** + * Gets an immutable collection of certificates in the entity's trust chain. The entity certificate is contained + * within this list. No specific ordering of the certificates is guaranteed. + * + * @return a certificate chain + */ + virtual const std::vector& getEntityCertificateChain() const=0; + + /** + * Gets a CRL associated with the credential. + * + * @return CRL associated with the credential + */ + virtual XSECCryptoX509CRL* getCRL() const=0; + }; +}; + +#endif /* __xmltooling_x509cred_h__ */ diff --git a/xmltooling/security/X509TrustEngine.h b/xmltooling/security/X509TrustEngine.h index 6387baf..097e630 100644 --- a/xmltooling/security/X509TrustEngine.h +++ b/xmltooling/security/X509TrustEngine.h @@ -38,7 +38,7 @@ namespace xmltooling { * If a DOM is supplied, the following XML content is supported: * *

    - *
  • <KeyResolver> elements with a type attribute + *
  • <KeyInfoResolver> elements with a type attribute *
* * XML namespaces are ignored in the processing of this content. @@ -52,26 +52,27 @@ namespace xmltooling { /** * 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. + * source of credentials supplied. * - * 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. + *

It is the responsibility of the application to ensure that the credentials + * supplied are in fact associated with the peer who presented the credential. + * + *

If criteria with a peer name are supplied, the "name" of the EE certificate + * may also be checked to ensure that it identifies the intended peer. + * The peer name itself or implementation-specific rules based on the content of the + * peer credentials may be applied. Implementations may omit this check if they + * deem it unnecessary. * * @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 + * @param credResolver a locked resolver to supply trusted peer credentials to the TrustEngine + * @param criteria criteria for selecting peer credentials */ virtual bool validate( XSECCryptoX509* certEE, const std::vector& certChain, - const KeyInfoSource& keyInfoSource, - bool checkName=true, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const=0; }; diff --git a/xmltooling/security/impl/AbstractPKIXTrustEngine.cpp b/xmltooling/security/impl/AbstractPKIXTrustEngine.cpp index 8065543..a891f7d 100644 --- a/xmltooling/security/impl/AbstractPKIXTrustEngine.cpp +++ b/xmltooling/security/impl/AbstractPKIXTrustEngine.cpp @@ -28,7 +28,11 @@ #include #include #include +#include +#include +#include #include +#include #include #include #include @@ -38,15 +42,6 @@ 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) @@ -91,10 +86,7 @@ namespace { for (vector::const_iterator j=crls.begin(); j!=crls.end(); ++j) { if ((*j)->getProviderName()==DSIGConstants::s_unicodeStrPROVOpenSSL) { // owned by store - X509_STORE_add_crl( - store, - X509_CRL_dup(static_cast(*j)->getOpenSSLX509CRL()) - ); + X509_STORE_add_crl(store, X509_CRL_dup(static_cast(*j)->getOpenSSLX509CRL())); } } @@ -144,31 +136,20 @@ namespace { } }; -bool AbstractPKIXTrustEngine::checkEntityNames(X509* certEE, const KeyInfoSource& keyInfoSource) const +bool AbstractPKIXTrustEngine::checkEntityNames( + X509* certEE, const CredentialResolver& credResolver, const CredentialCriteria& criteria + ) 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 keynames; - auto_ptr keyInfoIter(keyInfoSource.getKeyInfoIterator()); - while (keyInfoIter->hasNext()) { - const KeyInfo* keyInfo = keyInfoIter->next(); - const vector& knames=keyInfo->getKeyNames(); - for (vector::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); - + vector creds; + credResolver.resolve(creds,&criteria); + + // Build a list of acceptable names. + vector keynames(1,criteria.getPeerName()); + for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) + (*cred)->getKeyNames(keynames); + char buf[256]; X509_NAME* subject=X509_get_subject_name(certEE); if (subject) { @@ -264,9 +245,8 @@ bool AbstractPKIXTrustEngine::checkEntityNames(X509* certEE, const KeyInfoSource bool AbstractPKIXTrustEngine::validate( X509* certEE, STACK_OF(X509)* certChain, - const KeyInfoSource& keyInfoSource, - bool checkName, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { #ifdef _DEBUG @@ -279,19 +259,19 @@ bool AbstractPKIXTrustEngine::validate( return false; } - if (checkName) { + if (criteria && criteria->getPeerName() && *(criteria->getPeerName())) { log.debug("checking that the certificate name is acceptable"); - if (!checkEntityNames(certEE,keyInfoSource)) { - log.debug("certificate name was not acceptable"); + if (criteria->getUsage()==CredentialCriteria::UNSPECIFIED_CREDENTIAL) + criteria->setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + if (!checkEntityNames(certEE,credResolver,*criteria)) { + log.error("certificate name was not acceptable"); return false; } } log.debug("performing certificate path validation..."); - auto_ptr pkix( - getPKIXValidationInfoIterator(keyInfoSource, *(keyResolver ? keyResolver : m_inlineResolver)) - ); + auto_ptr pkix(getPKIXValidationInfoIterator(credResolver, criteria, m_keyInfoResolver)); while (pkix->next()) { if (::validate(certEE,certChain,pkix.get())) { return true; @@ -305,9 +285,8 @@ bool AbstractPKIXTrustEngine::validate( bool AbstractPKIXTrustEngine::validate( XSECCryptoX509* certEE, const vector& certChain, - const KeyInfoSource& keyInfoSource, - bool checkName, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { #ifdef _DEBUG @@ -326,15 +305,15 @@ bool AbstractPKIXTrustEngine::validate( for (vector::const_iterator i=certChain.begin(); i!=certChain.end(); ++i) sk_X509_push(untrusted,static_cast(*i)->getOpenSSLX509()); - bool ret = validate(static_cast(certEE)->getOpenSSLX509(),untrusted,keyInfoSource,checkName,keyResolver); + bool ret = validate(static_cast(certEE)->getOpenSSLX509(), untrusted, credResolver, criteria); sk_X509_free(untrusted); return ret; } bool AbstractPKIXTrustEngine::validate( Signature& sig, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { #ifdef _DEBUG @@ -342,9 +321,23 @@ bool AbstractPKIXTrustEngine::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)) { + const KeyInfoResolver* inlineResolver = m_keyInfoResolver; + if (!inlineResolver) + inlineResolver = XMLToolingConfig::getConfig().getKeyInfoResolver(); + if (!inlineResolver) { + log.error("unable to perform PKIX validation, no KeyInfoResolver available"); + return false; + } + + // Pull the certificate chain out of the signature. + X509Credential* x509cred; + auto_ptr cred(inlineResolver->resolve(&sig,X509Credential::RESOLVE_CERTS)); + if (!cred.get() || !(x509cred=dynamic_cast(cred.get()))) { + log.error("unable to perform PKIX validation, signature does not contain any certificates"); + return false; + } + const vector& certs = x509cred->getEntityCertificateChain(); + if (certs.empty()) { log.error("unable to perform PKIX validation, signature does not contain any certificates"); return false; } @@ -355,20 +348,21 @@ bool AbstractPKIXTrustEngine::validate( // Most of the time, this will be the first one anyway. XSECCryptoX509* certEE=NULL; SignatureValidator keyValidator; - for (vector::const_iterator i=certs.v().begin(); !certEE && i!=certs.v().end(); ++i) { + for (vector::const_iterator i=certs.begin(); !certEE && i!=certs.end(); ++i) { try { - keyValidator.setKey((*i)->clonePublicKey()); + auto_ptr key((*i)->clonePublicKey()); + keyValidator.setKey(key.get()); keyValidator.validate(&sig); log.debug("signature verified with key inside signature, attempting certificate validation..."); certEE=(*i); } - catch (ValidationException&) { - // trap failures + catch (ValidationException& ex) { + log.debug(ex.what()); } } if (certEE) - return validate(certEE,certs.v(),keyInfoSource,true,keyResolver); + return validate(certEE,certs,credResolver,criteria); log.debug("failed to verify signature with embedded certificates"); return false; @@ -380,8 +374,8 @@ bool AbstractPKIXTrustEngine::validate( KeyInfo* keyInfo, const char* in, unsigned int in_len, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { #ifdef _DEBUG @@ -389,9 +383,28 @@ bool AbstractPKIXTrustEngine::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)) { + if (!keyInfo) { + log.error("unable to perform PKIX validation, KeyInfo not present"); + return false; + } + + const KeyInfoResolver* inlineResolver = m_keyInfoResolver; + if (!inlineResolver) + inlineResolver = XMLToolingConfig::getConfig().getKeyInfoResolver(); + if (!inlineResolver) { + log.error("unable to perform PKIX validation, no KeyInfoResolver available"); + return false; + } + + // Pull the certificate chain out of the signature. + X509Credential* x509cred; + auto_ptr cred(inlineResolver->resolve(keyInfo,X509Credential::RESOLVE_CERTS)); + if (!cred.get() || !(x509cred=dynamic_cast(cred.get()))) { + log.error("unable to perform PKIX validation, KeyInfo does not contain any certificates"); + return false; + } + const vector& certs = x509cred->getEntityCertificateChain(); + if (certs.empty()) { log.error("unable to perform PKIX validation, KeyInfo does not contain any certificates"); return false; } @@ -401,8 +414,7 @@ bool AbstractPKIXTrustEngine::validate( // Find and save off a pointer to the certificate that unlocks the object. // Most of the time, this will be the first one anyway. XSECCryptoX509* certEE=NULL; - SignatureValidator keyValidator; - for (vector::const_iterator i=certs.v().begin(); !certEE && i!=certs.v().end(); ++i) { + for (vector::const_iterator i=certs.begin(); !certEE && i!=certs.end(); ++i) { try { auto_ptr key((*i)->clonePublicKey()); if (Signature::verifyRawSignature(key.get(), sigAlgorithm, sig, in, in_len)) { @@ -410,13 +422,13 @@ bool AbstractPKIXTrustEngine::validate( certEE=(*i); } } - catch (SignatureException&) { - // trap failures + catch (SignatureException& ex) { + log.debug(ex.what()); } } if (certEE) - return validate(certEE,certs.v(),keyInfoSource,true,keyResolver); + return validate(certEE,certs,credResolver,criteria); log.debug("failed to verify signature with embedded certificates"); return false; diff --git a/xmltooling/security/impl/BasicX509Credential.cpp b/xmltooling/security/impl/BasicX509Credential.cpp new file mode 100644 index 0000000..d6f41da --- /dev/null +++ b/xmltooling/security/impl/BasicX509Credential.cpp @@ -0,0 +1,114 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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. + */ + +/** + * BasicX509Credential.cpp + * + * Wraps an X.509-based Credential by storing key/cert objects inside. + */ + +#include "internal.h" +#include "security/BasicX509Credential.h" +#include "signature/KeyInfo.h" + +#include +#include +#include + +using namespace xmlsignature; +using namespace xmltooling; +using namespace std; + +BasicX509Credential::~BasicX509Credential() +{ + delete m_key; + if (m_ownCerts) + for_each(m_xseccerts.begin(), m_xseccerts.end(), xmltooling::cleanup()); + delete m_crl; + delete m_keyInfo; + delete m_compactKeyInfo; +} + +void BasicX509Credential::initKeyInfo() +{ + delete m_keyInfo; + m_keyInfo = NULL; + delete m_compactKeyInfo; + m_compactKeyInfo = NULL; + + vector names; + if (getKeyNames(names)>0) { + m_compactKeyInfo = KeyInfoBuilder::buildKeyInfo(); + VectorOf(KeyName) knames = m_compactKeyInfo->getKeyNames(); + for (vector::const_iterator n = names.begin(); n!=names.end(); ++n) { + xmltooling::auto_ptr_XMLCh wide(n->c_str()); + KeyName* kname = KeyNameBuilder::buildKeyName(); + kname->setName(wide.get()); + knames.push_back(kname); + } + } + + if (!m_xseccerts.empty()) { + m_keyInfo = m_compactKeyInfo ? m_compactKeyInfo->cloneKeyInfo() : KeyInfoBuilder::buildKeyInfo(); + X509Data* x509Data=X509DataBuilder::buildX509Data(); + m_keyInfo->getX509Datas().push_back(x509Data); + for (vector::const_iterator x = m_xseccerts.begin(); x!=m_xseccerts.end(); ++x) { + safeBuffer& buf=(*x)->getDEREncodingSB(); + X509Certificate* x509=X509CertificateBuilder::buildX509Certificate(); + x509->setValue(buf.sbStrToXMLCh()); + x509Data->getX509Certificates().push_back(x509); + } + } +} + +vector::size_type BasicX509Credential::getKeyNames(vector& results) const +{ + if (m_xseccerts.empty() || m_xseccerts.front()->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) + return 0; + + X509* cert = static_cast(m_xseccerts.front())->getOpenSSLX509(); + if (!cert) + return 0; + + X509_NAME* subject=X509_get_subject_name(cert); + if (subject) { + char buf[256]; + memset(buf,0,sizeof(buf)); + if (X509_NAME_get_text_by_NID(subject,NID_commonName,buf,255)>0) + results.push_back(buf); + + STACK_OF(GENERAL_NAME)* altnames=(STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + if (altnames) { + string alt; + int numalts = sk_GENERAL_NAME_num(altnames); + for (int an=0; antype==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); + if (altlen>0) { + alt.erase(); + alt.append(altptr,altlen); + results.push_back(alt); + } + } + } + } + GENERAL_NAMES_free(altnames); + } + + return results.size(); +} diff --git a/xmltooling/security/impl/ChainingTrustEngine.cpp b/xmltooling/security/impl/ChainingTrustEngine.cpp index 41e04b1..1834aab 100644 --- a/xmltooling/security/impl/ChainingTrustEngine.cpp +++ b/xmltooling/security/impl/ChainingTrustEngine.cpp @@ -23,6 +23,7 @@ #include "internal.h" #include "exceptions.h" #include "security/ChainingTrustEngine.h" +#include "util/XMLHelper.h" #include #include @@ -65,14 +66,10 @@ ChainingTrustEngine::~ChainingTrustEngine() { for_each(m_engines.begin(), m_engines.end(), xmltooling::cleanup()); } -bool ChainingTrustEngine::validate( - Signature& sig, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver - ) const +bool ChainingTrustEngine::validate(Signature& sig, const CredentialResolver& credResolver, CredentialCriteria* criteria) const { for (vector::const_iterator i=m_engines.begin(); i!=m_engines.end(); ++i) { - if ((*i)->validate(sig,keyInfoSource,keyResolver)) + if ((*i)->validate(sig,credResolver,criteria)) return true; } return false; @@ -84,12 +81,12 @@ bool ChainingTrustEngine::validate( KeyInfo* keyInfo, const char* in, unsigned int in_len, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { for (vector::const_iterator i=m_engines.begin(); i!=m_engines.end(); ++i) { - if ((*i)->validate(sigAlgorithm, sig, keyInfo, in, in_len, keyInfoSource, keyResolver)) + if ((*i)->validate(sigAlgorithm, sig, keyInfo, in, in_len, credResolver, criteria)) return true; } return false; @@ -98,15 +95,14 @@ bool ChainingTrustEngine::validate( bool ChainingTrustEngine::validate( XSECCryptoX509* certEE, const vector& certChain, - const KeyInfoSource& keyInfoSource, - bool checkName, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { X509TrustEngine* down; for (vector::const_iterator i=m_engines.begin(); i!=m_engines.end(); ++i) { if ((down = dynamic_cast(*i)) && - down->validate(certEE,certChain,keyInfoSource,checkName,keyResolver)) + down->validate(certEE,certChain,credResolver,criteria)) return true; } return false; @@ -115,15 +111,13 @@ bool ChainingTrustEngine::validate( bool ChainingTrustEngine::validate( X509* certEE, STACK_OF(X509)* certChain, - const KeyInfoSource& keyInfoSource, - bool checkName, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { OpenSSLTrustEngine* down; for (vector::const_iterator i=m_engines.begin(); i!=m_engines.end(); ++i) { - if ((down = dynamic_cast(*i)) && - down->validate(certEE,certChain,keyInfoSource,checkName,keyResolver)) + if ((down = dynamic_cast(*i)) && down->validate(certEE,certChain,credResolver,criteria)) return true; } return false; diff --git a/xmltooling/security/impl/Credential.cpp b/xmltooling/security/impl/Credential.cpp new file mode 100644 index 0000000..2656f8d --- /dev/null +++ b/xmltooling/security/impl/Credential.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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. + */ + +/** + * Credential.cpp + * + * Wraps keys and related functionality. + */ + +#include "internal.h" +#include "security/Credential.h" + +#include +#include +#include +#include +#include + +using namespace xmltooling; + +bool Credential::isEqual(XSECCryptoKey& key) const +{ + XSECCryptoKey* key2 = getPublicKey(); + if (!key2) { + log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Credential").warn("no public key in credential for comparison"); + return false; + } + + if (key.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL || + key2->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { + log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Credential").warn("non-OpenSSL credentials are not supported."); + return false; + } + + if (key.getKeyType()==XSECCryptoKey::KEY_RSA_PUBLIC || key.getKeyType()==XSECCryptoKey::KEY_RSA_PAIR) { + if (key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PUBLIC && key2->getKeyType()==XSECCryptoKey::KEY_RSA_PAIR) + return false; + RSA* rsa1 = static_cast(&key)->getOpenSSLRSA(); + RSA* rsa2 = static_cast(key2)->getOpenSSLRSA(); + return (BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->e,rsa2->e) == 0); + } + + if (key.getKeyType()==XSECCryptoKey::KEY_DSA_PUBLIC || key.getKeyType()==XSECCryptoKey::KEY_DSA_PAIR) { + if (key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PUBLIC && key2->getKeyType()==XSECCryptoKey::KEY_DSA_PAIR) + return false; + DSA* dsa1 = static_cast(&key)->getOpenSSLDSA(); + DSA* dsa2 = static_cast(key2)->getOpenSSLDSA(); + return (BN_cmp(dsa1->pub_key,dsa2->pub_key) == 0); + } + + log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Credential").warn("unsupported key type for comparison"); + return false; +} diff --git a/xmltooling/security/impl/ExplicitKeyTrustEngine.cpp b/xmltooling/security/impl/ExplicitKeyTrustEngine.cpp index 08a30bd..7646bc5 100644 --- a/xmltooling/security/impl/ExplicitKeyTrustEngine.cpp +++ b/xmltooling/security/impl/ExplicitKeyTrustEngine.cpp @@ -21,6 +21,9 @@ */ #include "internal.h" +#include "security/Credential.h" +#include "security/CredentialCriteria.h" +#include "security/CredentialResolver.h" #include "security/OpenSSLTrustEngine.h" #include "signature/SignatureValidator.h" #include "util/NDC.h" @@ -45,8 +48,8 @@ namespace xmltooling { virtual bool validate( Signature& sig, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; virtual bool validate( const XMLCh* sigAlgorithm, @@ -54,22 +57,20 @@ namespace xmltooling { KeyInfo* keyInfo, const char* in, unsigned int in_len, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; virtual bool validate( XSECCryptoX509* certEE, const vector& certChain, - const KeyInfoSource& keyInfoSource, - bool checkName=true, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; virtual bool validate( X509* certEE, STACK_OF(X509)* certChain, - const KeyInfoSource& keyInfoSource, - bool checkName=true, - const KeyResolver* keyResolver=NULL + const CredentialResolver& credResolver, + CredentialCriteria* criteria=NULL ) const; }; @@ -81,43 +82,47 @@ namespace xmltooling { bool ExplicitKeyTrustEngine::validate( Signature& sig, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { #ifdef _DEBUG NDC ndc("validate"); #endif Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine"); - - auto_ptr keyInfoIter(keyInfoSource.getKeyInfoIterator()); - if (!keyInfoIter->hasNext()) { - log.warn("unable to validate signature, no key information available for peer"); + + vector credentials; + if (criteria) { + criteria->setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + criteria->setSignature(sig); + credResolver.resolve(credentials,criteria); + } + else { + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + cc.setSignature(sig); + credResolver.resolve(credentials,&cc); + } + if (credentials.empty()) { + log.warn("unable to validate signature, no credentials available from peer"); return false; } - log.debug("attempting to validate signature with the key information for peer"); + log.debug("attempting to validate signature with the peer's credentials"); SignatureValidator sigValidator; - while (keyInfoIter->hasNext()) { - XSECCryptoKey* key = (keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoIter->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.debug("signature validated with public key"); - return true; - } - catch (ValidationException& e) { - log.debug("public key did not validate signature: %s", e.what()); - } + for (vector::const_iterator c=credentials.begin(); c!=credentials.end(); ++c) { + sigValidator.setCredential(*c); + try { + sigValidator.validate(&sig); + log.debug("signature validated with credential"); + return true; } - else { - log.debug("key information does not resolve to a public key, skipping it"); + catch (ValidationException& e) { + log.debug("public key did not validate signature: %s", e.what()); } } - log.error("no peer key information validated the signature"); + log.error("no peer credentials validated the signature"); return false; } @@ -127,8 +132,8 @@ bool ExplicitKeyTrustEngine::validate( KeyInfo* keyInfo, const char* in, unsigned int in_len, - const KeyInfoSource& keyInfoSource, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { #ifdef _DEBUG @@ -136,19 +141,28 @@ bool ExplicitKeyTrustEngine::validate( #endif Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine"); - auto_ptr keyInfoIter(keyInfoSource.getKeyInfoIterator()); - if (!keyInfoIter->hasNext()) { - log.warn("unable to validate signature, no key information available for peer"); + vector credentials; + if (criteria) { + criteria->setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + criteria->setKeyInfo(keyInfo); + credResolver.resolve(credentials,criteria); + } + else { + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + cc.setKeyInfo(keyInfo); + credResolver.resolve(credentials,&cc); + } + if (credentials.empty()) { + log.warn("unable to validate signature, no credentials available from peer"); return false; } - log.debug("attempting to validate signature with the key information for peer"); - while (keyInfoIter->hasNext()) { - auto_ptr key((keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoIter->next())); - if (key.get()) { - log.debug("attempting to validate signature with public key..."); + log.debug("attempting to validate signature with the peer's credentials"); + for (vector::const_iterator c=credentials.begin(); c!=credentials.end(); ++c) { + if ((*c)->getPublicKey()) { try { - if (Signature::verifyRawSignature(key.get(), sigAlgorithm, sig, in, in_len)) { + if (Signature::verifyRawSignature((*c)->getPublicKey(), sigAlgorithm, sig, in, in_len)) { log.debug("signature validated with public key"); return true; } @@ -159,21 +173,17 @@ bool ExplicitKeyTrustEngine::validate( } } } - else { - log.debug("key information does not resolve to a public key, skipping it"); - } } - log.error("no peer key information validated the signature"); + log.error("no peer credentials validated the signature"); return false; } bool ExplicitKeyTrustEngine::validate( XSECCryptoX509* certEE, const vector& certChain, - const KeyInfoSource& keyInfoSource, - bool checkName, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { #ifdef _DEBUG @@ -188,15 +198,14 @@ bool ExplicitKeyTrustEngine::validate( return false; } - return validate(static_cast(certEE)->getOpenSSLX509(), NULL, keyInfoSource, checkName, keyResolver); + return validate(static_cast(certEE)->getOpenSSLX509(), NULL, credResolver, criteria); } bool ExplicitKeyTrustEngine::validate( X509* certEE, STACK_OF(X509)* certChain, - const KeyInfoSource& keyInfoSource, - bool checkName, - const KeyResolver* keyResolver + const CredentialResolver& credResolver, + CredentialCriteria* criteria ) const { #ifdef _DEBUG @@ -209,19 +218,29 @@ bool ExplicitKeyTrustEngine::validate( return false; } - auto_ptr keyInfoIter(keyInfoSource.getKeyInfoIterator()); - if (!keyInfoIter->hasNext()) { - log.warn("unable to validate, no key information available for peer"); + vector credentials; + if (criteria) { + if (criteria->getUsage()==CredentialCriteria::UNSPECIFIED_CREDENTIAL) + criteria->setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + credResolver.resolve(credentials,criteria); + } + else { + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + credResolver.resolve(credentials,&cc); + } + if (credentials.empty()) { + log.warn("unable to validate certificate, no credentials available from peer"); return false; } // The "explicit" trust implementation relies solely on keys living within the - // peer interface to verify the EE certificate. + // peer resolver to verify the EE certificate. - log.debug("attempting to match key information from peer with end-entity certificate"); - while (keyInfoIter->hasNext()) { - auto_ptr key((keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoIter->next())); - if (key.get()) { + log.debug("attempting to match credentials from peer with end-entity certificate"); + for (vector::const_iterator c=credentials.begin(); c!=credentials.end(); ++c) { + XSECCryptoKey* key = (*c)->getPublicKey(); + if (key) { log.debug("checking if peer key matches end-entity certificate"); if (key->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { log.error("only the OpenSSL XSEC provider is supported"); @@ -230,13 +249,13 @@ bool ExplicitKeyTrustEngine::validate( switch (key->getKeyType()) { case XSECCryptoKey::KEY_RSA_PUBLIC: { - RSA* rsa = static_cast(key.get())->getOpenSSLRSA(); + RSA* rsa = static_cast(key)->getOpenSSLRSA(); EVP_PKEY* evp = X509_PUBKEY_get(X509_get_X509_PUBKEY(certEE)); if (rsa && evp && evp->type == EVP_PKEY_RSA && BN_cmp(rsa->n,evp->pkey.rsa->n) == 0 && BN_cmp(rsa->e,evp->pkey.rsa->e) == 0) { - log.debug("end-entity certificate matches peer RSA key information"); if (evp) EVP_PKEY_free(evp); + log.debug("end-entity certificate matches peer RSA key information"); return true; } if (evp) @@ -246,12 +265,12 @@ bool ExplicitKeyTrustEngine::validate( case XSECCryptoKey::KEY_DSA_PUBLIC: { - DSA* dsa = static_cast(key.get())->getOpenSSLDSA(); + DSA* dsa = static_cast(key)->getOpenSSLDSA(); EVP_PKEY* evp = X509_PUBKEY_get(X509_get_X509_PUBKEY(certEE)); if (dsa && evp && evp->type == EVP_PKEY_DSA && BN_cmp(dsa->pub_key,evp->pkey.dsa->pub_key) == 0) { - log.debug("end-entity certificate matches peer DSA key information"); if (evp) EVP_PKEY_free(evp); + log.debug("end-entity certificate matches peer DSA key information"); return true; } if (evp) @@ -263,9 +282,6 @@ bool ExplicitKeyTrustEngine::validate( log.warn("unknown peer key type, skipping..."); } } - else { - log.debug("key information does not resolve to a public key, skipping it"); - } } log.debug("no keys within this peer's key information matched the given end-entity certificate"); diff --git a/xmltooling/security/impl/FilesystemCredentialResolver.cpp b/xmltooling/security/impl/FilesystemCredentialResolver.cpp index a026fdb..1e81da0 100644 --- a/xmltooling/security/impl/FilesystemCredentialResolver.cpp +++ b/xmltooling/security/impl/FilesystemCredentialResolver.cpp @@ -21,14 +21,16 @@ */ #include "internal.h" -#include "security/KeyResolver.h" -#include "security/OpenSSLCredentialResolver.h" +#include "security/BasicX509Credential.h" +#include "security/CredentialCriteria.h" +#include "security/CredentialResolver.h" +#include "security/KeyInfoResolver.h" +#include "security/OpenSSLCredential.h" #include "util/NDC.h" #include "util/XMLHelper.h" #include #include -#include #include #include #include @@ -56,35 +58,84 @@ static int passwd_callback(char* buf, int len, int verify, void* passwd) } namespace xmltooling { - class XMLTOOL_DLLLOCAL FilesystemCredentialResolver : public OpenSSLCredentialResolver, public KeyResolver + +#if defined (_MSC_VER) + #pragma warning( push ) + #pragma warning( disable : 4250 ) +#endif + + class XMLTOOL_DLLLOCAL FilesystemCredentialResolver; + class XMLTOOL_DLLLOCAL FilesystemCredential : public OpenSSLCredential, public BasicX509Credential + { + public: + FilesystemCredential(FilesystemCredentialResolver* resolver, XSECCryptoKey* key, const std::vector& xseccerts) + : BasicX509Credential(key, xseccerts), m_resolver(resolver) { + initKeyInfo(); + } + virtual ~FilesystemCredential() {} + void attach(SSL_CTX* ctx) const; + + FilesystemCredentialResolver* m_resolver; + }; + +#if defined (_MSC_VER) + #pragma warning( pop ) +#endif + + class XMLTOOL_DLLLOCAL FilesystemCredentialResolver : public CredentialResolver { public: FilesystemCredentialResolver(const DOMElement* e); - virtual ~FilesystemCredentialResolver(); + virtual ~FilesystemCredentialResolver() { + delete m_credential; + for_each(m_certs.begin(),m_certs.end(),X509_free); + } Lockable* lock() { return this; } void unlock() {} - XSECCryptoKey* loadKey(); - - XSECCryptoKey* getKey(const KeyInfo* keyInfo=NULL) const { return m_key ? m_key->clone() : NULL; } - const vector& getCertificates() const { return m_xseccerts; } - void attach(SSL_CTX* ctx) const; - - XSECCryptoKey* resolveKey(const KeyInfo* keyInfo) const { return m_key ? m_key->clone() : NULL; } - XSECCryptoKey* resolveKey(DSIGKeyInfoList* keyInfo) const { return m_key ? m_key->clone() : NULL; } - vector::size_type resolveCertificates(const KeyInfo* keyInfo, ResolvedCertificates& certs) const { - accessCertificates(certs).assign(m_xseccerts.begin(), m_xseccerts.end()); - accessOwned(certs) = false; - return accessCertificates(certs).size(); + const Credential* resolve(const CredentialCriteria* criteria=NULL) const { + return matches(criteria) ? m_credential : NULL; } - vector::size_type resolveCertificates(DSIGKeyInfoList* keyInfo, ResolvedCertificates& certs) const { - accessCertificates(certs).assign(m_xseccerts.begin(), m_xseccerts.end()); - accessOwned(certs) = false; - return accessCertificates(certs).size(); + + virtual vector::size_type resolve( + vector& results, const CredentialCriteria* criteria=NULL + ) const { + if (matches(criteria)) { + results.push_back(m_credential); + return 1; + } + return 0; } - + + void attach(SSL_CTX* ctx) const; + private: + XSECCryptoKey* loadKey(); + bool matches(const CredentialCriteria* criteria) const { + bool match = true; + if (criteria) { + // See if algorithm is kosher. + const char* alg = criteria->getKeyAlgorithm(); + if (alg && *alg) { + match = false; + for (vector::const_iterator a = m_algorithms.begin(); a!=m_algorithms.end(); ++a) { + if (strstr(alg, a->c_str())) + match = true; + } + } + if (match && m_credential->getPublicKey()) { + // See if we have to match a specific key. + auto_ptr cred( + XMLToolingConfig::getConfig().getKeyInfoResolver()->resolve(*criteria,Credential::RESOLVE_KEYS) + ); + if (cred.get()) + match = cred->isEqual(*(m_credential->getPublicKey())); + } + } + return match; + } + enum format_t { PEM=SSL_FILETYPE_PEM, DER=SSL_FILETYPE_ASN1, _PKCS12, UNKNOWN }; format_t getEncodingFormat(BIO* in) const; @@ -94,21 +145,17 @@ namespace xmltooling { format_t m_keyformat; string m_keypath,m_keypass; vector m_certs; - vector m_xseccerts; - XSECCryptoKey* m_key; + FilesystemCredential* m_credential; + vector m_algorithms; }; CredentialResolver* XMLTOOL_DLLLOCAL FilesystemCredentialResolverFactory(const DOMElement* const & e) { return new FilesystemCredentialResolver(e); } - - KeyResolver* XMLTOOL_DLLLOCAL FilesystemKeyResolverFactory(const DOMElement* const & e) - { - return new FilesystemCredentialResolver(e); - } }; +static const XMLCh AlgorithmPrefix[] = UNICODE_LITERAL_15(A,l,g,o,r,i,t,h,m,P,r,e,f,i,x); static const XMLCh CAPath[] = UNICODE_LITERAL_6(C,A,P,a,t,h); static const XMLCh Certificate[] = UNICODE_LITERAL_11(C,e,r,t,i,f,i,c,a,t,e); static const XMLCh format[] = UNICODE_LITERAL_6(f,o,r,m,a,t); @@ -116,19 +163,38 @@ static const XMLCh Key[] = UNICODE_LITERAL_3(K,e,y); static const XMLCh password[] = UNICODE_LITERAL_8(p,a,s,s,w,o,r,d); static const XMLCh Path[] = UNICODE_LITERAL_4(P,a,t,h); -FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) : m_key(NULL) +FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) : m_credential(NULL) { #ifdef _DEBUG NDC ndc("FilesystemCredentialResolver"); #endif Category& log=Category::getInstance(XMLTOOLING_LOGCAT".CredentialResolver"); + const DOMElement* root=e; + e=XMLHelper::getFirstChildElement(root,AlgorithmPrefix); + while (e) { + if (e->hasChildNodes()) { + auto_ptr_char alg(e->getFirstChild()->getNodeValue()); + if (alg.get()) + m_algorithms.push_back(alg.get()); + } + e=XMLHelper::getNextSiblingElement(e,AlgorithmPrefix); + } + + if (m_algorithms.empty()) { + m_algorithms.push_back(URI_ID_SIG_BASE); + m_algorithms.push_back(URI_ID_SIG_BASEMORE); + m_algorithms.push_back("http://www.w3.org/2001/04/xmlenc#rsa"); + } + + XSECCryptoKey* key=NULL; + vector xseccerts; + format_t fformat; const XMLCh* format_xml=NULL; BIO* in = NULL; // Move to Key - const DOMElement* root=e; e=XMLHelper::getFirstChildElement(root,Key); if (e) { @@ -192,18 +258,21 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) } // Load the key. - m_key = loadKey(); + key = loadKey(); } // Check for Certificate e=XMLHelper::getFirstChildElement(root,Certificate); - if (!e) + if (!e) { + m_credential = new FilesystemCredential(this,key,xseccerts); return; + } auto_ptr_char certpass(e->getAttributeNS(NULL,password)); DOMElement* ep=XMLHelper::getFirstChildElement(e,Path); if (!ep || !ep->hasChildNodes()) { log.error("Path element missing inside Certificate element or is empty"); + delete key; throw XMLSecurityException("FilesystemCredentialResolver can't access certificate file, missing or empty Path element."); } @@ -214,6 +283,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) if (fformat == UNKNOWN) { auto_ptr_char unknown(format_xml); log.error("configuration specifies unknown certificate encoding format (%s)", unknown.get()); + delete key; throw XMLSecurityException("FilesystemCredentialResolver configuration contains unknown certificate encoding format ($1)",params(1,unknown.get())); } } @@ -276,9 +346,8 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) in=NULL; } - if (m_certs.empty()) { + if (m_certs.empty()) throw XMLSecurityException("FilesystemCredentialResolver unable to load any certificate(s)"); - } // Load any extra CA files. DOMElement* extra=XMLHelper::getFirstChildElement(e,CAPath); @@ -348,14 +417,17 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) } } catch (XMLToolingException&) { - for (vector::iterator j=m_certs.begin(); j!=m_certs.end(); j++) - X509_free(*j); + delete key; + for_each(m_certs.begin(), m_certs.end(), X509_free); throw; } - // Reflect certs over to XSEC form. + // Reflect certs over to XSEC form and wrap with credential object. for (vector::iterator j=m_certs.begin(); j!=m_certs.end(); j++) - m_xseccerts.push_back(new OpenSSLCryptoX509(*j)); + xseccerts.push_back(new OpenSSLCryptoX509(*j)); + if (!key && !xseccerts.empty()) + key = xseccerts.front()->clonePublicKey(); + m_credential = new FilesystemCredential(this, key, xseccerts); } XSECCryptoKey* FilesystemCredentialResolver::loadKey() @@ -413,77 +485,6 @@ XSECCryptoKey* FilesystemCredentialResolver::loadKey() throw XMLSecurityException("FilesystemCredentialResolver unable to load private key from file."); } -FilesystemCredentialResolver::~FilesystemCredentialResolver() -{ - delete m_key; - for_each(m_certs.begin(),m_certs.end(),X509_free); - for_each(m_xseccerts.begin(),m_xseccerts.end(),xmltooling::cleanup()); -} - -void FilesystemCredentialResolver::attach(SSL_CTX* ctx) const -{ -#ifdef _DEBUG - NDC ndc("attach"); -#endif - - // Attach key. - SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); - SSL_CTX_set_default_passwd_cb_userdata(ctx, const_cast(m_keypass.c_str())); - - int ret=0; - switch (m_keyformat) { - case PEM: - ret=SSL_CTX_use_PrivateKey_file(ctx, m_keypath.c_str(), m_keyformat); - break; - - case DER: - ret=SSL_CTX_use_RSAPrivateKey_file(ctx, m_keypath.c_str(), m_keyformat); - break; - - default: { - BIO* in=BIO_new(BIO_s_file_internal()); - if (in && BIO_read_filename(in,m_keypath.c_str())>0) { - EVP_PKEY* pkey=NULL; - PKCS12* p12 = d2i_PKCS12_bio(in, NULL); - if (p12) { - PKCS12_parse(p12, const_cast(m_keypass.c_str()), &pkey, NULL, NULL); - PKCS12_free(p12); - if (pkey) { - ret=SSL_CTX_use_PrivateKey(ctx, pkey); - EVP_PKEY_free(pkey); - } - } - } - if (in) - BIO_free(in); - } - } - - if (ret!=1) { - log_openssl(); - throw XMLSecurityException("Unable to attach private key to SSL context."); - } - - // Attach certs. - for (vector::const_iterator i=m_certs.begin(); i!=m_certs.end(); i++) { - if (i==m_certs.begin()) { - if (SSL_CTX_use_certificate(ctx, *i) != 1) { - log_openssl(); - throw XMLSecurityException("Unable to attach client certificate to SSL context."); - } - } - else { - // When we add certs, they don't get ref counted, so we need to duplicate them. - X509* dup = X509_dup(*i); - if (SSL_CTX_add_extra_chain_cert(ctx, dup) != 1) { - X509_free(dup); - log_openssl(); - throw XMLSecurityException("Unable to attach CA certificate to SSL context."); - } - } - } -} - // Used to determine the encoding format of credentials files // dynamically. Supports: PEM, DER, PKCS12. FilesystemCredentialResolver::format_t FilesystemCredentialResolver::getEncodingFormat(BIO* in) const @@ -572,3 +573,72 @@ FilesystemCredentialResolver::format_t FilesystemCredentialResolver::xmlFormatTo return format; } + +void FilesystemCredentialResolver::attach(SSL_CTX* ctx) const +{ +#ifdef _DEBUG + NDC ndc("attach"); +#endif + + // Attach key. + SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); + SSL_CTX_set_default_passwd_cb_userdata(ctx, const_cast(m_keypass.c_str())); + + int ret=0; + switch (m_keyformat) { + case PEM: + ret=SSL_CTX_use_PrivateKey_file(ctx, m_keypath.c_str(), m_keyformat); + break; + + case DER: + ret=SSL_CTX_use_RSAPrivateKey_file(ctx, m_keypath.c_str(), m_keyformat); + break; + + default: { + BIO* in=BIO_new(BIO_s_file_internal()); + if (in && BIO_read_filename(in,m_keypath.c_str())>0) { + EVP_PKEY* pkey=NULL; + PKCS12* p12 = d2i_PKCS12_bio(in, NULL); + if (p12) { + PKCS12_parse(p12, const_cast(m_keypass.c_str()), &pkey, NULL, NULL); + PKCS12_free(p12); + if (pkey) { + ret=SSL_CTX_use_PrivateKey(ctx, pkey); + EVP_PKEY_free(pkey); + } + } + } + if (in) + BIO_free(in); + } + } + + if (ret!=1) { + log_openssl(); + throw XMLSecurityException("Unable to attach private key to SSL context."); + } + + // Attach certs. + for (vector::const_iterator i=m_certs.begin(); i!=m_certs.end(); i++) { + if (i==m_certs.begin()) { + if (SSL_CTX_use_certificate(ctx, *i) != 1) { + log_openssl(); + throw XMLSecurityException("Unable to attach client certificate to SSL context."); + } + } + else { + // When we add certs, they don't get ref counted, so we need to duplicate them. + X509* dup = X509_dup(*i); + if (SSL_CTX_add_extra_chain_cert(ctx, dup) != 1) { + X509_free(dup); + log_openssl(); + throw XMLSecurityException("Unable to attach CA certificate to SSL context."); + } + } + } +} + +void FilesystemCredential::attach(SSL_CTX* ctx) const +{ + return m_resolver->attach(ctx); +} diff --git a/xmltooling/security/impl/InlineKeyResolver.cpp b/xmltooling/security/impl/InlineKeyResolver.cpp index 311fd06..30e9dee 100644 --- a/xmltooling/security/impl/InlineKeyResolver.cpp +++ b/xmltooling/security/impl/InlineKeyResolver.cpp @@ -21,7 +21,8 @@ */ #include "internal.h" -#include "security/CachingKeyResolver.h" +#include "security/BasicX509Credential.h" +#include "security/KeyInfoResolver.h" #include "signature/KeyInfo.h" #include "util/NDC.h" #include "util/Threads.h" @@ -44,116 +45,122 @@ using namespace log4cpp; using namespace std; namespace xmltooling { - class XMLTOOL_DLLLOCAL InlineKeyResolver : public CachingKeyResolver + + class XMLTOOL_DLLLOCAL InlineCredential : public BasicX509Credential { + const KeyInfo* m_inlineKeyInfo; + DSIGKeyInfoList* m_nativeKeyInfo; public: - InlineKeyResolver(const DOMElement* e); - virtual ~InlineKeyResolver(); - - XSECCryptoKey* resolveKey(const KeyInfo* keyInfo) const; - XSECCryptoKey* resolveKey(DSIGKeyInfoList* keyInfo) const; - vector::size_type resolveCertificates(const KeyInfo* keyInfo, ResolvedCertificates& certs) const; - vector::size_type resolveCertificates(DSIGKeyInfoList* keyInfo, ResolvedCertificates& certs) const; - XSECCryptoX509CRL* resolveCRL(const KeyInfo* keyInfo) const; - XSECCryptoX509CRL* resolveCRL(DSIGKeyInfoList* keyInfo) const; - - void clearCache() { - if (m_lock) - m_lock->wrlock(); - m_cache.clear(); - if (m_lock) - m_lock->unlock(); + InlineCredential(const KeyInfo* keyInfo=NULL) + : BasicX509Credential(keyInfo!=NULL), m_inlineKeyInfo(keyInfo), m_nativeKeyInfo(NULL) { + } + InlineCredential(DSIGKeyInfoList* keyInfo) + : BasicX509Credential(false), m_inlineKeyInfo(NULL), m_nativeKeyInfo(keyInfo) { + } + virtual ~InlineCredential() {} + + XSECCryptoKey* getPrivateKey() const { + return NULL; + } + + const KeyInfo* getKeyInfo(bool compact=false) const { + return m_inlineKeyInfo; } - private: - struct XMLTOOL_DLLLOCAL CacheEntry { - CacheEntry() : m_key(NULL), m_crl(NULL) {} - ~CacheEntry() { - delete m_key; - for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup()); - delete m_crl; + vector::size_type getKeyNames(vector& results) const { + if (m_inlineKeyInfo) { + const vector& knames=m_inlineKeyInfo->getKeyNames(); + for (vector::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); + results.push_back(kn); + delete[] kn; + } + } + } + else if (m_nativeKeyInfo) { + for (size_t s=0; sgetSize(); s++) { + const XMLCh* n=m_nativeKeyInfo->item(s)->getKeyName(); + if (n && *n) { + char* kn=toUTF8(n); + results.push_back(kn); + delete[] kn; + } + } } - XSECCryptoKey* m_key; - vector m_certs; - XSECCryptoX509CRL* m_crl; - }; - - void _resolve(const KeyInfo* keyInfo, CacheEntry& entry) const; - XSECCryptoKey* _resolveKey(const KeyInfo* keyInfo) const; - vector::size_type _resolveCertificates(const KeyInfo* keyInfo, vector& certs) const; - XSECCryptoX509CRL* _resolveCRL(const KeyInfo* keyInfo) const; - - RWLock* m_lock; - mutable map m_cache; + return results.size(); + } + + void setKey(XSECCryptoKey* key) { + m_key = key; + } + + void addCert(XSECCryptoX509* cert) { + m_xseccerts.push_back(cert); + } + + void setCRL(XSECCryptoX509CRL* crl) { + m_crl = crl; + } }; - KeyResolver* XMLTOOL_DLLLOCAL InlineKeyResolverFactory(const DOMElement* const & e) + class XMLTOOL_DLLLOCAL InlineKeyResolver : public KeyInfoResolver { - return new InlineKeyResolver(e); - } -}; - -static const XMLCh cache[] = UNICODE_LITERAL_5(c,a,c,h,e); + public: + InlineKeyResolver() : m_log(Category::getInstance(XMLTOOLING_LOGCAT".KeyInfoResolver")) {} + virtual ~InlineKeyResolver() {} -InlineKeyResolver::InlineKeyResolver(const DOMElement* e) : m_lock(NULL) -{ - const XMLCh* flag = e ? e->getAttributeNS(NULL,cache) : NULL; - if (flag && XMLString::equals(flag,xmlconstants::XML_TRUE) || XMLString::equals(flag,xmlconstants::XML_ONE)) - m_lock=RWLock::create(); -} + Credential* resolve(const KeyInfo* keyInfo, int types=0) const; + Credential* resolve(DSIGKeyInfoList* keyInfo, int types=0) const; + + private: + bool resolveCerts(const KeyInfo* keyInfo, InlineCredential* credential) const; + bool resolveKey(const KeyInfo* keyInfo, InlineCredential* credential) const; + bool resolveCRL(const KeyInfo* keyInfo, InlineCredential* credential) const; -InlineKeyResolver::~InlineKeyResolver() -{ - clearCache(); - delete m_lock; -} + Category& m_log; + }; -void InlineKeyResolver::_resolve(const KeyInfo* keyInfo, CacheEntry& entry) const -{ - if (_resolveCertificates(keyInfo, entry.m_certs)>0) - entry.m_key = entry.m_certs.front()->clonePublicKey(); - else - entry.m_key = _resolveKey(keyInfo); - entry.m_crl = _resolveCRL(keyInfo); -} + KeyInfoResolver* XMLTOOL_DLLLOCAL InlineKeyInfoResolverFactory(const DOMElement* const & e) + { + return new InlineKeyResolver(); + } +}; -XSECCryptoKey* InlineKeyResolver::_resolveKey(const KeyInfo* keyInfo) const +Credential* InlineKeyResolver::resolve(const KeyInfo* keyInfo, int types) const { #ifdef _DEBUG - NDC ndc("_resolveKey"); + NDC ndc("resolve"); #endif - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver"); if (!keyInfo) return NULL; - // Check for ds:X509Data - const vector& x509Datas=keyInfo->getX509Datas(); - for (vector::const_iterator j=x509Datas.begin(); j!=x509Datas.end(); ++j) { - try { - const vector x509Certs=const_cast(*j)->getX509Certificates(); - if (!x509Certs.empty()) { - auto_ptr_char x(x509Certs.front()->getValue()); - if (!x.get()) { - log.warn("skipping empty ds:X509Certificate"); - } - else { - log.debug("resolving ds:X509Certificate"); - auto_ptr x509(XSECPlatformUtils::g_cryptoProvider->X509()); - x509->loadX509Base64Bin(x.get(), strlen(x.get())); - return x509->clonePublicKey(); - } - } - } - catch(XSECException& e) { - auto_ptr_char temp(e.getMsg()); - log.error("caught XML-Security exception loading certificate: %s", temp.get()); - } - catch(XSECCryptoException& e) { - log.error("caught XML-Security exception loading certificate: %s", e.getMsg()); - } + auto_ptr credential(new InlineCredential(keyInfo)); + if (types == 0) + types = Credential::RESOLVE_KEYS|X509Credential::RESOLVE_CERTS|X509Credential::RESOLVE_CRLS; + + if (types & X509Credential::RESOLVE_CERTS) + resolveCerts(keyInfo, credential.get()); + + if (types & Credential::RESOLVE_KEYS) { + // If we have a cert, just use it. + if (types & X509Credential::RESOLVE_CERTS && !credential->getEntityCertificateChain().empty()) + credential->setKey(credential->getEntityCertificateChain().front()->clonePublicKey()); + // Otherwise try directly for a key and then go for certs if none is found. + else if (!resolveKey(keyInfo, credential.get()) && resolveCerts(keyInfo, credential.get())) + credential->setKey(credential->getEntityCertificateChain().front()->clonePublicKey()); } + if (types & X509Credential::RESOLVE_CRLS) + resolveCRL(keyInfo, credential.get()); + + return credential.release(); +} + +bool InlineKeyResolver::resolveKey(const KeyInfo* keyInfo, InlineCredential* credential) const +{ // Check for ds:KeyValue const vector& keyValues = keyInfo->getKeyValues(); for (vector::const_iterator i=keyValues.begin(); i!=keyValues.end(); ++i) { @@ -161,17 +168,18 @@ XSECCryptoKey* InlineKeyResolver::_resolveKey(const KeyInfo* keyInfo) const SchemaValidators.validate(*i); // see if it's a "valid" key RSAKeyValue* rsakv = (*i)->getRSAKeyValue(); if (rsakv) { - log.debug("resolving ds:RSAKeyValue"); + m_log.debug("resolving ds:RSAKeyValue"); auto_ptr_char mod(rsakv->getModulus()->getValue()); auto_ptr_char exp(rsakv->getExponent()->getValue()); auto_ptr rsa(XSECPlatformUtils::g_cryptoProvider->keyRSA()); rsa->loadPublicModulusBase64BigNums(mod.get(), strlen(mod.get())); rsa->loadPublicExponentBase64BigNums(exp.get(), strlen(exp.get())); - return rsa.release(); + credential->setKey(rsa.release()); + return true; } DSAKeyValue* dsakv = (*i)->getDSAKeyValue(); if (dsakv) { - log.debug("resolving ds:DSAKeyValue"); + m_log.debug("resolving ds:DSAKeyValue"); auto_ptr dsa(XSECPlatformUtils::g_cryptoProvider->keyDSA()); auto_ptr_char y(dsakv->getY()->getValue()); dsa->loadYBase64BigNums(y.get(), strlen(y.get())); @@ -187,34 +195,33 @@ XSECCryptoKey* InlineKeyResolver::_resolveKey(const KeyInfo* keyInfo) const auto_ptr_char g(dsakv->getG()->getValue()); dsa->loadGBase64BigNums(g.get(), strlen(g.get())); } - return dsa.release(); + credential->setKey(dsa.release()); + return true; } } catch (ValidationException& ex) { - log.warn("skipping invalid ds:KeyValue (%s)", ex.what()); + m_log.warn("skipping invalid ds:KeyValue (%s)", ex.what()); } catch(XSECException& e) { auto_ptr_char temp(e.getMsg()); - log.error("caught XML-Security exception loading key: %s", temp.get()); + m_log.error("caught XML-Security exception loading key: %s", temp.get()); } catch(XSECCryptoException& e) { - log.error("caught XML-Security exception loading key: %s", e.getMsg()); + m_log.error("caught XML-Security exception loading key: %s", e.getMsg()); } } // Check for RetrievalMethod. const XMLCh* fragID=NULL; const XMLObject* treeRoot=NULL; - XSECCryptoKey* remote=NULL; - const vector methods=keyInfo->getRetrievalMethods(); + const vector& methods=keyInfo->getRetrievalMethods(); for (vector::const_iterator m=methods.begin(); m!=methods.end(); ++m) { - if (!XMLString::equals((*m)->getType(),RetrievalMethod::TYPE_X509DATA) && - !XMLString::equals((*m)->getType(),RetrievalMethod::TYPE_RSAKEYVALUE) && + if (!XMLString::equals((*m)->getType(),RetrievalMethod::TYPE_RSAKEYVALUE) && !XMLString::equals((*m)->getType(),RetrievalMethod::TYPE_DSAKEYVALUE)) continue; fragID = (*m)->getURI(); if (!fragID || *fragID != chPound || !*(fragID+1)) { - log.warn("skipping ds:RetrievalMethod with an empty or non-local reference"); + m_log.warn("skipping ds:RetrievalMethod with an empty or non-local reference"); continue; } if (!treeRoot) { @@ -224,68 +231,55 @@ XSECCryptoKey* InlineKeyResolver::_resolveKey(const KeyInfo* keyInfo) const } keyInfo = dynamic_cast(XMLHelper::getXMLObjectById(*treeRoot, fragID+1)); if (!keyInfo) { - log.warn("skipping ds:RetrievalMethod, local reference did not resolve to a ds:KeyInfo"); + m_log.warn("skipping ds:RetrievalMethod, local reference did not resolve to a ds:KeyInfo"); continue; } - remote = _resolveKey(keyInfo); - if (remote) - return remote; + if (resolveKey(keyInfo,credential)) + return true; } - - log.warn("unable to resolve key"); - return NULL; + return false; } -vector::size_type InlineKeyResolver::_resolveCertificates( - const KeyInfo* keyInfo, vector& certs - ) const +bool InlineKeyResolver::resolveCerts(const KeyInfo* keyInfo, InlineCredential* credential) const { -#ifdef _DEBUG - NDC ndc("_resolveCertificates"); -#endif - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver"); - - if (!keyInfo) - return 0; - // Check for ds:X509Data const vector& x509Datas=keyInfo->getX509Datas(); - for (vector::const_iterator j=x509Datas.begin(); certs.empty() && j!=x509Datas.end(); ++j) { + for (vector::const_iterator j=x509Datas.begin(); credential->getEntityCertificateChain().empty() && j!=x509Datas.end(); ++j) { const vector x509Certs=const_cast(*j)->getX509Certificates(); for (vector::const_iterator k=x509Certs.begin(); k!=x509Certs.end(); ++k) { try { auto_ptr_char x((*k)->getValue()); if (!x.get()) { - log.warn("skipping empty ds:X509Certificate"); + m_log.warn("skipping empty ds:X509Certificate"); } else { - log.debug("resolving ds:X509Certificate"); + m_log.debug("resolving ds:X509Certificate"); auto_ptr x509(XSECPlatformUtils::g_cryptoProvider->X509()); x509->loadX509Base64Bin(x.get(), strlen(x.get())); - certs.push_back(x509.release()); + credential->addCert(x509.release()); } } catch(XSECException& e) { auto_ptr_char temp(e.getMsg()); - log.error("caught XML-Security exception loading certificate: %s", temp.get()); + m_log.error("caught XML-Security exception loading certificate: %s", temp.get()); } catch(XSECCryptoException& e) { - log.error("caught XML-Security exception loading certificate: %s", e.getMsg()); + m_log.error("caught XML-Security exception loading certificate: %s", e.getMsg()); } } } - - if (certs.empty()) { + + if (credential->getEntityCertificateChain().empty()) { // Check for RetrievalMethod. const XMLCh* fragID=NULL; const XMLObject* treeRoot=NULL; const vector methods=keyInfo->getRetrievalMethods(); - for (vector::const_iterator m=methods.begin(); certs.empty() && m!=methods.end(); ++m) { + for (vector::const_iterator m=methods.begin(); m!=methods.end(); ++m) { if (!XMLString::equals((*m)->getType(),RetrievalMethod::TYPE_X509DATA)) continue; fragID = (*m)->getURI(); if (!fragID || *fragID != chPound || !*(fragID+1)) { - log.warn("skipping ds:RetrievalMethod with an empty or non-local reference"); + m_log.warn("skipping ds:RetrievalMethod with an empty or non-local reference"); continue; } if (!treeRoot) { @@ -295,29 +289,23 @@ vector::size_type InlineKeyResolver::_resolveCertificates( } keyInfo = dynamic_cast(XMLHelper::getXMLObjectById(*treeRoot, fragID+1)); if (!keyInfo) { - log.warn("skipping ds:RetrievalMethod, local reference did not resolve to a ds:KeyInfo"); + m_log.warn("skipping ds:RetrievalMethod, local reference did not resolve to a ds:KeyInfo"); continue; } - _resolveCertificates(keyInfo, certs); + if (resolveCerts(keyInfo,credential)) + return true; } + return false; } - if (log.isDebugEnabled()) { - log.debug("resolved %d certificate%s", certs.size(), certs.size()==1 ? "" : "s"); + if (m_log.isDebugEnabled()) { + m_log.debug("resolved %d certificate(s)", credential->getEntityCertificateChain().size()); } - return certs.size(); + return !credential->getEntityCertificateChain().empty(); } -XSECCryptoX509CRL* InlineKeyResolver::_resolveCRL(const KeyInfo* keyInfo) const +bool InlineKeyResolver::resolveCRL(const KeyInfo* keyInfo, InlineCredential* credential) const { -#ifdef _DEBUG - NDC ndc("_resolveCRL"); -#endif - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver"); - - if (!keyInfo) - return NULL; - // Check for ds:X509Data const vector& x509Datas=keyInfo->getX509Datas(); for (vector::const_iterator j=x509Datas.begin(); j!=x509Datas.end(); ++j) { @@ -326,21 +314,22 @@ XSECCryptoX509CRL* InlineKeyResolver::_resolveCRL(const KeyInfo* keyInfo) const try { auto_ptr_char x((*k)->getValue()); if (!x.get()) { - log.warn("skipping empty ds:X509CRL"); + m_log.warn("skipping empty ds:X509CRL"); } else { - log.debug("resolving ds:X509CRL"); + m_log.debug("resolving ds:X509CRL"); auto_ptr crl(XMLToolingConfig::getConfig().X509CRL()); crl->loadX509CRLBase64Bin(x.get(), strlen(x.get())); - return crl.release(); + credential->setCRL(crl.release()); + return true; } } catch(XSECException& e) { auto_ptr_char temp(e.getMsg()); - log.error("caught XML-Security exception loading certificate: %s", temp.get()); + m_log.error("caught XML-Security exception loading certificate: %s", temp.get()); } catch(XSECCryptoException& e) { - log.error("caught XML-Security exception loading certificate: %s", e.getMsg()); + m_log.error("caught XML-Security exception loading certificate: %s", e.getMsg()); } } } @@ -348,14 +337,13 @@ XSECCryptoX509CRL* InlineKeyResolver::_resolveCRL(const KeyInfo* keyInfo) const // Check for RetrievalMethod. const XMLCh* fragID=NULL; const XMLObject* treeRoot=NULL; - XSECCryptoX509CRL* remote=NULL; const vector methods=keyInfo->getRetrievalMethods(); for (vector::const_iterator m=methods.begin(); m!=methods.end(); ++m) { if (!XMLString::equals((*m)->getType(),RetrievalMethod::TYPE_X509DATA)) continue; fragID = (*m)->getURI(); if (!fragID || *fragID != chPound || !*(fragID+1)) { - log.warn("skipping ds:RetrievalMethod with an empty or non-local reference"); + m_log.warn("skipping ds:RetrievalMethod with an empty or non-local reference"); continue; } if (!treeRoot) { @@ -365,186 +353,83 @@ XSECCryptoX509CRL* InlineKeyResolver::_resolveCRL(const KeyInfo* keyInfo) const } keyInfo = dynamic_cast(XMLHelper::getXMLObjectById(*treeRoot, fragID+1)); if (!keyInfo) { - log.warn("skipping ds:RetrievalMethod, local reference did not resolve to a ds:KeyInfo"); + m_log.warn("skipping ds:RetrievalMethod, local reference did not resolve to a ds:KeyInfo"); continue; } - remote = _resolveCRL(keyInfo); - if (remote) - return remote; - } - - return NULL; -} - -XSECCryptoKey* InlineKeyResolver::resolveKey(const KeyInfo* keyInfo) const -{ - // Caching? - if (m_lock) { - // Get read lock. - m_lock->rdlock(); - map::iterator i=m_cache.find(keyInfo); - if (i != m_cache.end()) { - // Found in cache, so just return the results. - SharedLock locker(m_lock,false); - return i->second.m_key ? i->second.m_key->clone() : NULL; - } - else { - // Elevate lock. - m_lock->unlock(); - m_lock->wrlock(); - SharedLock locker(m_lock,false); - // Recheck cache. - i=m_cache.find(keyInfo); - if (i == m_cache.end()) { - i = m_cache.insert(make_pair(keyInfo,CacheEntry())).first; - _resolve(i->first, i->second); - } - return i->second.m_key ? i->second.m_key->clone() : NULL; - } + if (resolveCRL(keyInfo,credential)) + return true; } - return _resolveKey(keyInfo); -} -XSECCryptoX509CRL* InlineKeyResolver::resolveCRL(const KeyInfo* keyInfo) const -{ - // Caching? - if (m_lock) { - // Get read lock. - m_lock->rdlock(); - map::iterator i=m_cache.find(keyInfo); - if (i != m_cache.end()) { - // Found in cache, so just return the results. - SharedLock locker(m_lock,false); - return i->second.m_crl ? i->second.m_crl->clone() : NULL; - } - else { - // Elevate lock. - m_lock->unlock(); - m_lock->wrlock(); - SharedLock locker(m_lock,false); - // Recheck cache. - i=m_cache.find(keyInfo); - if (i == m_cache.end()) { - i = m_cache.insert(make_pair(keyInfo,CacheEntry())).first; - _resolve(i->first, i->second); - } - return i->second.m_crl ? i->second.m_crl->clone() : NULL; - } - } - return _resolveCRL(keyInfo); -} - -vector::size_type InlineKeyResolver::resolveCertificates( - const KeyInfo* keyInfo, ResolvedCertificates& certs - ) const -{ - // Caching? - if (m_lock) { - // Get read lock. - m_lock->rdlock(); - map::iterator i=m_cache.find(keyInfo); - if (i != m_cache.end()) { - // Found in cache, so just return the results. - SharedLock locker(m_lock,false); - accessCertificates(certs).assign(i->second.m_certs.begin(), i->second.m_certs.end()); - accessOwned(certs) = false; - return accessCertificates(certs).size(); - } - else { - // Elevate lock. - m_lock->unlock(); - m_lock->wrlock(); - SharedLock locker(m_lock,false); - // Recheck cache. - i=m_cache.find(keyInfo); - if (i == m_cache.end()) { - i = m_cache.insert(make_pair(keyInfo,CacheEntry())).first; - _resolve(i->first, i->second); - } - accessCertificates(certs).assign(i->second.m_certs.begin(), i->second.m_certs.end()); - accessOwned(certs) = false; - return accessCertificates(certs).size(); - } - } - accessOwned(certs) = true; - return _resolveCertificates(keyInfo, accessCertificates(certs)); + return false; } -XSECCryptoKey* InlineKeyResolver::resolveKey(DSIGKeyInfoList* keyInfo) const +Credential* InlineKeyResolver::resolve(DSIGKeyInfoList* keyInfo, int types) const { #ifdef _DEBUG - NDC ndc("resolveKey"); + NDC ndc("resolve"); #endif if (!keyInfo) return NULL; - // Default resolver handles RSA/DSAKeyValue and X509Certificate elements. - try { - XSECKeyInfoResolverDefault def; - return def.resolveKey(keyInfo); - } - catch(XSECException& e) { - auto_ptr_char temp(e.getMsg()); - Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading certificate: %s", temp.get()); - } - catch(XSECCryptoException& e) { - Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading certificate: %s", e.getMsg()); - } - return NULL; -} + if (types == 0) + types = Credential::RESOLVE_KEYS|X509Credential::RESOLVE_CERTS|X509Credential::RESOLVE_CRLS; -vector::size_type InlineKeyResolver::resolveCertificates( - DSIGKeyInfoList* keyInfo, ResolvedCertificates& certs - ) const -{ - accessCertificates(certs).clear(); - accessOwned(certs) = false; + auto_ptr credential(new InlineCredential(keyInfo)); - if (!keyInfo) - return 0; + if (types & Credential::RESOLVE_KEYS) { + // Default resolver handles RSA/DSAKeyValue and X509Certificate elements. + try { + XSECKeyInfoResolverDefault def; + credential->setKey(def.resolveKey(keyInfo)); + } + catch(XSECException& e) { + auto_ptr_char temp(e.getMsg()); + Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading certificate: %s", temp.get()); + } + catch(XSECCryptoException& e) { + Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading certificate: %s", e.getMsg()); + } + } DSIGKeyInfoList::size_type sz = keyInfo->getSize(); - for (DSIGKeyInfoList::size_type i=0; accessCertificates(certs).empty() && iitem(i)->getKeyInfoType()==DSIGKeyInfo::KEYINFO_X509) { - DSIGKeyInfoX509* x509 = static_cast(keyInfo->item(i)); - int count = x509->getCertificateListSize(); - for (int j=0; jgetCertificateCryptoItem(j)); + + if (types & X509Credential::RESOLVE_CERTS) { + for (DSIGKeyInfoList::size_type i=0; iitem(i)->getKeyInfoType()==DSIGKeyInfo::KEYINFO_X509) { + DSIGKeyInfoX509* x509 = static_cast(keyInfo->item(i)); + int count = x509->getCertificateListSize(); + if (count) { + for (int j=0; jaddCert(x509->getCertificateCryptoItem(j)); + break; + } } } } - return accessCertificates(certs).size(); -} -XSECCryptoX509CRL* InlineKeyResolver::resolveCRL(DSIGKeyInfoList* keyInfo) const -{ -#ifdef _DEBUG - NDC ndc("resolveCRL"); -#endif - - if (!keyInfo) - return NULL; - - DSIGKeyInfoList::size_type sz = keyInfo->getSize(); - for (DSIGKeyInfoList::size_type i=0; iitem(i)->getKeyInfoType()==DSIGKeyInfo::KEYINFO_X509) { - auto_ptr_char buf(static_cast(keyInfo->item(i))->getX509CRL()); - if (buf.get()) { - try { - auto_ptr crlobj(XMLToolingConfig::getConfig().X509CRL()); - crlobj->loadX509CRLBase64Bin(buf.get(), strlen(buf.get())); - return crlobj.release(); - } - catch(XSECException& e) { - auto_ptr_char temp(e.getMsg()); - Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading CRL: %s", temp.get()); - } - catch(XSECCryptoException& e) { - Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading CRL: %s", e.getMsg()); + if (types & X509Credential::RESOLVE_CRLS) { + for (DSIGKeyInfoList::size_type i=0; iitem(i)->getKeyInfoType()==DSIGKeyInfo::KEYINFO_X509) { + auto_ptr_char buf(static_cast(keyInfo->item(i))->getX509CRL()); + if (buf.get()) { + try { + auto_ptr crlobj(XMLToolingConfig::getConfig().X509CRL()); + crlobj->loadX509CRLBase64Bin(buf.get(), strlen(buf.get())); + credential->setCRL(crlobj.release()); + break; + } + catch(XSECException& e) { + auto_ptr_char temp(e.getMsg()); + Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading CRL: %s", temp.get()); + } + catch(XSECCryptoException& e) { + Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading CRL: %s", e.getMsg()); + } } } } } - return NULL; + + return credential.release(); } diff --git a/xmltooling/security/impl/KeyInfoResolver.cpp b/xmltooling/security/impl/KeyInfoResolver.cpp new file mode 100644 index 0000000..dda9367 --- /dev/null +++ b/xmltooling/security/impl/KeyInfoResolver.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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. + */ + +/** + * KeyInfoResolver.cpp + * + * Registration of factories for built-in resolvers + */ + +#include "internal.h" +#include "security/CredentialCriteria.h" +#include "security/KeyInfoResolver.h" +#include "signature/Signature.h" + +using namespace xmlsignature; +using namespace xmltooling; +using namespace std; + +namespace xmltooling { + XMLTOOL_DLLLOCAL PluginManager::Factory InlineKeyInfoResolverFactory; +}; + +void XMLTOOL_API xmltooling::registerKeyInfoResolvers() +{ + XMLToolingConfig& conf=XMLToolingConfig::getConfig(); + conf.KeyInfoResolverManager.registerFactory(INLINE_KEYINFO_RESOLVER, InlineKeyInfoResolverFactory); +} + +Credential* KeyInfoResolver::resolve(const Signature* sig, int types) const +{ + const KeyInfo* keyInfo = sig->getKeyInfo(); + if (keyInfo) + return resolve(keyInfo, types); + DSIGSignature* native = sig->getXMLSignature(); + return resolve(native ? native->getKeyInfoList() : (DSIGKeyInfoList*)NULL, types); +} + +Credential* KeyInfoResolver::resolve(const CredentialCriteria& criteria, int types) const +{ + const KeyInfo* keyInfo = criteria.getKeyInfo(); + if (keyInfo) + return resolve(keyInfo, types); + DSIGKeyInfoList* native = criteria.getNativeKeyInfo(); + return native ? resolve(native, types) : NULL; +} diff --git a/xmltooling/security/impl/KeyResolver.cpp b/xmltooling/security/impl/KeyResolver.cpp deleted file mode 100644 index c319b78..0000000 --- a/xmltooling/security/impl/KeyResolver.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2001-2007 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * 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. - */ - -/** - * KeyResolver.cpp - * - * Registration of factories for built-in resolvers - */ - -#include "internal.h" -#include "security/KeyResolver.h" -#include "signature/Signature.h" - -using namespace xmlsignature; -using namespace xmltooling; -using namespace std; - -namespace xmltooling { - XMLTOOL_DLLLOCAL PluginManager::Factory FilesystemKeyResolverFactory; - XMLTOOL_DLLLOCAL PluginManager::Factory InlineKeyResolverFactory; -}; - -void XMLTOOL_API xmltooling::registerKeyResolvers() -{ - XMLToolingConfig& conf=XMLToolingConfig::getConfig(); - conf.KeyResolverManager.registerFactory(FILESYSTEM_KEY_RESOLVER, FilesystemKeyResolverFactory); - conf.KeyResolverManager.registerFactory(INLINE_KEY_RESOLVER, InlineKeyResolverFactory); -} - -XSECCryptoKey* KeyResolver::resolveKey(const Signature* sig) const -{ - const KeyInfo* keyInfo = sig->getKeyInfo(); - if (keyInfo) - return resolveKey(keyInfo); - DSIGSignature* native = sig->getXMLSignature(); - return resolveKey(native ? native->getKeyInfoList() : (DSIGKeyInfoList*)NULL); -} - -vector::size_type KeyResolver::resolveCertificates( - const KeyInfo* keyInfo, ResolvedCertificates& certs - ) const -{ - return 0; -} - -vector::size_type KeyResolver::resolveCertificates( - DSIGKeyInfoList* keyInfo, ResolvedCertificates& certs - ) const -{ - return 0; -} - -vector::size_type KeyResolver::resolveCertificates( - const Signature* sig, ResolvedCertificates& certs - ) const -{ - const KeyInfo* keyInfo = sig->getKeyInfo(); - if (keyInfo) - return resolveCertificates(keyInfo, certs); - DSIGSignature* native = sig->getXMLSignature(); - return resolveCertificates(native ? native->getKeyInfoList() : (DSIGKeyInfoList*)NULL, certs); -} - -XSECCryptoX509CRL* KeyResolver::resolveCRL(const KeyInfo* keyInfo) const -{ - return NULL; -} - -XSECCryptoX509CRL* KeyResolver::resolveCRL(DSIGKeyInfoList* keyInfo) const -{ - return NULL; -} - -XSECCryptoX509CRL* KeyResolver::resolveCRL(const Signature* sig) const -{ - const KeyInfo* keyInfo = sig->getKeyInfo(); - if (keyInfo) - return resolveCRL(keyInfo); - DSIGSignature* native = sig->getXMLSignature(); - return resolveCRL(native ? native->getKeyInfoList() : (DSIGKeyInfoList*)NULL); -} diff --git a/xmltooling/security/impl/TrustEngine.cpp b/xmltooling/security/impl/TrustEngine.cpp index c2b56d7..adc2c2e 100644 --- a/xmltooling/security/impl/TrustEngine.cpp +++ b/xmltooling/security/impl/TrustEngine.cpp @@ -21,7 +21,9 @@ */ #include "internal.h" +#include "security/KeyInfoResolver.h" #include "security/TrustEngine.h" +#include "util/XMLHelper.h" #include @@ -40,25 +42,22 @@ void XMLTOOL_API xmltooling::registerTrustEngines() conf.TrustEngineManager.registerFactory(CHAINING_TRUSTENGINE, ChainingTrustEngineFactory); } -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); +static const XMLCh _KeyInfoResolver[] = UNICODE_LITERAL_15(K,e,y,I,n,f,o,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) +TrustEngine::TrustEngine(const DOMElement* e) : m_keyInfoResolver(NULL) { - DOMElement* child = e ? XMLHelper::getFirstChildElement(e,GenericKeyResolver) : NULL; + DOMElement* child = e ? XMLHelper::getFirstChildElement(e,_KeyInfoResolver) : NULL; if (child) { auto_ptr_char t(child->getAttributeNS(NULL,type)); if (t.get()) - m_keyResolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(t.get(),child); + m_keyInfoResolver = XMLToolingConfig::getConfig().KeyInfoResolverManager.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); + throw UnknownExtensionException(" element found with no type attribute"); } } TrustEngine::~TrustEngine() { - delete m_keyResolver; + delete m_keyInfoResolver; } diff --git a/xmltooling/signature/Signature.h b/xmltooling/signature/Signature.h index a86bd71..d26ccb8 100644 --- a/xmltooling/signature/Signature.h +++ b/xmltooling/signature/Signature.h @@ -122,8 +122,10 @@ namespace xmlsignature { /** * Compute and append the signature based on the assigned * ContentReference, KeyInfo, and signing key. + * + * @param credential optional source of signing key and KeyInfo */ - virtual void sign()=0; + virtual void sign(const xmltooling::Credential* credential=NULL)=0; /** * Type-safe clone operation. diff --git a/xmltooling/signature/SignatureValidator.h b/xmltooling/signature/SignatureValidator.h index 0e6ec5a..a082c39 100644 --- a/xmltooling/signature/SignatureValidator.h +++ b/xmltooling/signature/SignatureValidator.h @@ -23,38 +23,33 @@ #if !defined(__xmltooling_sigval_h__) && !defined(XMLTOOLING_NO_XMLSEC) #define __xmltooling_sigval_h__ -#include +#include #include #include namespace xmlsignature { /** - * Validator for signatures based on a Key or a KeyResolver + * Validator for signatures based on a Credential */ class XMLTOOL_API SignatureValidator : public xmltooling::Validator { public: /** - * Constructor using a KeyResolver + * Constructor using a key * - * @param resolver the key resolver to use, will be freed by Validator + * @param key the key to use */ - SignatureValidator(xmltooling::KeyResolver* resolver) : m_key(NULL), m_resolver(resolver) { - } + SignatureValidator(XSECCryptoKey* key=NULL) : m_key(key), m_credential(NULL) {} /** - * Constructor using a Key + * Constructor using a Credential * - * @param key the verification key to use, will be freed by Validator + * @param credential the credential to use */ - SignatureValidator(XSECCryptoKey* key=NULL) : m_key(key), m_resolver(NULL) { - } - - virtual ~SignatureValidator() { - delete m_key; - delete m_resolver; - } + SignatureValidator(const xmltooling::Credential* credential) : m_key(NULL), m_credential(credential) {} + + virtual ~SignatureValidator() {} virtual void validate(const xmltooling::XMLObject* xmlObject) const; @@ -66,35 +61,31 @@ namespace xmlsignature { virtual void validate(const Signature* signature) const; /** - * Replace the current Key, if any, with a new one. + * Replace the current key, if any, with a new one. * - * @param key the Key to attach + * @param key the key to attach */ void setKey(XSECCryptoKey* key) { - delete m_key; - delete m_resolver; - m_resolver=NULL; - m_key=key; + m_key = key; + m_credential = NULL; } /** - * Replace the current KeyResolver, if any, with a new one. + * Replace the current Credential, if any, with a new one. * - * @param resolver the KeyResolver to attach + * @param credential the Credential to attach */ - void setKeyResolver(xmltooling::KeyResolver* resolver) { - delete m_key; - delete m_resolver; - m_key=NULL; - m_resolver=resolver; + void setCredential(const xmltooling::Credential* credential) { + m_key = NULL; + m_credential = credential; } protected: /** Verification key. */ XSECCryptoKey* m_key; - - /** KeyResolver to use against signature. */ - xmltooling::KeyResolver* m_resolver; + + /** Verification credential. */ + const xmltooling::Credential* m_credential; }; }; diff --git a/xmltooling/signature/impl/SignatureValidator.cpp b/xmltooling/signature/impl/SignatureValidator.cpp index dab1311..667a439 100644 --- a/xmltooling/signature/impl/SignatureValidator.cpp +++ b/xmltooling/signature/impl/SignatureValidator.cpp @@ -43,16 +43,17 @@ void SignatureValidator::validate(const Signature* sigObj) const DSIGSignature* sig=sigObj->getXMLSignature(); if (!sig) throw ValidationException("Signature does not exist yet."); - else if (!m_key && !m_resolver) - throw ValidationException("No KeyResolver or signing key set on Validator."); + else if (!m_key && !m_credential) + throw ValidationException("No Credential or key set on Validator."); + + XSECCryptoKey* key = m_key ? m_key : (m_credential ? m_credential->getPublicKey() : NULL); + if (!key) + throw ValidationException("Credential did not contain a verification key."); try { - XSECCryptoKey* key = m_key ? m_key->clone() : m_resolver->resolveKey(sig->getKeyInfoList()); - if (!key) - throw ValidationException("Unable to resolve signing key."); - sig->setSigningKey(key); + sig->setSigningKey(key->clone()); if (!sig->verify()) - throw ValidationException("Digital signature does not validate with the given key."); + throw ValidationException("Digital signature does not validate with the supplied key."); } catch(XSECException& e) { auto_ptr_char temp(e.getMsg()); diff --git a/xmltooling/signature/impl/XMLSecSignatureImpl.cpp b/xmltooling/signature/impl/XMLSecSignatureImpl.cpp index b96b6ac..51a5119 100644 --- a/xmltooling/signature/impl/XMLSecSignatureImpl.cpp +++ b/xmltooling/signature/impl/XMLSecSignatureImpl.cpp @@ -23,6 +23,7 @@ #include "internal.h" #include "exceptions.h" #include "impl/UnknownElement.h" +#include "security/Credential.h" #include "signature/KeyInfo.h" #include "signature/Signature.h" #include "util/NDC.h" @@ -75,8 +76,8 @@ namespace xmlsignature { XMLObject* clone() const; Signature* cloneSignature() const; - DOMElement* marshall(DOMDocument* document=NULL, const vector* sigs=NULL) const; - DOMElement* marshall(DOMElement* parentElement, const vector* sigs=NULL) const; + DOMElement* marshall(DOMDocument* document=NULL, const vector* sigs=NULL, const Credential* credential=NULL) const; + DOMElement* marshall(DOMElement* parentElement, const vector* sigs=NULL, const Credential* credential=NULL) const; XMLObject* unmarshall(DOMElement* element, bool bindDocument=false); // Getters @@ -102,14 +103,14 @@ namespace xmlsignature { m_reference=reference; } - void sign(); + void sign(const Credential* credential=NULL); private: mutable DSIGSignature* m_signature; XMLCh* m_c14n; XMLCh* m_sm; XSECCryptoKey* m_key; - KeyInfo* m_keyInfo; + mutable KeyInfo* m_keyInfo; ContentReference* m_reference; }; @@ -171,18 +172,20 @@ Signature* XMLSecSignatureImpl::cloneSignature() const return ret; } -void XMLSecSignatureImpl::sign() +void XMLSecSignatureImpl::sign(const Credential* credential) { Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Signature"); log.debug("applying signature"); if (!m_signature) throw SignatureException("Only a marshalled Signature object can be signed."); - else if (!m_key) - throw SignatureException("No signing key available for signature creation."); else if (!m_reference) throw SignatureException("No ContentReference object set for signature creation."); + XSECCryptoKey* key = credential ? credential->getPrivateKey() : m_key; + if (!key) + throw SignatureException("No signing key available for signature creation."); + try { log.debug("creating signature reference(s)"); DSIGReferenceList* refs = m_signature->getReferenceList(); @@ -191,7 +194,7 @@ void XMLSecSignatureImpl::sign() m_reference->createReferences(m_signature); log.debug("computing signature"); - m_signature->setSigningKey(m_key->clone()); + m_signature->setSigningKey(key->clone()); m_signature->sign(); } catch(XSECException& e) { @@ -203,7 +206,7 @@ void XMLSecSignatureImpl::sign() } } -DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector* sigs) const +DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector* sigs, const Credential* credential) const { #ifdef _DEBUG xmltooling::NDC ndc("marshall"); @@ -285,6 +288,13 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vectorgetKeyInfo(); + if (fromcred) + m_keyInfo = fromcred->cloneKeyInfo(); + } if (m_keyInfo && (!m_signature->getKeyInfoList() || m_signature->getKeyInfoList()->isEmpty())) { m_keyInfo->marshall(cachedDOM); } @@ -298,7 +308,7 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector* sigs) const +DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, const vector* sigs, const Credential* credential) const { #ifdef _DEBUG xmltooling::NDC ndc("marshall"); @@ -364,6 +374,13 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, const vecto } // Marshall KeyInfo data. + if (credential) { + delete m_keyInfo; + m_keyInfo = NULL; + const KeyInfo* fromcred = credential->getKeyInfo(); + if (fromcred) + m_keyInfo = fromcred->cloneKeyInfo(); + } if (m_keyInfo && (!m_signature->getKeyInfoList() || m_signature->getKeyInfoList()->isEmpty())) { m_keyInfo->marshall(cachedDOM); } diff --git a/xmltooling/soap/SOAPClient.h b/xmltooling/soap/SOAPClient.h index ee33004..6e27d40 100644 --- a/xmltooling/soap/SOAPClient.h +++ b/xmltooling/soap/SOAPClient.h @@ -23,7 +23,7 @@ #ifndef __xmltooling_soap11client_h__ #define __xmltooling_soap11client_h__ -#include +#include #include namespace soap11 { @@ -68,11 +68,15 @@ namespace soap11 { * appropriate for the endpoint URL provided and supply it to the * prepareTransport() method below. * - * @param env SOAP envelope to send - * @param peer peer to send message to, expressed in TrustEngine terms - * @param endpoint URL of endpoint to recieve message + *

To authenticate the server end, the transport layer object + * exposes a method to load a TrustEngine and CredentialResolver + * in a subclass-specific version of the prepareTransport() method. + * + * @param env SOAP envelope to send + * @param peerName name of peer + * @param endpoint URL of endpoint to recieve message */ - virtual void send(const Envelope& env, const xmltooling::KeyInfoSource& peer, const char* endpoint); + virtual void send(const Envelope& env, const char* peerName, const char* endpoint); /** * Returns the response message, if any. As long as a response is diff --git a/xmltooling/soap/SOAPTransport.h b/xmltooling/soap/SOAPTransport.h index e044da3..d3b8bc5 100644 --- a/xmltooling/soap/SOAPTransport.h +++ b/xmltooling/soap/SOAPTransport.h @@ -28,8 +28,8 @@ namespace xmltooling { + class XMLTOOL_API Credential; class XMLTOOL_API CredentialResolver; - class XMLTOOL_API KeyResolver; class XMLTOOL_API X509TrustEngine; /** @@ -92,30 +92,31 @@ namespace xmltooling { #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. + * Supplies transport credentials. + * + *

The lifetime of the credential must be longer than the lifetime of this object. * - *

The CredentialResolver MUST be locked by the caller. - * - * @param credResolver a locked CredentialResolver instance, or NULL - * @return true iff the transport supports the use of a CredentialResolver + * @param credential a Credential instance, or NULL + * @return true iff the transport supports the use of the Credential */ - virtual bool setCredentialResolver(const CredentialResolver* credResolver)=0; + virtual bool setCredential(const Credential* credential=NULL)=0; /** - * Provides a TrustEngine to the transport to authenticate the transport peer. + * Provides an X509TrustEngine 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 trustEngine an X509TrustEngine instance, or NULL + * @param credResolver a CredentialResolver to supply the peer's trusted credentials, or NULL + * @param criteria optional criteria for selecting peer credentials * @param mandatory flag controls whether message is sent at all if the * transport isn't authenticated using the TrustEngine - * @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, - bool mandatory=true, - const KeyResolver* keyResolver=NULL + const X509TrustEngine* trustEngine=NULL, + const CredentialResolver* credResolver=NULL, + CredentialCriteria* criteria=NULL, + bool mandatory=true )=0; #endif diff --git a/xmltooling/soap/impl/CURLSOAPTransport.cpp b/xmltooling/soap/impl/CURLSOAPTransport.cpp index 314940b..043e613 100644 --- a/xmltooling/soap/impl/CURLSOAPTransport.cpp +++ b/xmltooling/soap/impl/CURLSOAPTransport.cpp @@ -22,8 +22,9 @@ #include "internal.h" #include "exceptions.h" +#include "security/CredentialCriteria.h" #include "security/OpenSSLTrustEngine.h" -#include "security/OpenSSLCredentialResolver.h" +#include "security/OpenSSLCredential.h" #include "soap/HTTPSOAPTransport.h" #include "soap/OpenSSLSOAPTransport.h" #include "util/NDC.h" @@ -48,8 +49,8 @@ namespace xmltooling { 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); + CURL* get(const char* to, const char* endpoint); + void put(const char* to, const char* endpoint, CURL* handle); private: typedef map > poolmap_t; @@ -65,13 +66,13 @@ namespace xmltooling { 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), + CURLSOAPTransport(const char* peerName, const char* endpoint) + : m_peerName(peerName ? peerName : ""), m_endpoint(endpoint), m_handle(NULL), m_headers(NULL), #ifndef XMLTOOLING_NO_XMLSEC - m_credResolver(NULL), m_trustEngine(NULL), m_mandatory(false), m_keyResolver(NULL), + m_cred(NULL), m_trustEngine(NULL), m_peerResolver(NULL), m_mandatory(false), #endif m_ssl_callback(NULL), m_ssl_userptr(NULL), m_chunked(true), m_secure(false) { - m_handle = g_CURLPool->get(peer.getName(), endpoint); + m_handle = g_CURLPool->get(peerName, 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); @@ -85,7 +86,7 @@ namespace xmltooling { curl_slist_free_all(m_headers); curl_easy_setopt(m_handle,CURLOPT_ERRORBUFFER,NULL); curl_easy_setopt(m_handle,CURLOPT_PRIVATE,m_secure ? "secure" : NULL); // Save off security "state". - g_CURLPool->put(m_peer.getName(), m_endpoint.c_str(), m_handle); + g_CURLPool->put(m_peerName.c_str(), m_endpoint.c_str(), m_handle); } bool isConfidential() const { @@ -103,25 +104,32 @@ namespace xmltooling { bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL); #ifndef XMLTOOLING_NO_XMLSEC - bool setCredentialResolver(const CredentialResolver* credResolver) { - const OpenSSLCredentialResolver* down = dynamic_cast(credResolver); + bool setCredential(const Credential* cred=NULL) { + const OpenSSLCredential* down = dynamic_cast(cred); if (!down) { - m_credResolver = NULL; - return (credResolver==NULL); + m_cred = NULL; + return (cred==NULL); } - m_credResolver = down; + m_cred = down; return true; } - bool setTrustEngine(const X509TrustEngine* trustEngine, bool mandatory=true, const KeyResolver* keyResolver=NULL) { + bool setTrustEngine( + const X509TrustEngine* trustEngine=NULL, + const CredentialResolver* peerResolver=NULL, + CredentialCriteria* criteria=NULL, + bool mandatory=true + ) { const OpenSSLTrustEngine* down = dynamic_cast(trustEngine); if (!down) { m_trustEngine = NULL; - m_keyResolver = NULL; + m_peerResolver = NULL; + m_criteria = NULL; return (trustEngine==NULL); } m_trustEngine = down; - m_keyResolver = keyResolver; + m_peerResolver = peerResolver; + m_criteria = criteria; m_mandatory = mandatory; return true; } @@ -166,17 +174,17 @@ namespace xmltooling { private: // per-call state - const KeyInfoSource& m_peer; - string m_endpoint; + string m_peerName,m_endpoint; CURL* m_handle; stringstream m_stream; struct curl_slist* m_headers; map > m_response_headers; #ifndef XMLTOOLING_NO_XMLSEC - const OpenSSLCredentialResolver* m_credResolver; + const OpenSSLCredential* m_cred; const OpenSSLTrustEngine* m_trustEngine; + const CredentialResolver* m_peerResolver; + CredentialCriteria* m_criteria; bool m_mandatory; - const KeyResolver* m_keyResolver; #endif ssl_ctx_callback_fn m_ssl_callback; void* m_ssl_userptr; @@ -198,9 +206,9 @@ namespace xmltooling { int XMLTOOL_DLLLOCAL verify_callback(X509_STORE_CTX* x509_ctx, void* arg); #endif - SOAPTransport* CURLSOAPTransportFactory(const pair& dest) + SOAPTransport* CURLSOAPTransportFactory(const pair& dest) { - return new CURLSOAPTransport(*dest.first, dest.second); + return new CURLSOAPTransport(dest.first, dest.second); } }; @@ -231,14 +239,14 @@ CURLPool::~CURLPool() delete m_lock; } -CURL* CURLPool::get(const string& to, const char* endpoint) +CURL* CURLPool::get(const char* 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); + poolmap_t::iterator i=m_bindingMap.find(string(to) + "|" + endpoint); if (i!=m_bindingMap.end()) { // Move this pool to the front of the list. @@ -277,9 +285,9 @@ CURL* CURLPool::get(const string& to, const char* endpoint) return handle; } -void CURLPool::put(const string& to, const char* endpoint, CURL* handle) +void CURLPool::put(const char* to, const char* endpoint, CURL* handle) { - string key = to + "|" + endpoint; + string key = string(to) + "|" + endpoint; m_lock->lock(); poolmap_t::iterator i=m_bindingMap.find(key); if (i==m_bindingMap.end()) @@ -404,7 +412,7 @@ void CURLSOAPTransport::send(istream& in) // Set request headers. curl_easy_setopt(m_handle,CURLOPT_HTTPHEADER,m_headers); - if (m_ssl_callback || m_credResolver || m_trustEngine) { + if (m_ssl_callback || m_cred || 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); @@ -504,8 +512,21 @@ int xmltooling::verify_callback(X509_STORE_CTX* x509_ctx, void* arg) ); #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)) { + bool success=false; + if (ctx->m_criteria) { + ctx->m_criteria->setUsage(CredentialCriteria::TLS_CREDENTIAL); + // Bypass name check (handled for us by curl). + ctx->m_criteria->setPeerName(NULL); + success = ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,*(ctx->m_peerResolver),ctx->m_criteria); + } + else { + // Bypass name check (handled for us by curl). + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::TLS_CREDENTIAL); + success = ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,*(ctx->m_peerResolver),&cc); + } + + if (!success) { log.error("supplied TrustEngine failed to validate SSL/TLS server certificate"); x509_ctx->error=X509_V_ERR_APPLICATION_VERIFICATION; // generic error, check log for plugin specifics ctx->setSecure(false); @@ -524,8 +545,8 @@ CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* us CURLSOAPTransport* conf = reinterpret_cast(userptr); #ifndef XMLTOOLING_NO_XMLSEC - if (conf->m_credResolver) - conf->m_credResolver->attach(ssl_ctx); + if (conf->m_cred) + conf->m_cred->attach(ssl_ctx); if (conf->m_trustEngine) { SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL); diff --git a/xmltooling/soap/impl/SOAPClient.cpp b/xmltooling/soap/impl/SOAPClient.cpp index fbfc1bd..2a56979 100644 --- a/xmltooling/soap/impl/SOAPClient.cpp +++ b/xmltooling/soap/impl/SOAPClient.cpp @@ -46,14 +46,14 @@ void SOAPClient::reset() m_transport=NULL; } -void SOAPClient::send(const Envelope& env, const KeyInfoSource& peer, const char* endpoint) +void SOAPClient::send(const Envelope& env, const char* peerName, const char* endpoint) { // Prepare a transport object. const char* pch = strchr(endpoint,':'); if (!pch) throw IOException("SOAP endpoint was not a URL."); string scheme(endpoint, pch-endpoint); - m_transport = XMLToolingConfig::getConfig().SOAPTransportManager.newPlugin(scheme.c_str(), make_pair(&peer,endpoint)); + m_transport = XMLToolingConfig::getConfig().SOAPTransportManager.newPlugin(scheme.c_str(), make_pair(peerName,endpoint)); prepareTransport(*m_transport); // Serialize envelope. diff --git a/xmltooling/util/XMLHelper.h b/xmltooling/util/XMLHelper.h index f7c9034..66ce0ab 100644 --- a/xmltooling/util/XMLHelper.h +++ b/xmltooling/util/XMLHelper.h @@ -53,6 +53,24 @@ namespace xmltooling { } /** + * Returns resource held by this object. + * + * @return the resource held or NULL + */ + T* get() { + return m_held; + } + + /** + * Returns resource held by this object. + * + * @return the resource held or NULL + */ + T* operator->() { + return m_held; + } + + /** * Returns resource held by this object and releases it to the caller. * * @return the resource held or NULL diff --git a/xmltooling/xmltooling.vcproj b/xmltooling/xmltooling.vcproj index 6846084..9334729 100644 --- a/xmltooling/xmltooling.vcproj +++ b/xmltooling/xmltooling.vcproj @@ -346,6 +346,10 @@ > + + @@ -370,10 +374,18 @@ > + + + + @@ -390,7 +402,7 @@ > - - @@ -665,7 +673,7 @@ > + + + + diff --git a/xmltoolingtest/EncryptionTest.h b/xmltoolingtest/EncryptionTest.h index 4f6f0b5..f3de66a 100644 --- a/xmltoolingtest/EncryptionTest.h +++ b/xmltoolingtest/EncryptionTest.h @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include @@ -26,16 +28,6 @@ using namespace xmlencryption; -class _addcert : public std::binary_function { -public: - void operator()(X509Data* bag, XSECCryptoX509* cert) const { - safeBuffer& buf=cert->getDEREncodingSB(); - X509Certificate* x=X509CertificateBuilder::buildX509Certificate(); - x->setValue(buf.sbStrToXMLCh()); - bag->getX509Certificates().push_back(x); - } -}; - class EncryptionTest : public CxxTest::TestSuite { CredentialResolver* m_resolver; public: @@ -61,14 +53,20 @@ public: TS_ASSERT(doc!=NULL); try { + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); Locker locker(m_resolver); + const Credential* cred=m_resolver->resolve(&cc); + TSM_ASSERT("Retrieved credential was null", cred!=NULL); + Encrypter encrypter; Encrypter::EncryptionParams ep; - Encrypter::KeyEncryptionParams kep(DSIGConstants::s_unicodeStrURIRSA_1_5,m_resolver->getKey()); + Encrypter::KeyEncryptionParams kep(*cred,DSIGConstants::s_unicodeStrURIRSA_1_5); auto_ptr encData(encrypter.encryptElement(doc->getDocumentElement(),ep,&kep)); string buf; XMLHelper::serialize(encData->marshall(), buf); + //TS_TRACE(buf.c_str()); istringstream is(buf); DOMDocument* doc2=XMLToolingConfig::getConfig().getValidatingParser().parse(is); auto_ptr encData2( diff --git a/xmltoolingtest/FilesystemCredentialResolverTest.h b/xmltoolingtest/FilesystemCredentialResolverTest.h index 8091870..a396685 100644 --- a/xmltoolingtest/FilesystemCredentialResolverTest.h +++ b/xmltoolingtest/FilesystemCredentialResolverTest.h @@ -17,6 +17,7 @@ #include "XMLObjectBaseTestCase.h" #include +#include #include @@ -41,8 +42,9 @@ public: ); Locker locker(credResolver.get()); - auto_ptr key(credResolver->getKey()); - TSM_ASSERT("Retrieved key was null", key.get()!=NULL); - TSM_ASSERT_EQUALS("Unexpected number of certificates", 1, credResolver->getCertificates().size()); + const X509Credential* cred=dynamic_cast(credResolver->resolve()); + TSM_ASSERT("Retrieved credential was null", cred!=NULL); + TSM_ASSERT("Retrieved key was null", cred->getPrivateKey()!=NULL); + TSM_ASSERT_EQUALS("Unexpected number of certificates", 1, cred->getEntityCertificateChain().size()); } }; diff --git a/xmltoolingtest/InlineKeyResolverTest.h b/xmltoolingtest/InlineKeyResolverTest.h index d59b0b3..007af8c 100644 --- a/xmltoolingtest/InlineKeyResolverTest.h +++ b/xmltoolingtest/InlineKeyResolverTest.h @@ -17,13 +17,14 @@ #include "XMLObjectBaseTestCase.h" #include +#include +#include #include -#include using namespace xmlsignature; class InlineKeyResolverTest : public CxxTest::TestSuite { - KeyResolver* m_resolver; + KeyInfoResolver* m_resolver; public: InlineKeyResolverTest() : m_resolver(NULL) {} @@ -32,7 +33,7 @@ public: ifstream in(config.c_str()); DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in); XercesJanitor janitor(doc); - m_resolver=XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(INLINE_KEY_RESOLVER,doc->getDocumentElement()); + m_resolver=XMLToolingConfig::getConfig().KeyInfoResolverManager.newPlugin(INLINE_KEYINFO_RESOLVER,doc->getDocumentElement()); } void tearDown() { @@ -50,14 +51,12 @@ public: auto_ptr kiObject(dynamic_cast(b->buildFromDocument(doc))); TS_ASSERT(kiObject.get()!=NULL); - auto_ptr key(m_resolver->resolveKey(kiObject.get())); - TSM_ASSERT("Unable to resolve public key.", key.get()!=NULL); - TSM_ASSERT_EQUALS("Unexpected key type.", key->getKeyType(), XSECCryptoKey::KEY_RSA_PUBLIC); + auto_ptr cred(dynamic_cast(m_resolver->resolve(kiObject.get()))); + TSM_ASSERT("Unable to resolve KeyInfo into Credential.", cred.get()!=NULL); - auto_ptr crl(m_resolver->resolveCRL(kiObject.get())); - TSM_ASSERT("Unable to resolve CRL.", crl.get()!=NULL); - - KeyResolver::ResolvedCertificates certs; - TSM_ASSERT_EQUALS("Wrong certificate count.", m_resolver->resolveCertificates(kiObject.get(), certs), 1); + TSM_ASSERT("Unable to resolve public key.", cred->getPublicKey()!=NULL); + TSM_ASSERT_EQUALS("Unexpected key type.", cred->getPublicKey()->getKeyType(), XSECCryptoKey::KEY_RSA_PUBLIC); + TSM_ASSERT_EQUALS("Wrong certificate count.", cred->getEntityCertificateChain().size(), 1); + TSM_ASSERT("Unable to resolve CRL.", cred->getCRL()!=NULL); } }; diff --git a/xmltoolingtest/SignatureTest.h b/xmltoolingtest/SignatureTest.h index 394583e..8e05cce 100644 --- a/xmltoolingtest/SignatureTest.h +++ b/xmltoolingtest/SignatureTest.h @@ -16,6 +16,8 @@ #include "XMLObjectBaseTestCase.h" +#include +#include #include #include #include @@ -49,7 +51,7 @@ class TestValidator : public SignatureValidator XMLCh* m_uri; public: - TestValidator(const XMLCh* uri) : SignatureValidator(XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(INLINE_KEY_RESOLVER,NULL)) { + TestValidator(const XMLCh* uri, const Credential* credential) : SignatureValidator(credential) { m_uri=XMLString::replicate(uri); } @@ -67,16 +69,6 @@ public: } }; -class _addcert : public std::binary_function { -public: - void operator()(X509Data* bag, XSECCryptoX509* cert) const { - safeBuffer& buf=cert->getDEREncodingSB(); - X509Certificate* x=X509CertificateBuilder::buildX509Certificate(); - x->setValue(buf.sbStrToXMLCh()); - bag->getX509Certificates().push_back(x); - } -}; - class SignatureTest : public CxxTest::TestSuite { CredentialResolver* m_resolver; public: @@ -126,20 +118,16 @@ public: sxObject->setSignature(sig); sig->setContentReference(new TestContext(&chNull)); + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); Locker locker(m_resolver); - sig->setSigningKey(m_resolver->getKey()); - - // Build KeyInfo. - KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo(); - X509Data* x509Data=X509DataBuilder::buildX509Data(); - keyInfo->getX509Datas().push_back(x509Data); - for_each(m_resolver->getCertificates().begin(),m_resolver->getCertificates().end(),bind1st(_addcert(),x509Data)); - sig->setKeyInfo(keyInfo); + const Credential* cred = m_resolver->resolve(&cc); + TSM_ASSERT("Retrieved credential was null", cred!=NULL); DOMElement* rootElement = NULL; try { - rootElement=sxObject->marshall((DOMDocument*)NULL); - sig->sign(); + vector sigs(1,sig); + rootElement=sxObject->marshall((DOMDocument*)NULL,&sigs,cred); } catch (XMLToolingException& e) { TS_TRACE(e.what()); @@ -157,7 +145,7 @@ public: TS_ASSERT(sxObject2->getSignature()!=NULL); try { - TestValidator tv(&chNull); + TestValidator tv(&chNull, cred); tv.validate(sxObject2->getSignature()); } catch (XMLToolingException& e) { -- 2.1.4