Removed ValidatingXMLObject interface and implementations.
[shibboleth/cpp-xmltooling.git] / xmltooling / signature / impl / XMLSecSignatureImpl.cpp
index b561814..2082939 100644 (file)
@@ -36,6 +36,7 @@
 #include <xsec/enc/XSECCryptoException.hpp>\r
 #include <xsec/framework/XSECException.hpp>\r
 \r
+using namespace xmlsignature;\r
 using namespace xmltooling;\r
 using namespace log4cpp;\r
 using namespace std;\r
@@ -45,37 +46,65 @@ using namespace std;
     #pragma warning( disable : 4250 4251 )\r
 #endif\r
 \r
-namespace xmltooling {\r
+namespace xmlsignature {\r
     \r
     class XMLTOOL_DLLLOCAL XMLSecSignatureImpl : public UnknownElementImpl, public virtual Signature\r
     {\r
     public:\r
         XMLSecSignatureImpl() : UnknownElementImpl(XMLConstants::XMLSIG_NS, Signature::LOCAL_NAME, XMLConstants::XMLSIG_PREFIX),\r
-            m_signature(NULL), m_c14n(NULL), m_sm(NULL) {}\r
+            m_signature(NULL), m_c14n(NULL), m_sm(NULL), m_key(NULL), m_keyInfo(NULL), m_reference(NULL) {}\r
         virtual ~XMLSecSignatureImpl();\r
         \r
-        void releaseDOM();\r
+        void releaseDOM() const;\r
+        void releaseChildrenDOM(bool propagateRelease=true) const {\r
+            if (m_keyInfo) {\r
+                m_keyInfo->releaseDOM();\r
+                if (propagateRelease)\r
+                    m_keyInfo->releaseChildrenDOM();\r
+            }\r
+        }\r
         XMLObject* clone() const;\r
+        Signature* cloneSignature() const;\r
 \r
-        DOMElement* marshall(DOMDocument* document=NULL, MarshallingContext* ctx=NULL) const;\r
-        DOMElement* marshall(DOMElement* parentElement, MarshallingContext* ctx=NULL) const;\r
+        DOMElement* marshall(DOMDocument* document=NULL, const vector<Signature*>* sigs=NULL) const;\r
+        DOMElement* marshall(DOMElement* parentElement, const vector<Signature*>* sigs=NULL) const;\r
         XMLObject* unmarshall(DOMElement* element, bool bindDocument=false);\r
         \r
         // Getters\r
         const XMLCh* getCanonicalizationMethod() const { return m_c14n ? m_c14n : DSIGConstants::s_unicodeStrURIEXC_C14N_NOC; }\r
         const XMLCh* getSignatureAlgorithm() const { return m_sm ? m_sm : DSIGConstants::s_unicodeStrURIRSA_SHA1; }\r
-\r
+        KeyInfo* getKeyInfo() const { return m_keyInfo; }\r
+        ContentReference* getContentReference() const { return m_reference; }\r
+        DSIGSignature* getXMLSignature() const { return m_signature; }\r
+        \r
         // Setters\r
         void setCanonicalizationMethod(const XMLCh* c14n) { m_c14n = prepareForAssignment(m_c14n,c14n); }\r
         void setSignatureAlgorithm(const XMLCh* sm) { m_sm = prepareForAssignment(m_sm,sm); }\r
-\r
-        void sign(const SigningContext& ctx);\r
-        void verify(const VerifyingContext& ctx) const;\r
+        void setSigningKey(XSECCryptoKey* signingKey) {\r
+            delete m_key;\r
+            m_key=signingKey;\r
+            if (m_key)\r
+                releaseThisandParentDOM();\r
+        }\r
+        void setKeyInfo(KeyInfo* keyInfo) {\r
+            prepareForAssignment(m_keyInfo, keyInfo);\r
+            m_keyInfo=keyInfo;\r
+        }\r
+        void setContentReference(ContentReference* reference) {\r
+            delete m_reference;\r
+            m_reference=reference;\r
+            releaseThisandParentDOM();\r
+        }\r
+        \r
+        void sign();\r
 \r
     private:\r
         mutable DSIGSignature* m_signature;\r
         XMLCh* m_c14n;\r
         XMLCh* m_sm;\r
+        XSECCryptoKey* m_key;\r
+        KeyInfo* m_keyInfo;\r
+        ContentReference* m_reference;\r
     };\r
     \r
 };\r
@@ -92,26 +121,40 @@ XMLSecSignatureImpl::~XMLSecSignatureImpl()
 \r
     XMLString::release(&m_c14n);\r
     XMLString::release(&m_sm);\r
+    delete m_key;\r
+    delete m_keyInfo;\r
+    delete m_reference;\r
 }\r
 \r
