From 420effca96f38dfa5f2a6549679a5d455a3945a7 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 6 Sep 2010 01:00:44 +0000 Subject: [PATCH] https://issues.shibboleth.net/jira/browse/SSPCPP-304 --- configure.ac | 4 + xmltooling/XMLToolingConfig.cpp | 127 ++++++++++++++++++++++--------- xmltooling/XMLToolingConfig.h | 23 +++++- xmltooling/encryption/Encrypter.h | 4 + xmltooling/encryption/impl/Encrypter.cpp | 36 +++++++-- xmltooling/internal.h | 8 +- 6 files changed, 153 insertions(+), 49 deletions(-) diff --git a/configure.ac b/configure.ac index 62e4adf..7af6f4c 100644 --- a/configure.ac +++ b/configure.ac @@ -284,6 +284,10 @@ if test x_$with_xmlsec != x_no; then AC_MSG_ERROR([unable to link with openssl libraries])) AC_MSG_RESULT(yes) + AC_CHECK_DECL(EVP_sha512, + [AC_DEFINE(XMLTOOLING_OPENSSL_HAVE_SHA2)], + ,[#include ]) + # restore master libs LIBS="$save_LIBS" diff --git a/xmltooling/XMLToolingConfig.cpp b/xmltooling/XMLToolingConfig.cpp index 202c9f1..3c0a9c5 100644 --- a/xmltooling/XMLToolingConfig.cpp +++ b/xmltooling/XMLToolingConfig.cpp @@ -61,6 +61,7 @@ #ifndef XMLTOOLING_NO_XMLSEC # include # include +# include # include # include # include @@ -73,6 +74,12 @@ using namespace xmltooling; using namespace xercesc; using namespace std; +#ifdef WIN32 +# if (OPENSSL_VERSION_NUMBER >= 0x00908000) +# define XMLTOOLING_OPENSSL_HAVE_SHA2 +# endif +#endif + DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling); DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling); @@ -630,22 +637,34 @@ XSECCryptoX509CRL* XMLToolingInternalConfig::X509CRL() const pair XMLToolingInternalConfig::mapXMLAlgorithmToKeyAlgorithm(const XMLCh* xmlAlgorithm) const { - algmap_t::const_iterator i = m_algorithmMap.find(xmlAlgorithm); - if (i == m_algorithmMap.end()) - return pair(nullptr, 0); - return make_pair(i->second.first.c_str(), i->second.second); + for (algmap_t::const_iterator i = m_algorithmMap.begin(); i != m_algorithmMap.end(); ++i) { + algmap_t::value_type::second_type::const_iterator j = i->second.find(xmlAlgorithm); + if (j != i->second.end()) + return pair(j->second.first.c_str(), j->second.second); + } + return pair(nullptr, 0); } -void XMLToolingInternalConfig::registerXMLAlgorithm(const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size) +void XMLToolingInternalConfig::registerXMLAlgorithm( + const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size, XMLSecurityAlgorithmType type + ) { - m_algorithmMap[xmlAlgorithm] = pair(keyAlgorithm, size); + m_algorithmMap[type][xmlAlgorithm] = pair((keyAlgorithm ? keyAlgorithm : ""), size); } -bool XMLToolingInternalConfig::isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm) +bool XMLToolingInternalConfig::isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm, XMLSecurityAlgorithmType type) { try { - if (XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(xmlAlgorithm)) - return true; + // First check for basic support from the xmlsec layer. + if (XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(xmlAlgorithm)) { + // Make sure the algorithm is registered. + algmap_t::const_iterator i = m_algorithmMap.find(type); + if (i != m_algorithmMap.end()) { + algmap_t::value_type::second_type::const_iterator j = i->second.find(xmlAlgorithm); + if (j != i->second.end()) + return true; + } + } } catch (XSECException&) { } @@ -654,40 +673,78 @@ bool XMLToolingInternalConfig::isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm void XMLToolingInternalConfig::registerXMLAlgorithms() { - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_MD5, "RSA", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA1, "RSA", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA224, "RSA", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA256, "RSA", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA384, "RSA", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA512, "RSA", 0); + // The deal with all the macros is to try and figure out with no false positives whether + // the OpenSSL version *and* the XML-Security version support the algorithms. - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_1_5, "RSA", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, "RSA", 0); + // With ECDSA, XML-Security exports a public macro for OpenSSL's support, and any + // versions of XML-Security that didn't provide the macro don't handle ECDSA anyway. - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIDSA_SHA1, "DSA", 0); + // With AES, all supported XML-Security versions export a macro for OpenSSL's support. - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA1, "EC", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA256, "EC", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA384, "EC", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA512, "EC", 0); + // With SHA2, only the very latest XML-Security exports a macro, but all the versions + // will handle SHA2 *if* OpenSSL does. So we use our own macro to check OpenSSL's + // support, and then add checks to see if specific versions are compiled out. - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA1, "HMAC", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA224, "HMAC", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA256, "HMAC", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA384, "HMAC", 0); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA512, "HMAC", 0); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIMD5, nullptr, 0, ALGTYPE_DIGEST); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA1, nullptr, 0, ALGTYPE_DIGEST); +#if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256) + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA224, nullptr, 0, ALGTYPE_DIGEST); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA256, nullptr, 0, ALGTYPE_DIGEST); +#endif +#if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512) + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA384, nullptr, 0, ALGTYPE_DIGEST); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA512, nullptr, 0, ALGTYPE_DIGEST); +#endif - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURI3DES_CBC, "DESede", 192); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_3DES, "DESede", 192); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIDSA_SHA1, "DSA", 0, ALGTYPE_SIGN); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_MD5, "RSA", 0, ALGTYPE_SIGN); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA1, "RSA", 0, ALGTYPE_SIGN); +#if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256) + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA224, "RSA", 0, ALGTYPE_SIGN); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA256, "RSA", 0, ALGTYPE_SIGN); +#endif +#if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512) + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA384, "RSA", 0, ALGTYPE_SIGN); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA512, "RSA", 0, ALGTYPE_SIGN); +#endif - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES128_CBC, "AES", 128); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES128, "AES", 128); +#ifdef XSEC_OPENSSL_HAVE_EC + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA1, "EC", 0, ALGTYPE_SIGN); +#if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256) + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA256, "EC", 0, ALGTYPE_SIGN); +# endif +#if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512) + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA384, "EC", 0, ALGTYPE_SIGN); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA512, "EC", 0, ALGTYPE_SIGN); +# endif +#endif + + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA1, "HMAC", 0, ALGTYPE_SIGN); +#if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256) + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA224, "HMAC", 0, ALGTYPE_SIGN); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA256, "HMAC", 0, ALGTYPE_SIGN); +#endif +#if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512) + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA384, "HMAC", 0, ALGTYPE_SIGN); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA512, "HMAC", 0, ALGTYPE_SIGN); +#endif + + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_1_5, "RSA", 0, ALGTYPE_KEYENCRYPT); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, "RSA", 0, ALGTYPE_KEYENCRYPT); + + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURI3DES_CBC, "DESede", 192, ALGTYPE_ENCRYPT); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_3DES, "DESede", 192, ALGTYPE_KEYENCRYPT); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES192_CBC, "AES", 192); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES192, "AES", 192); +#ifdef XSEC_OPENSSL_HAVE_AES + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES128_CBC, "AES", 128, ALGTYPE_ENCRYPT); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES128, "AES", 128, ALGTYPE_KEYENCRYPT); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES256_CBC, "AES", 256); - registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES256, "AES", 256); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES192_CBC, "AES", 192, ALGTYPE_ENCRYPT); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES192, "AES", 192, ALGTYPE_KEYENCRYPT); + + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES256_CBC, "AES", 256, ALGTYPE_ENCRYPT); + registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES256, "AES", 256, ALGTYPE_KEYENCRYPT); +#endif } #endif diff --git a/xmltooling/XMLToolingConfig.h b/xmltooling/XMLToolingConfig.h index 56beaf0..6aa6af9 100644 --- a/xmltooling/XMLToolingConfig.h +++ b/xmltooling/XMLToolingConfig.h @@ -286,21 +286,38 @@ namespace xmltooling { virtual std::pair mapXMLAlgorithmToKeyAlgorithm(const XMLCh* xmlAlgorithm) const=0; /** + * Types of XML Security algorithms. + */ + enum XMLSecurityAlgorithmType { + ALGTYPE_UNK, + ALGTYPE_DIGEST, + ALGTYPE_SIGN, + ALGTYPE_ENCRYPT, + ALGTYPE_KEYENCRYPT, + ALGTYPE_KEYAGREE + }; + + /** * Registers an XML Signature/Encryption algorithm identifier against a library-specific * key algorithm and size for use in resolving credentials. * * @param xmlAlgorithm XML Signature/Encryption algorithm identifier * @param keyAlgorithm a key algorithm * @param size a key size (or 0 if the size is irrelevant) + * @param type type of algorithm, if known */ - virtual void registerXMLAlgorithm(const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size=0)=0; + virtual void registerXMLAlgorithm( + const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size=0, XMLSecurityAlgorithmType type=ALGTYPE_UNK + )=0; /** - * Checks for implementation support of a particular XML security algorithm. + * Checks for implementation support of a particular XML Security algorithm. * + * @param xmlAlgorithm XML Signature/Encryption algorithm identifier + * @param type type of algorithm, or ALGTYPE_UNK to ignore * @return true iff the algorithm is supported by the underlying libraries */ - virtual bool isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm)=0; + virtual bool isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm, XMLSecurityAlgorithmType type=ALGTYPE_UNK)=0; #endif /** diff --git a/xmltooling/encryption/Encrypter.h b/xmltooling/encryption/Encrypter.h index 140a860..e1723e9 100644 --- a/xmltooling/encryption/Encrypter.h +++ b/xmltooling/encryption/Encrypter.h @@ -81,7 +81,11 @@ namespace xmlencryption { * @param compact true iff the encrypted representation should be made as small as possible */ EncryptionParams( +#ifdef XSEC_OPENSSL_HAVE_AES const XMLCh* algorithm=DSIGConstants::s_unicodeStrURIAES128_CBC, +#else + const XMLCh* algorithm=DSIGConstants::s_unicodeStrURI3DES_CBC, +#endif const unsigned char* keyBuffer=nullptr, unsigned int keyBufferSize=0, const xmltooling::Credential* credential=nullptr, diff --git a/xmltooling/encryption/impl/Encrypter.cpp b/xmltooling/encryption/impl/Encrypter.cpp index 3ee5da8..97583a7 100644 --- a/xmltooling/encryption/impl/Encrypter.cpp +++ b/xmltooling/encryption/impl/Encrypter.cpp @@ -239,6 +239,8 @@ EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, Key throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key."); if (!kencParams->m_algorithm) kencParams->m_algorithm = getKeyTransportAlgorithm(kencParams->m_credential, encParams.m_algorithm); + if (!kencParams->m_algorithm) + throw EncryptionException("Unable to derive a supported key encryption algorithm."); m_cipher->setKEK(kek->clone()); // ownership of this belongs to us, for some reason... @@ -276,6 +278,9 @@ EncryptedKey* Encrypter::encryptKey( const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact ) { + if (!kencParams.m_algorithm) + throw EncryptionException("KeyEncryptionParams structure did not include a key encryption algorithm."); + // Get a fresh cipher object and document. if (m_cipher) { @@ -326,25 +331,40 @@ EncryptedKey* Encrypter::encryptKey( const XMLCh* Encrypter::getKeyTransportAlgorithm(const Credential& credential, const XMLCh* encryptionAlg) { + XMLToolingConfig& conf = XMLToolingConfig::getConfig(); const char* alg = credential.getAlgorithm(); if (!alg || !strcmp(alg, "RSA")) { - if (XMLString::equals(encryptionAlg,DSIGConstants::s_unicodeStrURI3DES_CBC)) - return DSIGConstants::s_unicodeStrURIRSA_1_5; - else - return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1; + if (XMLString::equals(encryptionAlg,DSIGConstants::s_unicodeStrURI3DES_CBC)) { + if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_1_5, XMLToolingConfig::ALGTYPE_KEYENCRYPT)) + return DSIGConstants::s_unicodeStrURIRSA_1_5; + else if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, XMLToolingConfig::ALGTYPE_KEYENCRYPT)) + return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1; + } + else { + if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, XMLToolingConfig::ALGTYPE_KEYENCRYPT)) + return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1; + else if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_1_5, XMLToolingConfig::ALGTYPE_KEYENCRYPT)) + return DSIGConstants::s_unicodeStrURIRSA_1_5; + } } else if (!strcmp(alg, "AES")) { + const XMLCh* ret = nullptr; switch (credential.getKeySize()) { case 128: - return DSIGConstants::s_unicodeStrURIKW_AES128; + ret = DSIGConstants::s_unicodeStrURIKW_AES128; case 192: - return DSIGConstants::s_unicodeStrURIKW_AES192; + ret = DSIGConstants::s_unicodeStrURIKW_AES192; case 256: - return DSIGConstants::s_unicodeStrURIKW_AES256; + ret = DSIGConstants::s_unicodeStrURIKW_AES256; + default: + return nullptr; } + if (conf.isXMLAlgorithmSupported(ret, XMLToolingConfig::ALGTYPE_KEYENCRYPT)) + return ret; } else if (!strcmp(alg, "DESede")) { - return DSIGConstants::s_unicodeStrURIKW_3DES; + if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIKW_3DES, XMLToolingConfig::ALGTYPE_KEYENCRYPT)) + return DSIGConstants::s_unicodeStrURIKW_3DES; } return nullptr; diff --git a/xmltooling/internal.h b/xmltooling/internal.h index 193f3ce..a49e26b 100644 --- a/xmltooling/internal.h +++ b/xmltooling/internal.h @@ -112,13 +112,15 @@ namespace xmltooling { #ifndef XMLTOOLING_NO_XMLSEC XSECCryptoX509CRL* X509CRL() const; std::pair mapXMLAlgorithmToKeyAlgorithm(const XMLCh* xmlAlgorithm) const; - void registerXMLAlgorithm(const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size=0); - bool isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm); + void registerXMLAlgorithm( + const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size=0, XMLSecurityAlgorithmType type=ALGTYPE_UNK + ); + bool isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm, XMLSecurityAlgorithmType type=ALGTYPE_UNK); void registerXMLAlgorithms(); XSECProvider* m_xsecProvider; private: - typedef std::map< xstring,std::pair > algmap_t; + typedef std::map > > algmap_t; algmap_t m_algorithmMap; #endif -- 2.1.4