Multi-line svn commit, see body.
[shibboleth/cpp-xmltooling.git] / xmltooling / signature / impl / InlineKeyResolver.cpp
index c34db20..9ad79df 100644 (file)
  */\r
 \r
 #include "internal.h"\r
-#include "signature/KeyResolver.h"\r
+#include "signature/CachingKeyResolver.h"\r
+#include "signature/KeyInfo.h"\r
 #include "util/NDC.h"\r
 #include "util/Threads.h"\r
+#include "util/XMLConstants.h"\r
+#include "validation/ValidatorSuite.h"\r
 \r
-#include <algorithm>\r
 #include <log4cpp/Category.hh>\r
 #include <xercesc/util/XMLUniDefs.hpp>\r
 #include <xsec/dsig/DSIGKeyInfoX509.hpp>\r
@@ -42,7 +44,7 @@ using namespace log4cpp;
 using namespace std;\r
 \r
 namespace xmlsignature {\r
-    class XMLTOOL_DLLLOCAL InlineKeyResolver : public KeyResolver\r
+    class XMLTOOL_DLLLOCAL InlineKeyResolver : public CachingKeyResolver\r
     {\r
     public:\r
         InlineKeyResolver(const DOMElement* e);\r
@@ -50,23 +52,36 @@ namespace xmlsignature {
 \r
         XSECCryptoKey* resolveKey(const KeyInfo* keyInfo) const;\r
         XSECCryptoKey* resolveKey(DSIGKeyInfoList* keyInfo) const;\r
-        vector<XSECCryptoX509*>::size_type resolveCertificates(const KeyInfo* keyInfo, vector<XSECCryptoX509*>& certs) const;\r
-        vector<XSECCryptoX509*>::size_type resolveCertificates(DSIGKeyInfoList* keyInfo, vector<XSECCryptoX509*>& certs) const;\r
+        vector<XSECCryptoX509*>::size_type resolveCertificates(const KeyInfo* keyInfo, ResolvedCertificates& certs) const;\r
+        vector<XSECCryptoX509*>::size_type resolveCertificates(DSIGKeyInfoList* keyInfo, ResolvedCertificates& certs) const;\r
+        XSECCryptoX509CRL* resolveCRL(const KeyInfo* keyInfo) const;\r
+        XSECCryptoX509CRL* resolveCRL(DSIGKeyInfoList* keyInfo) const;\r
+        \r
+        void clearCache() {\r
+            if (m_lock)\r
+                m_lock->wrlock();\r
+            m_cache.clear();\r
+            if (m_lock)\r
+                m_lock->unlock();\r
+        }\r
         \r
     private:\r
         struct XMLTOOL_DLLLOCAL CacheEntry {\r
-            CacheEntry() : m_key(NULL) {}\r
+            CacheEntry() : m_key(NULL), m_crl(NULL) {}\r
             ~CacheEntry() {\r
                 delete m_key;\r
                 for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup<XSECCryptoX509>());\r
+                delete m_crl;\r
             }\r
             XSECCryptoKey* m_key;\r
             vector<XSECCryptoX509*> m_certs;\r
+            XSECCryptoX509CRL* m_crl;\r
         };\r
 \r
         void _resolve(const KeyInfo* keyInfo, CacheEntry& entry) const;\r
         XSECCryptoKey* _resolveKey(const KeyInfo* keyInfo) const;\r
         vector<XSECCryptoX509*>::size_type _resolveCertificates(const KeyInfo* keyInfo, vector<XSECCryptoX509*>& certs) const;\r
+        XSECCryptoX509CRL* _resolveCRL(const KeyInfo* keyInfo) const;\r
 \r
         RWLock* m_lock;\r
         mutable map<const KeyInfo*,CacheEntry> m_cache;\r
@@ -89,7 +104,7 @@ InlineKeyResolver::InlineKeyResolver(const DOMElement* e) : m_lock(NULL)
 \r
 InlineKeyResolver::~InlineKeyResolver()\r
 {\r
-    m_cache.clear();\r
+    clearCache();\r
     delete m_lock;\r
 }\r
 \r
@@ -99,6 +114,7 @@ void InlineKeyResolver::_resolve(const KeyInfo* keyInfo, CacheEntry& entry) cons
         entry.m_key = entry.m_certs.front()->clonePublicKey();\r
     else\r
         entry.m_key = _resolveKey(keyInfo);\r
+    entry.m_crl = _resolveCRL(keyInfo);\r
 }\r
 \r
 XSECCryptoKey* InlineKeyResolver::_resolveKey(const KeyInfo* keyInfo) const\r
@@ -108,6 +124,9 @@ XSECCryptoKey* InlineKeyResolver::_resolveKey(const KeyInfo* keyInfo) const
 #endif\r
     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver");\r
 \r
+    if (!keyInfo)\r
+        return NULL;\r
+\r
     // Check for ds:X509Data\r
     const vector<X509Data*>& x509Datas=keyInfo->getX509Datas();\r
     for (vector<X509Data*>::const_iterator j=x509Datas.begin(); j!=x509Datas.end(); ++j) {\r
@@ -139,7 +158,7 @@ XSECCryptoKey* InlineKeyResolver::_resolveKey(const KeyInfo* keyInfo) const
     const vector<KeyValue*>& keyValues = keyInfo->getKeyValues();\r
     for (vector<KeyValue*>::const_iterator i=keyValues.begin(); i!=keyValues.end(); ++i) {\r
         try {\r
-            KeyInfoSchemaValidators.validate(*i);    // see if it's a "valid" key\r
+            SchemaValidators.validate(*i);    // see if it's a "valid" key\r
             RSAKeyValue* rsakv = (*i)->getRSAKeyValue();\r
             if (rsakv) {\r
                 log.debug("resolving ds:RSAKeyValue");\r
@@ -196,6 +215,9 @@ vector<XSECCryptoX509*>::size_type InlineKeyResolver::_resolveCertificates(
 #endif\r
     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver");\r
 \r
+    if (!keyInfo)\r
+        return 0;\r
+\r
     // Check for ds:X509Data\r
     const vector<X509Data*>& x509Datas=keyInfo->getX509Datas();\r
     for (vector<X509Data*>::const_iterator j=x509Datas.begin(); certs.empty() && j!=x509Datas.end(); ++j) {\r
@@ -228,6 +250,45 @@ vector<XSECCryptoX509*>::size_type InlineKeyResolver::_resolveCertificates(
     return certs.size();\r
 }\r
 \r
+XSECCryptoX509CRL* InlineKeyResolver::_resolveCRL(const KeyInfo* keyInfo) const\r
+{\r
+#ifdef _DEBUG\r
+    NDC ndc("_resolveCRL");\r
+#endif\r
+    Category& log=Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver");\r
+\r
+    if (!keyInfo)\r
+        return NULL;\r
+\r
+    // Check for ds:X509Data\r
+    const vector<X509Data*>& x509Datas=keyInfo->getX509Datas();\r
+    for (vector<X509Data*>::const_iterator j=x509Datas.begin(); j!=x509Datas.end(); ++j) {\r
+        const vector<X509CRL*> x509CRLs=const_cast<const X509Data*>(*j)->getX509CRLs();\r
+        for (vector<X509CRL*>::const_iterator k=x509CRLs.begin(); k!=x509CRLs.end(); ++k) {\r
+            try {\r
+                auto_ptr_char x((*k)->getValue());\r
+                if (!x.get()) {\r
+                    log.warn("skipping empty ds:X509CRL");\r
+                }\r
+                else {\r
+                    log.debug("resolving ds:X509CRL");\r
+                    auto_ptr<XSECCryptoX509CRL> crl(XMLToolingConfig::getConfig().X509CRL());\r
+                    crl->loadX509CRLBase64Bin(x.get(), strlen(x.get()));\r
+                    return crl.release();\r
+                }\r
+            }\r
+            catch(XSECException& e) {\r
+                auto_ptr_char temp(e.getMsg());\r
+                log.error("caught XML-Security exception loading certificate: %s", temp.get());\r
+            }\r
+            catch(XSECCryptoException& e) {\r
+                log.error("caught XML-Security exception loading certificate: %s", e.getMsg());\r
+            }\r
+        }\r
+    }\r
+    return NULL;\r
+}\r
+\r
 XSECCryptoKey* InlineKeyResolver::resolveKey(const KeyInfo* keyInfo) const\r
 {\r
     // Caching?\r
@@ -257,8 +318,37 @@ XSECCryptoKey* InlineKeyResolver::resolveKey(const KeyInfo* keyInfo) const
     return _resolveKey(keyInfo);\r
 }\r
 \r
+XSECCryptoX509CRL* InlineKeyResolver::resolveCRL(const KeyInfo* keyInfo) const\r
+{\r
+    // Caching?\r
+    if (m_lock) {\r
+        // Get read lock.\r
+        m_lock->rdlock();\r
+        map<const KeyInfo*,CacheEntry>::iterator i=m_cache.find(keyInfo);\r
+        if (i != m_cache.end()) {\r
+            // Found in cache, so just return the results.\r
+            SharedLock locker(m_lock,false);\r
+            return i->second.m_crl ? i->second.m_crl->clone() : NULL;\r
+        }\r
+        else {\r
+            // Elevate lock.\r
+            m_lock->unlock();\r
+            m_lock->wrlock();\r
+            SharedLock locker(m_lock,false);\r
+            // Recheck cache.\r
+            i=m_cache.find(keyInfo);\r
+            if (i == m_cache.end()) {\r
+                i = m_cache.insert(make_pair(keyInfo,CacheEntry())).first;\r
+                _resolve(i->first, i->second);\r
+            }\r
+            return i->second.m_crl ? i->second.m_crl->clone() : NULL;\r
+        }\r
+    }\r
+    return _resolveCRL(keyInfo);\r
+}\r
+\r
 vector<XSECCryptoX509*>::size_type InlineKeyResolver::resolveCertificates(\r
-    const KeyInfo* keyInfo, vector<XSECCryptoX509*>& certs\r
+    const KeyInfo* keyInfo, ResolvedCertificates& certs\r
     ) const\r
 {\r
     // Caching?\r
@@ -269,8 +359,9 @@ vector<XSECCryptoX509*>::size_type InlineKeyResolver::resolveCertificates(
         if (i != m_cache.end()) {\r
             // Found in cache, so just return the results.\r
             SharedLock locker(m_lock,false);\r
-            certs.assign(i->second.m_certs.begin(), i->second.m_certs.end());\r
-            return certs.size();\r
+            accessCertificates(certs).assign(i->second.m_certs.begin(), i->second.m_certs.end());\r
+            accessOwned(certs) = false;\r
+            return accessCertificates(certs).size();\r
         }\r
         else {\r
             // Elevate lock.\r
@@ -283,19 +374,24 @@ vector<XSECCryptoX509*>::size_type InlineKeyResolver::resolveCertificates(
                 i = m_cache.insert(make_pair(keyInfo,CacheEntry())).first;\r
                 _resolve(i->first, i->second);\r
             }\r
-            certs.assign(i->second.m_certs.begin(), i->second.m_certs.end());\r
-            return certs.size();\r
+            accessCertificates(certs).assign(i->second.m_certs.begin(), i->second.m_certs.end());\r
+            accessOwned(certs) = false;\r
+            return accessCertificates(certs).size();\r
         }\r
     }\r
-    return _resolveCertificates(keyInfo, certs);\r
+    accessOwned(certs) = true;\r
+    return _resolveCertificates(keyInfo, accessCertificates(certs));\r
 }\r
 \r
 XSECCryptoKey* InlineKeyResolver::resolveKey(DSIGKeyInfoList* keyInfo) const\r
 {\r
 #ifdef _DEBUG\r
-    NDC ndc("_resolveKey");\r
+    NDC ndc("resolveKey");\r
 #endif\r
 \r
+    if (!keyInfo)\r
+        return NULL;\r
+\r
     // Default resolver handles RSA/DSAKeyValue and X509Certificate elements.\r
     try {\r
         XSECKeyInfoResolverDefault def;\r
@@ -312,19 +408,56 @@ XSECCryptoKey* InlineKeyResolver::resolveKey(DSIGKeyInfoList* keyInfo) const
 }\r
 \r
 vector<XSECCryptoX509*>::size_type InlineKeyResolver::resolveCertificates(\r
-    DSIGKeyInfoList* keyInfo, vector<XSECCryptoX509*>& certs\r
+    DSIGKeyInfoList* keyInfo, ResolvedCertificates& certs\r
     ) const\r
 {\r
-    certs.clear();\r
+    accessCertificates(certs).clear();\r
+    accessOwned(certs) = false;\r
+\r
+    if (!keyInfo)\r
+        return 0;\r
+\r
        DSIGKeyInfoList::size_type sz = keyInfo->getSize();\r
-    for (DSIGKeyInfoList::size_type i=0; certs.empty() && i<sz; ++i) {\r
+    for (DSIGKeyInfoList::size_type i=0; accessCertificates(certs).empty() && i<sz; ++i) {\r
         if (keyInfo->item(i)->getKeyInfoType()==DSIGKeyInfo::KEYINFO_X509) {\r
             DSIGKeyInfoX509* x509 = static_cast<DSIGKeyInfoX509*>(keyInfo->item(i));\r
             int count = x509->getCertificateListSize();\r
             for (int j=0; j<count; ++j) {\r
-                certs.push_back(x509->getCertificateCryptoItem(j));\r
+                accessCertificates(certs).push_back(x509->getCertificateCryptoItem(j));\r
             }\r
         }\r
     }\r
-    return certs.size();\r
+    return accessCertificates(certs).size();\r
+}\r
+\r
+XSECCryptoX509CRL* InlineKeyResolver::resolveCRL(DSIGKeyInfoList* keyInfo) const\r
+{\r
+#ifdef _DEBUG\r
+    NDC ndc("resolveCRL");\r
+#endif\r
+\r
+    if (!keyInfo)\r
+        return NULL;\r
+\r
+    DSIGKeyInfoList::size_type sz = keyInfo->getSize();\r
+    for (DSIGKeyInfoList::size_type i=0; i<sz; ++i) {\r
+        if (keyInfo->item(i)->getKeyInfoType()==DSIGKeyInfo::KEYINFO_X509) {\r
+            auto_ptr_char buf(static_cast<DSIGKeyInfoX509*>(keyInfo->item(i))->getX509CRL());\r
+            if (buf.get()) {\r
+                try {\r
+                    auto_ptr<XSECCryptoX509CRL> crlobj(XMLToolingConfig::getConfig().X509CRL());\r
+                    crlobj->loadX509CRLBase64Bin(buf.get(), strlen(buf.get()));\r
+                    return crlobj.release();\r
+                }\r
+                catch(XSECException& e) {\r
+                    auto_ptr_char temp(e.getMsg());\r
+                    Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading CRL: %s", temp.get());\r
+                }\r
+                catch(XSECCryptoException& e) {\r
+                    Category::getInstance(XMLTOOLING_LOGCAT".KeyResolver").error("caught XML-Security exception loading CRL: %s", e.getMsg());\r
+                }\r
+            }\r
+        }\r
+    }\r
+    return NULL;\r
 }\r