Add support for DEREncodedKeyValue.
authorcantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Wed, 9 Jun 2010 16:14:49 +0000 (16:14 +0000)
committercantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Wed, 9 Jun 2010 16:14:49 +0000 (16:14 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/branches/REL_1@759 de75baf8-a10c-0410-a50a-987c0e22f00f

config_win32.h
configure.ac
xmltooling/security/SecurityHelper.h
xmltooling/security/impl/InlineKeyResolver.cpp
xmltooling/security/impl/SecurityHelper.cpp
xmltoolingtest/InlineKeyResolverTest.h
xmltoolingtest/data/KeyInfo4.xml
xmltoolingtest/data/KeyInfo5.xml [new file with mode: 0644]

index f67756a..ed324c2 100644 (file)
@@ -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. */
index 40dd161..6e78970 100644 (file)
@@ -223,6 +223,16 @@ AC_TRY_COMPILE([#include <xercesc/dom/DOM.hpp>],
       [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 <xercesc/util/XMLString.hpp>],
+    [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]),,
index 2650013..7c045a9 100644 (file)
@@ -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);
     };
 };
 
index ab1d418..9c3471c 100644 (file)
@@ -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 <xercesc/util/XMLUniDefs.hpp>
 #include <xsec/dsig/DSIGKeyInfoX509.hpp>
 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
-#include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
-#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
-#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
+#include <xsec/enc/XSECCryptoX509.hpp>
+#include <xsec/enc/XSECCryptoKeyRSA.hpp>
+#include <xsec/enc/XSECCryptoKeyDSA.hpp>
 #include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/framework/XSECException.hpp>
 
@@ -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<KeyValue*>& keyValues = keyInfo->getKeyValues();
-    for (vector<KeyValue*>::const_iterator i=keyValues.begin(); i!=keyValues.end(); ++i) {
+    for (vector<KeyValue*>::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<DEREncodedKeyValue*>& derValues = keyInfo->getDEREncodedKeyValues();
+    for (vector<DEREncodedKeyValue*>::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;
index ddc62ac..4b87ac7 100644 (file)
 #include "util/NDC.h"
 
 #include <fstream>
+#include <openssl/evp.h>
 #include <openssl/pem.h>
 #include <openssl/pkcs12.h>
+#include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
+#include <xercesc/util/Base64.hpp>
 
 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<const XMLByte*>(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;
+}
index 0f6a8fa..d8e88d2 100644 (file)
@@ -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<KeyInfo> kiObject(dynamic_cast<KeyInfo*>(b->buildFromDocument(doc)));
+        TS_ASSERT(kiObject.get()!=nullptr);
+
+        auto_ptr<X509Credential> cred(dynamic_cast<X509Credential*>(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);
+    }
 };
index 90b011e..3b76883 100644 (file)
@@ -1,11 +1,11 @@
-<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ds11="http://www.w3.org/2009/xmldsig11#">\r
-    <ds:KeyValue>\r
-        <ds11:ECKeyValue>\r
-            <ds11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>\r
-            <ds11:PublicKey>\r
-            MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER9z9tFObV/MdgFT0IDEUq6b8VZFL\r
-            sj+qeNjJMVgEIrioShi5HfJfZq/aLuTvt5DZEybsFNC1Fit5cYx7+0DN3g==\r
-            </ds11:PublicKey>\r
-        </ds11:ECKeyValue>\r
-    </ds:KeyValue>\r
-</ds:KeyInfo>\r
+<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ds11="http://www.w3.org/2009/xmldsig11#">
+    <ds:KeyValue>
+        <ds11:ECKeyValue>
+            <ds11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>
+            <ds11:PublicKey>
+            MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER9z9tFObV/MdgFT0IDEUq6b8VZFL
+            sj+qeNjJMVgEIrioShi5HfJfZq/aLuTvt5DZEybsFNC1Fit5cYx7+0DN3g==
+            </ds11:PublicKey>
+        </ds11:ECKeyValue>
+    </ds:KeyValue>
+</ds:KeyInfo>
diff --git a/xmltoolingtest/data/KeyInfo5.xml b/xmltoolingtest/data/KeyInfo5.xml
new file mode 100644 (file)
index 0000000..2e5c27d
--- /dev/null
@@ -0,0 +1,8 @@
+<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ds11="http://www.w3.org/2009/xmldsig11#">
+    <ds11:DEREncodedKeyValue>
+    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQsVsByijs8ArbG2VIYc0I13Mi
+    hwO865fFKqAsru4Wis6xJiO7nZewei/s8YJ5lUc+M7MNTybFWFLfcxugAQvj+17c
+    eOk5P4eYDuoVi+FwcxVLisLDEWdEQdLAL+okLc+kwsh+OzgUiUjduIe3v74lENGb
+    SmLCaP6/AR656IiZNQIDAQAB
+    </ds11:DEREncodedKeyValue>
+</ds:KeyInfo>