From eab22660b1e5678870b4750af89a963476e38c3f Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Wed, 9 Jun 2010 16:14:49 +0000 Subject: [PATCH] Add support for DEREncodedKeyValue. --- config_win32.h | 2 + configure.ac | 10 ++++ xmltooling/security/SecurityHelper.h | 20 +++++++- xmltooling/security/impl/InlineKeyResolver.cpp | 27 ++++++++-- xmltooling/security/impl/SecurityHelper.cpp | 70 ++++++++++++++++++++++++++ xmltoolingtest/InlineKeyResolverTest.h | 19 +++++++ xmltoolingtest/data/KeyInfo4.xml | 22 ++++---- xmltoolingtest/data/KeyInfo5.xml | 8 +++ 8 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 xmltoolingtest/data/KeyInfo5.xml diff --git a/config_win32.h b/config_win32.h index f67756a..ed324c2 100644 --- a/config_win32.h +++ b/config_win32.h @@ -77,6 +77,8 @@ # define XMLTOOLING_XERCESC_BOOLSETIDATTRIBUTE 1 # define XMLTOOLING_XERCESC_64BITSAFE 1 # define XMLTOOLING_XERCESC_INPUTSTREAM_HAS_CONTENTTYPE 1 +#else +# define XMLTOOLING_XERCESC_HAS_XMLBYTE_RELEASE #endif /* Define to 1 if you have the `xsecsize_t' type. */ diff --git a/configure.ac b/configure.ac index 40dd161..6e78970 100644 --- a/configure.ac +++ b/configure.ac @@ -223,6 +223,16 @@ AC_TRY_COMPILE([#include ], [AC_DEFINE([XMLTOOLING_XERCESC_BOOLSETIDATTRIBUTE], [1], [Define to 1 if Xerces DOM ID methods take extra parameter.])], [AC_MSG_RESULT([no])]) +AC_MSG_CHECKING([whether Xerces XMLString::release(XMLByte**) exists]) +AC_TRY_COMPILE([#include ], + [using namespace XERCES_CPP_NAMESPACE; + XMLByte* buf=NULL; + XMLString::release(&buf); + ], + [AC_MSG_RESULT([yes])] + [AC_DEFINE([XMLTOOLING_XERCESC_HAS_XMLBYTE_RELEASE], [1], [Define to 1 if Xerces XMLString includes XMLByte release.])], + [AC_MSG_RESULT([no])]) + # XML-Security settings AC_ARG_WITH(xmlsec, AC_HELP_STRING([--with-xmlsec=PATH], [where xmlsec is installed]),, diff --git a/xmltooling/security/SecurityHelper.h b/xmltooling/security/SecurityHelper.h index 2650013..7c045a9 100644 --- a/xmltooling/security/SecurityHelper.h +++ b/xmltooling/security/SecurityHelper.h @@ -200,7 +200,7 @@ namespace xmltooling { /** * @deprecated - * Returns the base64-encoded DER encoding of a certifiate's public key in SubjectPublicKeyInfo format. + * Returns the base64-encoded DER encoding of a certificate's public key in SubjectPublicKeyInfo format. * * @param cert the certificate's key to encode * @param hash if true, the DER encoded data is hashed with SHA-1 before base64 encoding @@ -208,6 +208,24 @@ namespace xmltooling { * @return the base64 encoded key value */ static std::string getDEREncoding(const XSECCryptoX509& cert, bool hash=false, bool nowrap=true); + + /** + * Decodes a DER-encoded public key. + * + * @param buf DER encoded data + * @param buflen length of data in bytes + * @param base64 true iff DER is base64-encoded + * @return the decoded public key, or nullptr + */ + static XSECCryptoKey* fromDEREncoding(const char* buf, unsigned long buflen, bool base64=true); + + /** + * Decodes a base64-encoded and DER-encoded public key. + * + * @param buf base64 and DER encoded data + * @return the decoded public key, or nullptr + */ + static XSECCryptoKey* fromDEREncoding(const XMLCh* buf); }; }; diff --git a/xmltooling/security/impl/InlineKeyResolver.cpp b/xmltooling/security/impl/InlineKeyResolver.cpp index ab1d418..9c3471c 100644 --- a/xmltooling/security/impl/InlineKeyResolver.cpp +++ b/xmltooling/security/impl/InlineKeyResolver.cpp @@ -25,6 +25,7 @@ #include "security/BasicX509Credential.h" #include "security/KeyInfoCredentialContext.h" #include "security/KeyInfoResolver.h" +#include "security/SecurityHelper.h" #include "security/XSECCryptoX509CRL.h" #include "signature/KeyInfo.h" #include "signature/Signature.h" @@ -36,9 +37,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -72,8 +73,10 @@ namespace xmltooling { if (ret) { ret->setId(nullptr); ret->getRetrievalMethods().clear(); + ret->getKeyInfoReferences().clear(); if (compact) { ret->getKeyValues().clear(); + ret->getDEREncodedKeyValues().clear(); ret->getSPKIDatas().clear(); ret->getPGPDatas().clear(); ret->getUnknownXMLObjects().clear(); @@ -81,6 +84,7 @@ namespace xmltooling { for (VectorOf(X509Data)::size_type pos = 0; pos < x509Datas.size();) { x509Datas[pos]->getX509Certificates().clear(); x509Datas[pos]->getX509CRLs().clear(); + x509Datas[pos]->getOCSPResponses().clear(); x509Datas[pos]->getUnknownXMLObjects().clear(); if (x509Datas[pos]->hasChildren()) ++pos; @@ -243,7 +247,7 @@ bool InlineCredential::resolveKey(const KeyInfo* keyInfo, bool followRefs) // Check for ds:KeyValue const vector& keyValues = keyInfo->getKeyValues(); - for (vector::const_iterator i=keyValues.begin(); i!=keyValues.end(); ++i) { + for (vector::const_iterator i = keyValues.begin(); i != keyValues.end(); ++i) { try { SchemaValidators.validate(*i); // see if it's a "valid" key RSAKeyValue* rsakv = (*i)->getRSAKeyValue(); @@ -278,6 +282,10 @@ bool InlineCredential::resolveKey(const KeyInfo* keyInfo, bool followRefs) m_key = dsa.release(); return true; } + ECKeyValue* eckv = (*i)->getECKeyValue(); + if (eckv) { + log.warn("skipping ds11:ECKeyValue, not yet supported"); + } } catch (ValidationException& ex) { log.warn("skipping invalid ds:KeyValue (%s)", ex.what()); @@ -291,6 +299,17 @@ bool InlineCredential::resolveKey(const KeyInfo* keyInfo, bool followRefs) } } + // Check for ds11:DEREncodedKeyValue + const vector& derValues = keyInfo->getDEREncodedKeyValues(); + for (vector::const_iterator j = derValues.begin(); j != derValues.end(); ++j) { + log.debug("resolving ds11:DEREncodedKeyValue"); + m_key = SecurityHelper::fromDEREncoding((*j)->getValue()); + if (m_key) + return true; + log.warn("failed to resolve ds11:DEREncodedKeyValue"); + } + + if (followRefs) { // Check for KeyInfoReference. const XMLCh* fragID=NULL; diff --git a/xmltooling/security/impl/SecurityHelper.cpp b/xmltooling/security/impl/SecurityHelper.cpp index ddc62ac..4b87ac7 100644 --- a/xmltooling/security/impl/SecurityHelper.cpp +++ b/xmltooling/security/impl/SecurityHelper.cpp @@ -30,11 +30,14 @@ #include "util/NDC.h" #include +#include #include #include +#include #include #include #include +#include using namespace xmltooling::logging; using namespace xmltooling; @@ -726,3 +729,70 @@ string SecurityHelper::getDEREncoding(const Credential& cred, bool hash, bool no { return getDEREncoding(cred, hash ? "SHA1" : nullptr, nowrap); } + +XSECCryptoKey* SecurityHelper::fromDEREncoding(const char* buf, unsigned long buflen, bool base64) +{ + xsecsize_t x; + XMLByte* decoded=nullptr; + if (base64) { + decoded = xercesc::Base64::decode(reinterpret_cast(buf), &x); + if (!decoded) { + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("base64 decode failed"); + return nullptr; + } + } + + BIO* b = BIO_new_mem_buf((void*)(base64 ? (char*)decoded : buf), (base64 ? x : buflen)); + EVP_PKEY* pkey = d2i_PUBKEY_bio(b, nullptr); + BIO_free(b); + if (base64) { +#ifdef XMLTOOLING_XERCESC_HAS_XMLBYTE_RELEASE + XMLString::release(&decoded); +#else + XMLString::release((char**)&decoded); +#endif + } + + if (pkey) { + // Now map it to an XSEC wrapper. + XSECCryptoKey* ret = nullptr; + try { + switch (pkey->type) { + case EVP_PKEY_RSA: + ret = new OpenSSLCryptoKeyRSA(pkey); + break; + + case EVP_PKEY_DSA: + ret = new OpenSSLCryptoKeyDSA(pkey); + break; + + default: + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("unsupported public key type"); + } + } + catch (XSECCryptoException& ex) { + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error(ex.getMsg()); + } + EVP_PKEY_free(pkey); + return ret; + } + + return nullptr; +} + +XSECCryptoKey* SecurityHelper::fromDEREncoding(const XMLCh* buf) +{ + xsecsize_t x; + XMLByte* decoded = xercesc::Base64::decodeToXMLByte(buf, &x); + if (!decoded) { + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("base64 decode failed"); + return nullptr; + } + XSECCryptoKey* ret = fromDEREncoding((const char*)decoded, x, false); +#ifdef XMLTOOLING_XERCESC_HAS_XMLBYTE_RELEASE + XMLString::release(&decoded); +#else + XMLString::release((char**)&decoded); +#endif + return ret; +} diff --git a/xmltoolingtest/InlineKeyResolverTest.h b/xmltoolingtest/InlineKeyResolverTest.h index 0f6a8fa..d8e88d2 100644 --- a/xmltoolingtest/InlineKeyResolverTest.h +++ b/xmltoolingtest/InlineKeyResolverTest.h @@ -60,4 +60,23 @@ public: TSM_ASSERT_EQUALS("Wrong certificate count.", cred->getEntityCertificateChain().size(), 1); TSM_ASSERT_EQUALS("Wrong CRL count.", cred->getCRLs().size(), 3); } + + void testDER() { + string path=data_path + "KeyInfo5.xml"; + ifstream fs(path.c_str()); + DOMDocument* doc=XMLToolingConfig::getConfig().getValidatingParser().parse(fs); + TS_ASSERT(doc!=nullptr); + const XMLObjectBuilder* b = XMLObjectBuilder::getBuilder(doc->getDocumentElement()); + TS_ASSERT(b!=nullptr); + auto_ptr kiObject(dynamic_cast(b->buildFromDocument(doc))); + TS_ASSERT(kiObject.get()!=nullptr); + + auto_ptr cred(dynamic_cast(m_resolver->resolve(kiObject.get()))); + TSM_ASSERT("Unable to resolve KeyInfo into Credential.", cred.get()!=nullptr); + + TSM_ASSERT("Unable to resolve public key.", cred->getPublicKey()!=nullptr); + TSM_ASSERT_EQUALS("Unexpected key type.", cred->getPublicKey()->getKeyType(), XSECCryptoKey::KEY_RSA_PUBLIC); + TSM_ASSERT_EQUALS("Wrong certificate count.", cred->getEntityCertificateChain().size(), 0); + TSM_ASSERT_EQUALS("Wrong CRL count.", cred->getCRLs().size(), 0); + } }; diff --git a/xmltoolingtest/data/KeyInfo4.xml b/xmltoolingtest/data/KeyInfo4.xml index 90b011e..3b76883 100644 --- a/xmltoolingtest/data/KeyInfo4.xml +++ b/xmltoolingtest/data/KeyInfo4.xml @@ -1,11 +1,11 @@ - - - - - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER9z9tFObV/MdgFT0IDEUq6b8VZFL - sj+qeNjJMVgEIrioShi5HfJfZq/aLuTvt5DZEybsFNC1Fit5cYx7+0DN3g== - - - - + + + + + + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER9z9tFObV/MdgFT0IDEUq6b8VZFL + sj+qeNjJMVgEIrioShi5HfJfZq/aLuTvt5DZEybsFNC1Fit5cYx7+0DN3g== + + + + diff --git a/xmltoolingtest/data/KeyInfo5.xml b/xmltoolingtest/data/KeyInfo5.xml new file mode 100644 index 0000000..2e5c27d --- /dev/null +++ b/xmltoolingtest/data/KeyInfo5.xml @@ -0,0 +1,8 @@ + + + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQsVsByijs8ArbG2VIYc0I13Mi + hwO865fFKqAsru4Wis6xJiO7nZewei/s8YJ5lUc+M7MNTybFWFLfcxugAQvj+17c + eOk5P4eYDuoVi+FwcxVLisLDEWdEQdLAL+okLc+kwsh+OzgUiUjduIe3v74lENGb + SmLCaP6/AR656IiZNQIDAQAB + + -- 2.1.4