-void XMLSecSignatureImpl::releaseDOM()\r
+void XMLSecSignatureImpl::releaseDOM() const\r
 {\r
-    // This should save off the DOM\r
-    UnknownElementImpl::releaseDOM();\r
-    \r
-    // Release the associated signature.\r
-    if (m_signature) {\r
-        XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(m_signature);\r
-        m_signature=NULL;\r
+    if (getDOM()) {\r
+        // This should save off the DOM\r
+        UnknownElementImpl::releaseDOM();\r
+        \r
+        // Release the associated signature.\r
+        if (m_signature) {\r
+            XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(m_signature);\r
+            m_signature=NULL;\r
+        }\r
     }\r
 }\r
 \r
 XMLObject* XMLSecSignatureImpl::clone() const\r
 {\r
+    return cloneSignature();\r
+}\r
+\r
+Signature* XMLSecSignatureImpl::cloneSignature() const\r
+{\r
     XMLSecSignatureImpl* ret=new XMLSecSignatureImpl();\r
 \r
     ret->m_c14n=XMLString::replicate(m_c14n);\r
     ret->m_sm=XMLString::replicate(m_sm);\r
+    if (m_key)\r
+        ret->m_key=m_key->clone();\r
+    if (m_keyInfo)\r
+        ret->m_keyInfo=m_keyInfo->cloneKeyInfo();\r
 \r
     // If there's no XML locally, serialize this object into the new one, otherwise just copy it over.\r
     if (m_xml.empty())\r
@@ -122,33 +165,24 @@ XMLObject* XMLSecSignatureImpl::clone() const
     return ret;\r
 }\r
 \r
-class _addcert : public std::binary_function<DSIGKeyInfoX509*,XSECCryptoX509*,void> {\r
-public:\r
-    void operator()(DSIGKeyInfoX509* bag, XSECCryptoX509* cert) const {\r
-        safeBuffer& buf=cert->getDEREncodingSB();\r
-        bag->appendX509Certificate(buf.sbStrToXMLCh());\r
-    }\r
-};\r
-\r
-void XMLSecSignatureImpl::sign(const SigningContext& ctx)\r
+void XMLSecSignatureImpl::sign()\r
 {\r
     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Signature");\r
     log.debug("applying signature");\r
 \r
     if (!m_signature)\r
         throw SignatureException("Only a marshalled Signature object can be signed.");\r
+    else if (!m_key)\r
+        throw SignatureException("No signing key available for signature creation.");\r
+    else if (!m_reference)\r
+        throw SignatureException("No ContentReference object set for signature creation.");\r
 \r
     try {\r
-        log.debug("creating signature content");\r
-        ctx.createSignature(m_signature);\r
-        const std::vector<XSECCryptoX509*>& certs=ctx.getX509Certificates();\r
-        if (!certs.empty()) {\r
-            DSIGKeyInfoX509* x509Data=m_signature->appendX509Data();\r
-            for_each(certs.begin(),certs.end(),bind1st(_addcert(),x509Data));\r
-        }\r
+        log.debug("creating signature reference(s)");\r
+        m_reference->createReferences(m_signature);\r
         \r
         log.debug("computing signature");\r
-        m_signature->setSigningKey(ctx.getSigningKey());\r
+        m_signature->setSigningKey(m_key->clone());\r
         m_signature->sign();\r
     }\r
     catch(XSECException& e) {\r
@@ -160,27 +194,7 @@ void XMLSecSignatureImpl::sign(const SigningContext& ctx)
     }\r
 }\r
 \r
-void XMLSecSignatureImpl::verify(const VerifyingContext& ctx) const\r
-{\r
-    Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Signature");\r
-    log.debug("verifying signature");\r
-\r
-    if (!m_signature)\r
-        throw SignatureException("Only a marshalled Signature object can be verified.");\r
-\r
-    try {\r
-        ctx.verifySignature(m_signature);\r
-    }\r
-    catch(XSECException& e) {\r
-        auto_ptr_char temp(e.getMsg());\r
-        throw SignatureException(string("Caught an XMLSecurity exception verifying signature: ") + temp.get());\r
-    }\r
-    catch(XSECCryptoException& e) {\r
-        throw SignatureException(string("Caught an XMLSecurity exception verifying signature: ") + e.getMsg());\r
-    }\r
-}\r
-\r
-DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, MarshallingContext* ctx) const\r
+DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector<Signature*>* sigs) const\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("marshall");\r
@@ -199,32 +213,13 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, MarshallingCont
             return cachedDOM;\r
         }\r
         \r
