| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| /* |
| * XSEC |
| * |
| * DSIGSignature := Class for checking and setting up signature nodes in a DSIG signature |
| * |
| * Author(s): Berin Lautenbach |
| * |
| * $Id$ |
| * |
| */ |
| |
| // XSEC Includes |
| #include <xsec/dsig/DSIGSignature.hpp> |
| #include <xsec/dsig/DSIGConstants.hpp> |
| #include <xsec/dsig/DSIGKeyInfoX509.hpp> |
| #include <xsec/dsig/DSIGObject.hpp> |
| #include <xsec/dsig/DSIGReference.hpp> |
| #include <xsec/dsig/DSIGTransformList.hpp> |
| #include <xsec/dsig/DSIGKeyInfoValue.hpp> |
| #include <xsec/dsig/DSIGKeyInfoX509.hpp> |
| #include <xsec/dsig/DSIGKeyInfoName.hpp> |
| #include <xsec/dsig/DSIGKeyInfoPGPData.hpp> |
| #include <xsec/dsig/DSIGKeyInfoSPKIData.hpp> |
| #include <xsec/dsig/DSIGKeyInfoMgmtData.hpp> |
| #include <xsec/dsig/DSIGAlgorithmHandlerDefault.hpp> |
| #include <xsec/enc/XSECCryptoKeyDSA.hpp> |
| #include <xsec/enc/XSECCryptoKeyRSA.hpp> |
| #include <xsec/enc/XSECKeyInfoResolver.hpp> |
| #include <xsec/framework/XSECError.hpp> |
| #include <xsec/framework/XSECAlgorithmHandler.hpp> |
| #include <xsec/framework/XSECAlgorithmMapper.hpp> |
| #include <xsec/framework/XSECEnv.hpp> |
| #include <xsec/framework/XSECURIResolver.hpp> |
| #include <xsec/transformers/TXFMDocObject.hpp> |
| #include <xsec/transformers/TXFMOutputFile.hpp> |
| #include <xsec/transformers/TXFMBase64.hpp> |
| #include <xsec/transformers/TXFMC14n.hpp> |
| #include <xsec/transformers/TXFMChain.hpp> |
| #include <xsec/utils/XSECBinTXFMInputStream.hpp> |
| #include <xsec/utils/XSECDOMUtils.hpp> |
| #include <xsec/utils/XSECPlatformUtils.hpp> |
| |
| #include "../utils/XSECAlgorithmSupport.hpp" |
| |
| // Xerces includes |
| |
| #include <xercesc/dom/DOMNamedNodeMap.hpp> |
| #include <xercesc/util/Janitor.hpp> |
| |
| XERCES_CPP_NAMESPACE_USE |
| |
| // -------------------------------------------------------------------------------- |
| // Init |
| // -------------------------------------------------------------------------------- |
| |
| |
| void DSIGSignature::Initialise() { |
| |
| DSIGAlgorithmHandlerDefault def; |
| |
| // Register default signature algorithm handlers |
| |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_SHA1, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_MD5, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_SHA224, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_SHA256, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_SHA384, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_SHA512, def); |
| |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIDSA_SHA1, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIDSA_SHA256, def); |
| |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIECDSA_SHA1, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIECDSA_SHA224, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIECDSA_SHA256, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIECDSA_SHA384, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIECDSA_SHA512, def); |
| |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIHMAC_SHA1, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIHMAC_SHA224, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIHMAC_SHA256, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIHMAC_SHA384, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIHMAC_SHA512, def); |
| |
| // Register default hashing algorithm handlers |
| |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURISHA1, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURISHA224, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURISHA256, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURISHA384, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURISHA512, def); |
| XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIMD5, def); |
| |
| } |
| |
| |
| // -------------------------------------------------------------------------------- |
| // Get the Canonicalised BYTE_STREAM of the SignedInfo |
| // -------------------------------------------------------------------------------- |
| |
| XSECBinTXFMInputStream* DSIGSignature::makeBinInputStream() const { |
| |
| TXFMBase* txfm; |
| |
| // Create the starting point for the transform list |
| |
| XSECnew(txfm, TXFMDocObject(mp_doc)); |
| |
| TXFMChain* chain; |
| XSECnew(chain, TXFMChain(txfm)); |
| Janitor<TXFMChain> j_chain(chain); |
| |
| ((TXFMDocObject*) txfm)->setInput(mp_doc, mp_signedInfo->getDOMNode()); |
| |
| // canonicalize the SignedInfo content |
| |
| bool exclusive; |
| bool comments; |
| bool onedotone; |
| if (XSECAlgorithmSupport::evalCanonicalizationMethod(mp_signedInfo->getCanonicalizationMethod(), |
| exclusive, comments, onedotone)) { |
| |
| XSECnew(txfm, TXFMC14n(mp_doc)); |
| chain->appendTxfm(txfm); |
| |
| if (comments) |
| txfm->activateComments(); |
| else |
| txfm->stripComments(); |
| |
| if (exclusive) |
| ((TXFMC14n*) txfm)->setExclusive(); |
| |
| if (onedotone) |
| ((TXFMC14n*) txfm)->setInclusive11(); |
| |
| } else { |
| throw XSECException(XSECException::SigVfyError, |
| "Unknown CanonicalizationMethod in DSIGSignature::makeBinInputStream()"); |
| } |
| |
| // Now create the InputStream |
| |
| XSECBinTXFMInputStream* ret = new XSECBinTXFMInputStream(chain); |
| j_chain.release(); |
| |
| return ret; |
| } |
| |
| |
| // -------------------------------------------------------------------------------- |
| // Get the list of references |
| // -------------------------------------------------------------------------------- |
| |
| DSIGReferenceList* DSIGSignature::getReferenceList() { |
| return mp_signedInfo ? mp_signedInfo->getReferenceList() : NULL; |
| } |
| |
| const DSIGReferenceList* DSIGSignature::getReferenceList() const { |
| return mp_signedInfo ? mp_signedInfo->getReferenceList() : NULL; |
| } |
| |
| const XMLCh* DSIGSignature::getAlgorithmURI() const { |
| return mp_signedInfo ? mp_signedInfo->getAlgorithmURI() : NULL; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Set and Get Resolvers |
| // -------------------------------------------------------------------------------- |
| |
| |
| void DSIGSignature::setURIResolver(XSECURIResolver* resolver) { |
| mp_env->setURIResolver(resolver); |
| } |
| |
| XSECURIResolver* DSIGSignature::getURIResolver() const { |
| return mp_env->getURIResolver(); |
| } |
| |
| void DSIGSignature::setKeyInfoResolver(XSECKeyInfoResolver* resolver) { |
| |
| if (mp_KeyInfoResolver != 0) |
| delete mp_KeyInfoResolver; |
| |
| mp_KeyInfoResolver = resolver->clone(); |
| } |
| |
| XSECKeyInfoResolver* DSIGSignature::getKeyInfoResolver() const { |
| return mp_KeyInfoResolver; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Object Handling |
| // -------------------------------------------------------------------------------- |
| |
| DSIGObject* DSIGSignature::appendObject() { |
| |
| DSIGObject* ret; |
| XSECnew(ret, DSIGObject(mp_env)); |
| DOMElement* elt = ret->createBlankObject(); |
| |
| mp_sigNode->appendChild(elt); |
| mp_env->doPrettyPrint(mp_sigNode); |
| |
| m_objects.push_back(ret); |
| |
| return ret; |
| |
| } |
| |
| int DSIGSignature::getObjectLength() const { |
| return (unsigned int) m_objects.size(); |
| } |
| |
| DSIGObject* DSIGSignature::getObjectItem(int i) { |
| |
| if ( i < 0 || i >= ((int) m_objects.size())) { |
| throw XSECException(XSECException::ObjectError, |
| "DSIGSignature::getObjectItem - index out of range"); |
| } |
| |
| return m_objects[i]; |
| } |
| |
| const DSIGObject* DSIGSignature::getObjectItem(int i) const { |
| |
| if ( i < 0 || i >= ((int) m_objects.size())) { |
| throw XSECException(XSECException::ObjectError, |
| "DSIGSignature::getObjectItem - index out of range"); |
| } |
| |
| return m_objects[i]; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Signature |
| // -------------------------------------------------------------------------------- |
| |
| // Constructors and Destructors |
| |
| DSIGSignature::DSIGSignature(DOMDocument* doc, DOMNode* sigNode) : |
| m_loaded(false), |
| mp_doc(doc), |
| mp_sigNode(sigNode), |
| mp_signedInfo(NULL), |
| mp_signatureValueNode(NULL), |
| m_keyInfoList(NULL), |
| mp_KeyInfoNode(NULL), |
| m_errStr(""), |
| mp_signingKey(NULL), |
| mp_KeyInfoResolver(NULL), |
| m_interlockingReferences(false) { |
| |
| // Set up our formatter |
| XSECnew(mp_formatter, XSECSafeBufferFormatter("UTF-8",XMLFormatter::NoEscapes, |
| XMLFormatter::UnRep_CharRef)); |
| |
| // Set up the environment |
| XSECnew(mp_env, XSECEnv(doc)); |
| |
| m_keyInfoList.setEnvironment(mp_env); |
| } |
| |
| DSIGSignature::DSIGSignature() : |
| m_loaded(false), |
| mp_doc(NULL), |
| mp_sigNode(NULL), |
| mp_signedInfo(NULL), |
| mp_signatureValueNode(NULL), |
| m_keyInfoList(NULL), |
| mp_KeyInfoNode(NULL), |
| m_errStr(""), |
| mp_signingKey(NULL), |
| mp_KeyInfoResolver(NULL), |
| m_interlockingReferences(false) { |
| |
| // Set up our formatter |
| XSECnew(mp_formatter, XSECSafeBufferFormatter("UTF-8",XMLFormatter::NoEscapes, |
| XMLFormatter::UnRep_CharRef)); |
| |
| XSECnew(mp_env, XSECEnv(NULL)); |
| |
| m_keyInfoList.setEnvironment(mp_env); |
| } |
| |
| DSIGSignature::~DSIGSignature() { |
| |
| if (mp_env != NULL) |
| delete mp_env; |
| |
| if (mp_signingKey != NULL) { |
| |
| delete mp_signingKey; |
| mp_signingKey = NULL; |
| |
| } |
| |
| if (mp_signedInfo != NULL) { |
| |
| delete mp_signedInfo; |
| mp_signedInfo = NULL; |
| |
| } |
| |
| if (mp_formatter != NULL) { |
| |
| delete mp_formatter; |
| mp_formatter = NULL; |
| } |
| |
| if (mp_KeyInfoResolver != NULL) { |
| delete mp_KeyInfoResolver; |
| mp_KeyInfoResolver = NULL; |
| } |
| |
| // Delete any object items |
| for (int i = 0; i < ((int) m_objects.size()); ++i) { |
| delete (m_objects[i]); |
| } |
| } |
| |
| // Actions |
| |
| const XMLCh* DSIGSignature::getErrMsgs() const { |
| return m_errStr.rawXMLChBuffer(); |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Pretty Printing |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGSignature::setPrettyPrint(bool flag) { |
| mp_env->setPrettyPrintFlag(flag); |
| } |
| |
| |
| bool DSIGSignature::getPrettyPrint() const { |
| return mp_env->getPrettyPrintFlag(); |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Creating signatures from blank |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGSignature::setDSIGNSPrefix(const XMLCh* prefix) { |
| mp_env->setDSIGNSPrefix(prefix); |
| } |
| |
| void DSIGSignature::setECNSPrefix(const XMLCh* prefix) { |
| mp_env->setECNSPrefix(prefix); |
| } |
| |
| void DSIGSignature::setXPFNSPrefix(const XMLCh* prefix) { |
| mp_env->setXPFNSPrefix(prefix); |
| } |
| |
| // get |
| |
| const XMLCh* DSIGSignature::getDSIGNSPrefix() const { |
| return mp_env->getDSIGNSPrefix(); |
| } |
| |
| |
| const XMLCh* DSIGSignature::getECNSPrefix() const { |
| return mp_env->getECNSPrefix(); |
| } |
| |
| const XMLCh* DSIGSignature::getXPFNSPrefix() const { |
| return mp_env->getXPFNSPrefix(); |
| } |
| |
| DOMElement*DSIGSignature::createBlankSignature( |
| DOMDocument* doc, |
| const XMLCh* canonicalizationAlgorithmURI, |
| const XMLCh* signatureAlgorithmURI) { |
| |
| // "New" method to create a blank signature, based on URIs. |
| |
| mp_doc = doc; |
| mp_env->setParentDocument(doc); |
| |
| const XMLCh* prefixNS = mp_env->getDSIGNSPrefix(); |
| |
| safeBuffer str; |
| |
| makeQName(str, prefixNS, "Signature"); |
| |
| DOMElement*sigNode = doc->createElementNS(DSIGConstants::s_unicodeStrURIDSIG, str.rawXMLChBuffer()); |
| |
| if (prefixNS[0] == '\0') { |
| str.sbTranscodeIn("xmlns"); |
| } |
| else { |
| str.sbTranscodeIn("xmlns:"); |
| str.sbXMLChCat(prefixNS); |
| } |
| |
| sigNode->setAttributeNS(DSIGConstants::s_unicodeStrURIXMLNS, |
| str.rawXMLChBuffer(), |
| DSIGConstants::s_unicodeStrURIDSIG); |
| |
| mp_sigNode = sigNode; |
| |
| mp_env->doPrettyPrint(mp_sigNode); |
| |
| // Create the skeleton SignedInfo |
| XSECnew(mp_signedInfo, DSIGSignedInfo(mp_doc, mp_formatter, mp_env)); |
| |
| mp_sigNode->appendChild(mp_signedInfo->createBlankSignedInfo( |
| canonicalizationAlgorithmURI, signatureAlgorithmURI)); |
| mp_env->doPrettyPrint(mp_sigNode); |
| |
| // Create a dummy signature value (dummy until signed) |
| |
| makeQName(str, mp_env->getDSIGNSPrefix(), "SignatureValue"); |
| DOMElement*sigValNode = doc->createElementNS(DSIGConstants::s_unicodeStrURIDSIG, |
| str.rawXMLChBuffer()); |
| mp_signatureValueNode = sigValNode; |
| mp_sigNode->appendChild(sigValNode); |
| mp_env->doPrettyPrint(mp_sigNode); |
| |
| // Some text to mark this as a template only |
| sigValNode->appendChild(doc->createTextNode(MAKE_UNICODE_STRING("Not yet signed"))); |
| |
| m_loaded = true; |
| |
| return sigNode; |
| } |
| |
| |
| |
| // -------------------------------------------------------------------------------- |
| // Creating References |
| // -------------------------------------------------------------------------------- |
| |
| DSIGReference* DSIGSignature::createReference( |
| const XMLCh* URI, |
| const XMLCh* hashAlgorithmURI, |
| const XMLCh* type) { |
| |
| return mp_signedInfo->createReference(URI, hashAlgorithmURI, type); |
| } |
| |
| DSIGReference* DSIGSignature::removeReference(DSIGReferenceList::size_type index) { |
| return mp_signedInfo ? mp_signedInfo->removeReference(index) : NULL; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Manipulation of KeyInfo elements |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGSignature::clearKeyInfo() { |
| |
| if (mp_KeyInfoNode == 0) |
| return; |
| |
| if (mp_sigNode->removeChild(mp_KeyInfoNode) != mp_KeyInfoNode) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Attempted to remove KeyInfo node but it is no longer a child of <Signature>"); |
| |
| } |
| |
| mp_KeyInfoNode->release(); // No longer required |
| |
| mp_KeyInfoNode = NULL; |
| |
| // Clear out the list |
| m_keyInfoList.empty(); |
| |
| } |
| |
| void DSIGSignature::createKeyInfoElement() { |
| |
| if (mp_KeyInfoNode != NULL) |
| return; |
| |
| safeBuffer str; |
| |
| makeQName(str, mp_env->getDSIGNSPrefix(), "KeyInfo"); |
| |
| mp_KeyInfoNode = m_keyInfoList.createKeyInfo(); |
| |
| // Append the node to the end of the signature |
| |
| DOMNode* afterSignatureValue = mp_signatureValueNode->getNextSibling(); |
| while (afterSignatureValue != 0 && afterSignatureValue->getNodeType() != DOMNode::ELEMENT_NODE) |
| afterSignatureValue = afterSignatureValue->getNextSibling(); |
| |
| if (afterSignatureValue == 0) { |
| mp_sigNode->appendChild(mp_KeyInfoNode); |
| mp_env->doPrettyPrint(mp_sigNode); |
| } |
| else { |
| mp_sigNode->insertBefore(mp_KeyInfoNode, afterSignatureValue); |
| if (mp_env->getPrettyPrintFlag() == true) |
| mp_sigNode->insertBefore(mp_doc->createTextNode(DSIGConstants::s_unicodeStrNL), |
| afterSignatureValue); |
| } |
| } |
| |
| DSIGKeyInfoValue* DSIGSignature::appendDSAKeyValue(const XMLCh* P, |
| const XMLCh* Q, |
| const XMLCh* G, |
| const XMLCh* Y) { |
| |
| createKeyInfoElement(); |
| return m_keyInfoList.appendDSAKeyValue(P, Q, G, Y); |
| } |
| |
| DSIGKeyInfoValue* DSIGSignature::appendRSAKeyValue(const XMLCh* modulus, |
| const XMLCh* exponent) { |
| |
| createKeyInfoElement(); |
| return m_keyInfoList.appendRSAKeyValue(modulus, exponent); |
| } |
| |
| |
| DSIGKeyInfoX509* DSIGSignature::appendX509Data() { |
| |
| createKeyInfoElement(); |
| return m_keyInfoList.appendX509Data(); |
| } |
| |
| DSIGKeyInfoName* DSIGSignature::appendKeyName(const XMLCh* name, bool isDName) { |
| |
| createKeyInfoElement(); |
| return m_keyInfoList.appendKeyName(name, isDName); |
| } |
| |
| DSIGKeyInfoPGPData* DSIGSignature::appendPGPData(const XMLCh* id, const XMLCh* packet) { |
| |
| createKeyInfoElement(); |
| return m_keyInfoList.appendPGPData(id, packet); |
| } |
| |
| DSIGKeyInfoSPKIData* DSIGSignature::appendSPKIData(const XMLCh* sexp) { |
| |
| createKeyInfoElement(); |
| return m_keyInfoList.appendSPKIData(sexp); |
| } |
| |
| DSIGKeyInfoMgmtData* DSIGSignature::appendMgmtData(const XMLCh* data) { |
| |
| createKeyInfoElement(); |
| return m_keyInfoList.appendMgmtData(data); |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Working on Existing templates |
| // -------------------------------------------------------------------------------- |
| |
| |
| void DSIGSignature::load() { |
| |
| // Load all the information from the source document into local variables for easier |
| // manipulation by the other functions in the class |
| |
| if (mp_sigNode == NULL) { |
| |
| // Attempt to load an empty signature element |
| throw XSECException(XSECException::LoadEmptySignature); |
| |
| } |
| |
| if (!strEquals(getDSIGLocalName(mp_sigNode), "Signature")) { |
| |
| throw XSECException(XSECException::LoadNonSignature); |
| |
| } |
| |
| m_loaded = true; |
| |
| // Find the prefix being used so that we can later use it to manipulate the signature |
| mp_env->setDSIGNSPrefix(mp_sigNode->getPrefix()); |
| |
| // Now check for SignedInfo |
| DOMNode*tmpElt = mp_sigNode->getFirstChild(); |
| |
| while (tmpElt != 0 && (tmpElt->getNodeType() != DOMNode::ELEMENT_NODE)) |
| // Skip text and comments |
| tmpElt = tmpElt->getNextSibling(); |
| |
| if (tmpElt == 0 || !strEquals(getDSIGLocalName(tmpElt), "SignedInfo")) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <SignedInfo> as first child of <Signature>"); |
| |
| } |
| |
| // Have a signed info |
| |
| XSECnew(mp_signedInfo, DSIGSignedInfo(mp_doc, mp_formatter, tmpElt, mp_env)); |
| mp_signedInfo->load(); |
| |
| // Look at Signature Value |
| tmpElt = findNextElementChild(tmpElt); |
| if (tmpElt == 0 || !strEquals(getDSIGLocalName(tmpElt), "SignatureValue")) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <SignatureValue> node"); |
| |
| } |
| |
| DOMNode*tmpSV = tmpElt->getFirstChild(); |
| while (tmpSV != 0 && tmpSV->getNodeType() != DOMNode::TEXT_NODE) |
| tmpSV = tmpSV->getNextSibling(); |
| |
| if (tmpSV == 0) |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected TEXT child of <SignatureValue>"); |
| |
| mp_signatureValueNode = tmpElt; |
| |
| // The signature value is transcoded to local code page, as it is easier |
| // to work with, and should be low ASCII in any case (Base64) |
| |
| m_signatureValueSB.sbTranscodeIn(tmpSV->getNodeValue()); |
| |
| |
| // Now look at KeyInfo |
| tmpElt = findNextElementChild(tmpElt); |
| |
| if (tmpElt != 0 && strEquals(getDSIGLocalName(tmpElt), "KeyInfo")) { |
| |
| // Have a keyInfo |
| |
| mp_KeyInfoNode = tmpElt; // In case we later want to manipulate it |
| |
| m_keyInfoList.loadListFromXML(tmpElt); |
| |
| tmpElt = findNextElementChild(tmpElt); |
| } |
| |
| while (tmpElt != 0 && strEquals(getDSIGLocalName(tmpElt), "Object")) { |
| |
| DSIGObject* obj; |
| XSECnew(obj, DSIGObject(mp_env, tmpElt)); |
| obj->load(); |
| |
| m_objects.push_back(obj); |
| |
| tmpElt = findNextElementChild(tmpElt); |
| |
| } |
| /* |
| * Strictly speaking, this should remain, but it causes too many problems with non |
| * conforming signatures |
| |
| if (tmpElt != 0) { |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "DSIGSignature::load - Unexpected (non Object) Element found at end of signature"); |
| } |
| */ |
| } |
| |
| TXFMChain* DSIGSignature::getSignedInfoInput() const { |
| |
| TXFMBase* txfm; |
| TXFMChain* chain; |
| |
| // First we calculate the hash. Start off by creating a starting point |
| XSECnew(txfm, TXFMDocObject(mp_doc)); |
| XSECnew(chain, TXFMChain(txfm)); |
| Janitor<TXFMChain> j_chain(chain); |
| |
| ((TXFMDocObject*) txfm)->setInput(mp_doc, mp_signedInfo->getDOMNode()); |
| |
| // canonicalise the SignedInfo content |
| |
| bool exclusive; |
| bool comments; |
| bool onedotone; |
| if (XSECAlgorithmSupport::evalCanonicalizationMethod(mp_signedInfo->getCanonicalizationMethod(), |
| exclusive, comments, onedotone)) { |
| |
| XSECnew(txfm, TXFMC14n(mp_doc)); |
| chain->appendTxfm(txfm); |
| |
| if (comments) |
| txfm->activateComments(); |
| else |
| txfm->stripComments(); |
| |
| if (exclusive) |
| ((TXFMC14n*) txfm)->setExclusive(); |
| |
| if (onedotone) |
| ((TXFMC14n*) txfm)->setInclusive11(); |
| |
| } else { |
| throw XSECException(XSECException::SigVfyError, |
| "Unknown CanonicalizationMethod in DSIGSignature::calculateSignedInfoHash()"); |
| } |
| |
| j_chain.release(); |
| return chain; |
| } |
| |
| unsigned int DSIGSignature::calculateSignedInfoHash(unsigned char* hashBuf, |
| unsigned int hashBufLen) const { |
| |
| // Get the SignedInfo input bytes |
| TXFMChain* chain = getSignedInfoInput(); |
| Janitor<TXFMChain> j_chain(chain); |
| |
| // Check for debugging sink for the data |
| TXFMBase* sink = XSECPlatformUtils::GetReferenceLoggingSink(mp_doc); |
| if (sink) |
| chain->appendTxfm(sink); |
| |
| // Setup Hash |
| // First find the appropriate handler for the URI |
| XSECAlgorithmHandler* handler = |
| XSECPlatformUtils::g_algorithmMapper->mapURIToHandler( |
| mp_signedInfo->getAlgorithmURI()); |
| |
| if (handler == NULL) { |
| throw XSECException(XSECException::SigVfyError, |
| "Hash method unknown in DSIGSignature::calculateSignedInfoHash()"); |
| } |
| |
| if (!handler->appendSignatureHashTxfm(chain, mp_signedInfo->getAlgorithmURI(), mp_signingKey)) { |
| throw XSECException(XSECException::SigVfyError, |
| "Unexpected error in handler whilst appending Signature Hash transform"); |
| } |
| |
| |
| // Write hash to the buffer |
| return chain->getLastTxfm()->readBytes((XMLByte*) hashBuf, hashBufLen); |
| } |
| |
| unsigned int DSIGSignature::calculateSignedInfoAndReferenceHash(unsigned char* hashBuf, |
| unsigned int hashBufLen) const { |
| |
| // Set up the reference list hashes - including any manifests |
| mp_signedInfo->hash(m_interlockingReferences); |
| // calculaet signed InfoHash |
| return calculateSignedInfoHash(hashBuf,hashBufLen); |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Verify a signature |
| // -------------------------------------------------------------------------------- |
| |
| bool DSIGSignature::verifySignatureOnlyInternal() const { |
| |
| unsigned char hash[4096]; |
| |
| if (!m_loaded) { |
| |
| // Need to call "load" prior to checking a signature |
| throw XSECException(XSECException::SigVfyError, |
| "DSIGSignature::verify() called prior to DSIGSignature::load()"); |
| |
| } |
| |
| // FIX: CVE-2009-0217 |
| |
| if (mp_signedInfo->getHMACOutputLength() > 0 && mp_signedInfo->getHMACOutputLength() < 80) { |
| throw XSECException(XSECException::SigVfyError, |
| "DSIGSignature::verify() - HMACOutputLength is unsafe"); |
| } |
| |
| // Try to find a key |
| if (mp_signingKey == NULL) { |
| |
| // // Try to load a key from the KeyInfo list |
| // if ((mp_signingKey = m_keyInfoList.findKey()) == NULL) { |
| |
| // throw XSECException(XSECException::SigVfyError, |
| // "DSIGSignature::verify() - no verification key loaded and cannot determine from KeyInfo list"); |
| // } |
| |
| if (mp_KeyInfoResolver == NULL) { |
| |
| throw XSECException(XSECException::SigVfyError, |
| "DSIGSignature::verify() - no verification key loaded and no KeyInfoResolver loaded"); |
| |
| } |
| |
| if ((mp_signingKey = mp_KeyInfoResolver->resolveKey(&m_keyInfoList)) == NULL) { |
| |
| throw XSECException(XSECException::SigVfyError, |
| "DSIGSignature::verify() - no verification key loaded and cannot determine from KeyInfoResolver"); |
| } |
| |
| } |
| |
| // Get the SignedInfo input bytes |
| TXFMChain* chain = getSignedInfoInput(); |
| Janitor<TXFMChain> j_chain(chain); |
| |
| calculateSignedInfoHash(hash, 4096); |
| |
| // Now set up to verify |
| // First find the appropriate handler for the URI |
| XSECAlgorithmHandler* handler = |
| XSECPlatformUtils::g_algorithmMapper->mapURIToHandler( |
| mp_signedInfo->getAlgorithmURI()); |
| |
| if (handler == NULL) { |
| |
| throw XSECException(XSECException::SigVfyError, |
| "Hash method unknown in DSIGSignature::verifySignatureOnlyInternal()"); |
| |
| } |
| |
| bool sigVfyRet = handler->verifyBase64Signature(chain, |
| mp_signedInfo->getAlgorithmURI(), |
| m_signatureValueSB.rawCharBuffer(), |
| mp_signedInfo->getHMACOutputLength(), |
| mp_signingKey); |
| |
| if (!sigVfyRet) |
| m_errStr.sbXMLChCat("Validation of <SignedInfo> failed"); |
| |
| return sigVfyRet; |
| } |
| |
| bool DSIGSignature::verifySignatureOnly() const { |
| m_errStr.sbTranscodeIn(""); |
| return verifySignatureOnlyInternal(); |
| } |
| |
| bool DSIGSignature::verify() const { |
| |
| // We have a (hopefully) fully loaded signature. Need to |
| // verify |
| |
| bool referenceCheckResult; |
| |
| if (!m_loaded) { |
| |
| // Need to call "load" prior to checking a signature |
| throw XSECException(XSECException::SigVfyError, |
| "DSIGSignature::verify() called prior to DSIGSignature::load()"); |
| |
| } |
| |
| // Reset |
| m_errStr.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty); |
| |
| // First thing to do is check the references |
| |
| referenceCheckResult = mp_signedInfo->verify(m_errStr); |
| |
| // Check the signature |
| |
| bool sigVfyResult = verifySignatureOnlyInternal(); |
| |
| return sigVfyResult & referenceCheckResult; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Sign the XML document that has been previously loaded |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGSignature::sign() { |
| |
| // We have a (hopefully) fully loaded signature. Need to |
| // sign |
| |
| if (!m_loaded) { |
| |
| // Need to call "load" prior to checking a signature |
| throw XSECException(XSECException::SigVfyError, |
| "DSIGSignature::sign() called prior to DSIGSignature::load()"); |
| |
| } |
| |
| // Check we have a key |
| if (mp_signingKey == NULL) { |
| |
| throw XSECException(XSECException::SigVfyError, |
| "DSIGSignature::sign() - no signing key loaded"); |
| |
| |
| } |
| |
| // Reset error string in case we have any reference problems. |
| m_errStr.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty); |
| |
| // Set up the reference list hashes - including any manifests |
| mp_signedInfo->hash(m_interlockingReferences); |
| |
| // Get the SignedInfo input bytes |
| TXFMChain* chain = getSignedInfoInput(); |
| Janitor<TXFMChain> j_chain(chain); |
| |
| // Calculate the hash to be signed |
| |
| safeBuffer b64Buf; |
| |
| XSECAlgorithmHandler* handler = |
| XSECPlatformUtils::g_algorithmMapper->mapURIToHandler( |
| mp_signedInfo->getAlgorithmURI()); |
| |
| if (handler == NULL) { |
| |
| |
| throw XSECException(XSECException::SigVfyError, |
| "Hash method unknown in DSIGSignature::sign()"); |
| |
| } |
| |
| if (!handler->signToSafeBuffer(chain, mp_signedInfo->getAlgorithmURI(), |
| mp_signingKey, mp_signedInfo->getHMACOutputLength(), b64Buf)) { |
| |
| throw XSECException(XSECException::SigVfyError, |
| "Unexpected error in handler whilst appending Signature Hash transform"); |
| |
| } |
| |
| // Now we have the signature - place it in the DOM structures |
| |
| DOMNode*tmpElt = mp_signatureValueNode->getFirstChild(); |
| |
| while (tmpElt != NULL && tmpElt->getNodeType() != DOMNode::TEXT_NODE) |
| tmpElt = tmpElt->getNextSibling(); |
| |
| if (tmpElt == NULL) { |
| // Need to create the underlying TEXT_NODE |
| DOMDocument* doc = mp_signatureValueNode->getOwnerDocument(); |
| tmpElt = doc->createTextNode(b64Buf.sbStrToXMLCh()); |
| mp_signatureValueNode->appendChild(tmpElt); |
| } |
| else { |
| tmpElt->setNodeValue(b64Buf.sbStrToXMLCh()); |
| } |
| |
| // And copy to the local buffer |
| m_signatureValueSB = b64Buf; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Key Management |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGSignature::setSigningKey(XSECCryptoKey* k) { |
| |
| if (mp_signingKey != NULL) |
| delete mp_signingKey; |
| |
| mp_signingKey = k; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // ID Handling |
| // -------------------------------------------------------------------------------- |
| |
| /* |
| * ID handling is really all done within the environment object - just pass the |
| * calls straight through |
| */ |
| |
| void DSIGSignature::setIdByAttributeName(bool flag) { |
| mp_env->setIdByAttributeName(flag); |
| } |
| |
| bool DSIGSignature::getIdByAttributeName() const { |
| return mp_env->getIdByAttributeName(); |
| } |
| |
| |
| void DSIGSignature::registerIdAttributeName(const XMLCh* name) { |
| mp_env->registerIdAttributeName(name); |
| } |
| |
| bool DSIGSignature::deregisterIdAttributeName(const XMLCh* name) { |
| return mp_env->deregisterIdAttributeName(name); |
| } |
| |
| void DSIGSignature::registerIdAttributeNameNS(const XMLCh* ns, const XMLCh* name) { |
| mp_env->registerIdAttributeNameNS(ns, name); |
| } |
| |
| bool DSIGSignature::deregisterIdAttributeNameNS(const XMLCh* ns, const XMLCh* name) { |
| return mp_env->deregisterIdAttributeNameNS(ns, name); |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Other functions |
| // -------------------------------------------------------------------------------- |
| |
| const XMLCh* DSIGSignature::getSignatureValue() const { |
| |
| if (mp_signatureValueNode == NULL) |
| return NULL; |
| |
| return findFirstChildOfType(mp_signatureValueNode, DOMNode::TEXT_NODE)->getNodeValue(); |
| } |