Add code paths for new xmlsec APIs, and allow for undetermined signature algorithm.
[shibboleth/cpp-xmltooling.git] / xmltooling / signature / impl / XMLSecSignatureImpl.cpp
index b96b6ac..dec07c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
-*  Copyright 2001-2007 Internet2
+*  Copyright 2001-2009 Internet2
  * 
 * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include "internal.h"
 #include "exceptions.h"
+#include "logging.h"
 #include "impl/UnknownElement.h"
+#include "security/Credential.h"
+#include "signature/ContentReference.h"
 #include "signature/KeyInfo.h"
 #include "signature/Signature.h"
 #include "util/NDC.h"
 #include "util/XMLConstants.h"
 #include "util/XMLHelper.h"
 
-#include <log4cpp/Category.hh>
 #include <xercesc/framework/MemBufInputSource.hpp>
 #include <xercesc/framework/Wrapper4InputSource.hpp>
 #include <xercesc/util/XMLUniDefs.hpp>
 #include <xsec/transformers/TXFMOutputFile.hpp>
 
 using namespace xmlsignature;
+using namespace xmltooling::logging;
 using namespace xmltooling;
-using namespace log4cpp;
+using namespace xercesc;
 using namespace std;
 using xmlconstants::XMLSIG_NS;
 using xmlconstants::XMLSIG_PREFIX;
 
+namespace xmlsignature {
+
 #if defined (_MSC_VER)
     #pragma warning( push )
     #pragma warning( disable : 4250 4251 )
 #endif
-
-namespace xmlsignature {
     
     class XMLTOOL_DLLLOCAL XMLSecSignatureImpl : public UnknownElementImpl, public virtual Signature
     {
     public:
-        XMLSecSignatureImpl() : UnknownElementImpl(XMLSIG_NS, Signature::LOCAL_NAME, XMLSIG_PREFIX),
+        XMLSecSignatureImpl() : AbstractXMLObject(XMLSIG_NS, Signature::LOCAL_NAME, XMLSIG_PREFIX),
+            UnknownElementImpl(XMLSIG_NS, Signature::LOCAL_NAME, XMLSIG_PREFIX),
             m_signature(NULL), m_c14n(NULL), m_sm(NULL), m_key(NULL), m_keyInfo(NULL), m_reference(NULL) {}
         virtual ~XMLSecSignatureImpl();
         
@@ -75,13 +79,29 @@ namespace xmlsignature {
         XMLObject* clone() const;
         Signature* cloneSignature() const;
 
-        DOMElement* marshall(DOMDocument* document=NULL, const vector<Signature*>* sigs=NULL) const;
-        DOMElement* marshall(DOMElement* parentElement, const vector<Signature*>* sigs=NULL) const;
+        DOMElement* marshall(DOMDocument* document=NULL, const vector<Signature*>* sigs=NULL, const Credential* credential=NULL) const;
+        DOMElement* marshall(DOMElement* parentElement, const vector<Signature*>* sigs=NULL, const Credential* credential=NULL) const;
         XMLObject* unmarshall(DOMElement* element, bool bindDocument=false);
         
         // Getters
-        const XMLCh* getCanonicalizationMethod() const { return m_c14n ? m_c14n : DSIGConstants::s_unicodeStrURIEXC_C14N_NOC; }
-        const XMLCh* getSignatureAlgorithm() const { return m_sm ? m_sm : DSIGConstants::s_unicodeStrURIRSA_SHA1; }
+        const XMLCh* getCanonicalizationMethod() const {
+            if (m_signature)
+                return canonicalizationMethod2UNICODEURI(m_signature->getCanonicalizationMethod());
+            return m_c14n ? m_c14n : DSIGConstants::s_unicodeStrURIEXC_C14N_NOC;
+        }
+        const XMLCh* getSignatureAlgorithm() const {
+            if (!m_sm && m_signature) {
+#ifdef XMLTOOLING_XMLSEC_SIGALGORITHM
+                m_sm = XMLString::replicate(m_signature->getAlgorithmURI());
+#else
+                safeBuffer sURI;
+                if (signatureHashMethod2URI(sURI, m_signature->getSignatureMethod(), m_signature->getHashMethod()))
+                    m_sm = XMLString::replicate(sURI.sbStrToXMLCh());
+#endif
+            }
+            return m_sm;
+        }
+
         KeyInfo* getKeyInfo() const { return m_keyInfo; }
         ContentReference* getContentReference() const { return m_reference; }
         DSIGSignature* getXMLSignature() const { return m_signature; }
@@ -102,22 +122,37 @@ namespace xmlsignature {
             m_reference=reference;
         }
         
-        void sign();
+        void sign(const Credential* credential=NULL);
 
     private:
         mutable DSIGSignature* m_signature;
         XMLCh* m_c14n;
-        XMLCh* m_sm;
+        mutable XMLCh* m_sm;
         XSECCryptoKey* m_key;
-        KeyInfo* m_keyInfo;
+        mutable KeyInfo* m_keyInfo;
         ContentReference* m_reference;
     };
-    
-};
 
 #if defined (_MSC_VER)
     #pragma warning( pop )
 #endif
+};
+
+ContentReference::ContentReference()
+{
+}
+
+ContentReference::~ContentReference()
+{
+}
+
+Signature::Signature()
+{
+}
+
+Signature::~Signature()
+{
+}
 
 XMLSecSignatureImpl::~XMLSecSignatureImpl()
 {
@@ -171,18 +206,20 @@ Signature* XMLSecSignatureImpl::cloneSignature() const
     return ret;
 }
 
-void XMLSecSignatureImpl::sign()
+void XMLSecSignatureImpl::sign(const Credential* credential)
 {
     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Signature");
     log.debug("applying signature");
 
     if (!m_signature)
         throw SignatureException("Only a marshalled Signature object can be signed.");
-    else if (!m_key)
-        throw SignatureException("No signing key available for signature creation.");
     else if (!m_reference)
         throw SignatureException("No ContentReference object set for signature creation.");
 
+    XSECCryptoKey* key = credential ? credential->getPrivateKey() : m_key;
+    if (!key)
+        throw SignatureException("No signing key available for signature creation.");
+
     try {
         log.debug("creating signature reference(s)");
         DSIGReferenceList* refs = m_signature->getReferenceList();
@@ -191,7 +228,7 @@ void XMLSecSignatureImpl::sign()
         m_reference->createReferences(m_signature);
         
         log.debug("computing signature");
-        m_signature->setSigningKey(m_key->clone());
+        m_signature->setSigningKey(key->clone());
         m_signature->sign();
     }
     catch(XSECException& e) {
@@ -203,7 +240,7 @@ void XMLSecSignatureImpl::sign()
     }
 }
 
-DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector<Signature*>* sigs) const
+DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector<Signature*>* sigs, const Credential* credential) const
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("marshall");
@@ -240,9 +277,13 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector<Si
             document=DOMImplementationRegistry::getDOMImplementation(NULL)->createDocument();
             bindDocument=true;
         }