-        // We have a DOM but it doesn't match the document we were given, so we import\r
-        // it into the new document.\r
-        cachedDOM=static_cast<DOMElement*>(document->importNode(cachedDOM, true));\r
-\r
-        try {\r
-            XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(m_signature);\r
-            m_signature=NULL;\r
-            m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(\r
-                document, cachedDOM\r
-                );\r
-            m_signature->load();\r
-        }\r
-        catch(XSECException& e) {\r
-            auto_ptr_char temp(e.getMsg());\r
-            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());\r
-        }\r
-        catch(XSECCryptoException& e) {\r
-            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());\r
-        }\r
-\r
-        // Recache the DOM.\r
-        setDocumentElement(document, cachedDOM);\r
-        log.debug("caching imported DOM for Signature");\r
-        setDOM(cachedDOM, false);\r
-        releaseParentDOM(true);\r
-        return cachedDOM;\r
+        // We have a DOM but it doesn't match the document we were given. This both sucks and blows.\r
+        // Without an adoptNode option to maintain the child pointers, we have to either import the\r
+        // DOM while somehow reassigning all the nested references (which amounts to a complete\r
+        // *unmarshall* operation), or we just release the existing DOM and hope that we can get\r
+        // it back. This depends on all objects being able to preserve their DOM at all costs.\r
+        releaseChildrenDOM(true);\r
+        releaseDOM();\r
     }\r
     \r
     // If we get here, we didn't have a usable DOM.\r
@@ -245,7 +240,7 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, MarshallingCont
         MemBufInputSource src(reinterpret_cast<const XMLByte*>(m_xml.c_str()),m_xml.length(),"XMLSecSignatureImpl");\r
         Wrapper4InputSource dsrc(&src,false);\r
         log.debug("parsing Signature XML back into DOM tree");\r
-        DOMDocument* internalDoc=XMLToolingInternalConfig::getInternalConfig().m_parserPool->parse(dsrc);\r
+        DOMDocument* internalDoc=XMLToolingConfig::getConfig().getParser().parse(dsrc);\r
         if (document) {\r
             // The caller insists on using his own document, so we now have to import the thing\r
             // into it. Then we're just dumping the one we built.\r
@@ -280,6 +275,11 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, MarshallingCont
         }\r
     }\r
     \r
+    // Marshall KeyInfo data.\r
+    if (m_keyInfo && (!m_signature->getKeyInfoList() || m_signature->getKeyInfoList()->isEmpty())) {\r
+        m_keyInfo->marshall(cachedDOM);\r
+    }\r
+\r
     // Recache the DOM and clear the serialized copy.\r
     setDocumentElement(document, cachedDOM);\r
     log.debug("caching DOM for Signature (document is %sbound)", bindDocument ? "" : "not ");\r
@@ -289,7 +289,7 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, MarshallingCont
     return cachedDOM;\r
 }\r
 \r
-DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, MarshallingContext* ctx) const\r
+DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, const vector<Signature*>* sigs) const\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("marshall");\r
@@ -302,37 +302,20 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, Marshalling
     if (cachedDOM) {\r
         if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) {\r
             log.debug("Signature has a usable cached DOM, reusing it");\r
-            parentElement->appendChild(cachedDOM);\r
-            releaseParentDOM(true);\r
+            if (parentElement!=cachedDOM->getParentNode()) {\r
+                parentElement->appendChild(cachedDOM);\r
+                releaseParentDOM(true);\r
+            }\r
             return cachedDOM;\r
         }\r
         \r
-        // We have a DOM but it doesn't match the document we were given, so we import\r
-        // it into the new document.\r
-        cachedDOM=static_cast<DOMElement*>(parentElement->getOwnerDocument()->importNode(cachedDOM, true));\r
-\r
-        try {\r
-            XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(m_signature);\r
-            m_signature=NULL;\r
-            m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(\r
-                parentElement->getOwnerDocument(), cachedDOM\r
-                );\r
-            m_signature->load();\r
-        }\r
-        catch(XSECException& e) {\r
-            auto_ptr_char temp(e.getMsg());\r
-            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());\r
-        }\r
-        catch(XSECCryptoException& e) {\r
-            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());\r
-        }\r
-\r
-        // Recache the DOM.\r
-        parentElement->appendChild(cachedDOM);\r
-        log.debug("caching imported DOM for Signature");\r
-        setDOM(cachedDOM, false);\r
-        releaseParentDOM(true);\r
-        return cachedDOM;\r
+        // We have a DOM but it doesn't match the document we were given. This both sucks and blows.\r
+        // Without an adoptNode option to maintain the child pointers, we have to either import the\r
+        // DOM while somehow reassigning all the nested references (which amounts to a complete\r
+        // *unmarshall* operation), or we just release the existing DOM and hope that we can get\r
+        // it back. This depends on all objects being able to preserve their DOM at all costs.\r
+        releaseChildrenDOM(true);\r
+        releaseDOM();\r
     }\r
     \r
     // If we get here, we didn't have a usable DOM.\r
@@ -349,7 +332,7 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, Marshalling
         MemBufInputSource src(reinterpret_cast<const XMLByte*>(m_xml.c_str()),m_xml.length(),"XMLSecSignatureImpl");\r
         Wrapper4InputSource dsrc(&src,false);\r
         log.debug("parsing XML back into DOM tree");\r
-        DOMDocument* internalDoc=XMLToolingInternalConfig::getInternalConfig().m_parserPool->parse(dsrc);\r
+        DOMDocument* internalDoc=XMLToolingConfig::getConfig().getParser().parse(dsrc);\r
         \r
         log.debug("reimporting new DOM into caller-supplied document");\r
         cachedDOM=static_cast<DOMElement*>(parentElement->getOwnerDocument()->importNode(internalDoc->getDocumentElement(),true));\r
@@ -371,6 +354,11 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, Marshalling
         }\r
     }\r
 \r
+    // Marshall KeyInfo data.\r
+    if (m_keyInfo && (!m_signature->getKeyInfoList() || m_signature->getKeyInfoList()->isEmpty())) {\r
+        m_keyInfo->marshall(cachedDOM);\r
+    }\r
+\r
     // Recache the DOM and clear the serialized copy.\r
     parentElement->appendChild(cachedDOM);\r
     log.debug("caching DOM for Signature");\r