-        m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignature();
-        m_signature->setDSIGNSPrefix(XMLSIG_PREFIX);
-        cachedDOM=m_signature->createBlankSignature(document, getCanonicalizationMethod(), getSignatureAlgorithm());
+        DSIGSignature* temp=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignature();
+        temp->setDSIGNSPrefix(XMLSIG_PREFIX);
+        const XMLCh* alg = getSignatureAlgorithm();
+        if (!alg)
+            alg = DSIGConstants::s_unicodeStrURIRSA_SHA1;
+        cachedDOM=temp->createBlankSignature(document, getCanonicalizationMethod(), alg);
+        m_signature = temp;
     }
     else {
         // We need to reparse the XML we saved off into a new DOM.
@@ -285,6 +326,11 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector<Si
     }
     
     // Marshall KeyInfo data.
+    if (credential) {
+        delete m_keyInfo;
+        m_keyInfo = NULL;
+        m_keyInfo = credential->getKeyInfo();
+    }
     if (m_keyInfo && (!m_signature->getKeyInfoList() || m_signature->getKeyInfoList()->isEmpty())) {
         m_keyInfo->marshall(cachedDOM);
     }
@@ -298,7 +344,7 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector<Si
     return cachedDOM;
 }
 
-DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, const vector<Signature*>* sigs) const
+DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, const vector<Signature*>* sigs, const Credential* credential) const
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("marshall");
@@ -331,11 +377,13 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, const vecto
     if (m_xml.empty()) {
         // Fresh signature, so we just create an empty one.
         log.debug("creating empty Signature element");
-        m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignature();
-        m_signature->setDSIGNSPrefix(XMLSIG_PREFIX);
-        cachedDOM=m_signature->createBlankSignature(
-            parentElement->getOwnerDocument(), getCanonicalizationMethod(), getSignatureAlgorithm()
-            );
+        DSIGSignature* temp=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignature();
+        temp->setDSIGNSPrefix(XMLSIG_PREFIX);
+        const XMLCh* alg = getSignatureAlgorithm();
+        if (!alg)
+            alg = DSIGConstants::s_unicodeStrURIRSA_SHA1;
+        cachedDOM=temp->createBlankSignature(parentElement->getOwnerDocument(), getCanonicalizationMethod(), alg);
+        m_signature = temp;
     }
     else {
         MemBufInputSource src(reinterpret_cast<const XMLByte*>(m_xml.c_str()),m_xml.length(),"XMLSecSignatureImpl");
@@ -364,6 +412,11 @@ DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, const vecto
     }
 
     // Marshall KeyInfo data.
+    if (credential) {
+        delete m_keyInfo;
+        m_keyInfo = NULL;
+        m_keyInfo = credential->getKeyInfo();
+    }
     if (m_keyInfo && (!m_signature->getKeyInfoList() || m_signature->getKeyInfoList()->isEmpty())) {
         m_keyInfo->marshall(cachedDOM);
     }
@@ -405,7 +458,7 @@ Signature*
 XMLObject*
 #endif
 SignatureBuilder::buildObject(
-    const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType
+    const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const xmltooling::QName* schemaType
     ) const
 {
     if (!XMLString::equals(nsURI,XMLSIG_NS) || !XMLString::equals(localName,Signature::LOCAL_NAME))
@@ -423,6 +476,20 @@ SignatureBuilder::buildObject() const
     return new XMLSecSignatureImpl();
 }
 
+Signature* SignatureBuilder::buildSignature() {
+    const SignatureBuilder* b = dynamic_cast<const SignatureBuilder*>(
+        XMLObjectBuilder::getBuilder(xmltooling::QName(xmlconstants::XMLSIG_NS,Signature::LOCAL_NAME))
+        );
+    if (b) {
+#ifdef HAVE_COVARIANT_RETURNS
+        return b->buildObject();
+#else
+        return dynamic_cast<Signature*>(b->buildObject());
+#endif
+    }
+    throw XMLObjectException("Unable to obtain typed builder for Signature.");
+}
+
 const XMLCh Signature::LOCAL_NAME[] = UNICODE_LITERAL_9(S,i,g,n,a,t,u,r,e);
 
 // Raw signature methods.