| /** |
| * 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 |
| * |
| * DSIG_Reference := Class for handling a DSIG reference element |
| * |
| * $Id$ |
| * |
| */ |
| |
| // XSEC includes |
| |
| #include <xsec/dsig/DSIGReference.hpp> |
| #include <xsec/transformers/TXFMChain.hpp> |
| #include <xsec/transformers/TXFMURL.hpp> |
| #include <xsec/transformers/TXFMDocObject.hpp> |
| #include <xsec/transformers/TXFMOutputFile.hpp> |
| #include <xsec/transformers/TXFMSHA1.hpp> |
| #include <xsec/transformers/TXFMMD5.hpp> |
| #include <xsec/transformers/TXFMBase64.hpp> |
| #include <xsec/transformers/TXFMSB.hpp> |
| #include <xsec/transformers/TXFMXPath.hpp> |
| #include <xsec/transformers/TXFMC14n.hpp> |
| #include <xsec/transformers/TXFMXSL.hpp> |
| #include <xsec/transformers/TXFMEnvelope.hpp> |
| #include <xsec/dsig/DSIGConstants.hpp> |
| #include <xsec/dsig/DSIGSignature.hpp> |
| #include <xsec/dsig/DSIGTransformList.hpp> |
| #include <xsec/dsig/DSIGTransformBase64.hpp> |
| #include <xsec/dsig/DSIGTransformEnvelope.hpp> |
| #include <xsec/dsig/DSIGTransformXPath.hpp> |
| #include <xsec/dsig/DSIGTransformXPathFilter.hpp> |
| #include <xsec/dsig/DSIGTransformXSL.hpp> |
| #include <xsec/dsig/DSIGTransformC14n.hpp> |
| |
| #include <xsec/framework/XSECError.hpp> |
| #include <xsec/framework/XSECEnv.hpp> |
| #include <xsec/framework/XSECAlgorithmHandler.hpp> |
| #include <xsec/framework/XSECAlgorithmMapper.hpp> |
| #include <xsec/utils/XSECPlatformUtils.hpp> |
| #include <xsec/utils/XSECDOMUtils.hpp> |
| #include <xsec/utils/XSECBinTXFMInputStream.hpp> |
| |
| // Xerces |
| |
| #include <xercesc/util/XMLNetAccessor.hpp> |
| #include <xercesc/util/XMLUniDefs.hpp> |
| #include <xercesc/util/Janitor.hpp> |
| |
| XERCES_CPP_NAMESPACE_USE |
| |
| #include <iostream> |
| |
| // -------------------------------------------------------------------------------- |
| // Some useful strings |
| // -------------------------------------------------------------------------------- |
| |
| |
| static const XMLCh s_unicodeStrURI[] = |
| { |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_U, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_R, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_I, |
| XERCES_CPP_NAMESPACE_QUALIFIER chNull |
| }; |
| |
| static const XMLCh s_unicodeStrxpointer[] = |
| { |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_x, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_p, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_i, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_e, |
| XERCES_CPP_NAMESPACE_QUALIFIER chLatin_r, |
| XERCES_CPP_NAMESPACE_QUALIFIER chNull |
| }; |
| |
| static const XMLCh s_unicodeStrRootNode[] = |
| { |
| XERCES_CPP_NAMESPACE_QUALIFIER chOpenParen, |
| XERCES_CPP_NAMESPACE_QUALIFIER chForwardSlash, |
| XERCES_CPP_NAMESPACE_QUALIFIER chCloseParen, |
| XERCES_CPP_NAMESPACE_QUALIFIER chNull |
| }; |
| |
| // -------------------------------------------------------------------------------- |
| // Constructors and Destructors |
| // -------------------------------------------------------------------------------- |
| |
| |
| DSIGReference::DSIGReference(const XSECEnv * env, DOMNode *dom) : |
| mp_formatter(NULL), |
| mp_referenceNode(dom), |
| mp_preHash(NULL), |
| mp_manifestList(NULL), |
| mp_URI(NULL), |
| m_isManifest(false), |
| mp_transformsNode(NULL), |
| me_hashMethod(HASH_NONE), |
| mp_hashValueNode(NULL), |
| mp_env(env), |
| mp_transformList(NULL), |
| mp_algorithmURI(NULL), |
| m_loaded(false) { |
| |
| // Should throw an exception if the node is not a REFERENCE element |
| |
| XSECnew(mp_formatter, XSECSafeBufferFormatter("UTF-8",XMLFormatter::NoEscapes, |
| XMLFormatter::UnRep_CharRef)); |
| } |
| |
| DSIGReference::DSIGReference(const XSECEnv * env) : |
| mp_formatter(NULL), |
| mp_referenceNode(NULL), |
| mp_preHash(NULL), |
| mp_manifestList(NULL), |
| mp_URI(NULL), |
| m_isManifest(false), |
| mp_transformsNode(NULL), |
| me_hashMethod(HASH_NONE), |
| mp_hashValueNode(NULL), |
| mp_env(env), |
| mp_transformList(NULL), |
| mp_algorithmURI(NULL), |
| m_loaded(false) { |
| |
| XSECnew(mp_formatter, XSECSafeBufferFormatter("UTF-8",XMLFormatter::NoEscapes, |
| XMLFormatter::UnRep_CharRef)); |
| }; |
| |
| DSIGReference::~DSIGReference() { |
| |
| // Destroy any associated transforms |
| |
| if (mp_transformList != NULL) { |
| |
| delete mp_transformList; |
| mp_transformList = NULL; |
| |
| } |
| |
| if (mp_formatter != NULL) |
| delete mp_formatter; |
| |
| if (mp_manifestList != NULL) |
| delete mp_manifestList; |
| |
| }; |
| |
| // -------------------------------------------------------------------------------- |
| // Creation of Transforms |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGReference::createTransformList(void) { |
| |
| // Creates the transforms list |
| safeBuffer str; |
| const XMLCh * prefix; |
| DOMDocument *doc = mp_env->getParentDocument(); |
| |
| prefix = mp_env->getDSIGNSPrefix(); |
| |
| if (mp_transformsNode == NULL) { |
| |
| // Need to create a transforms node |
| makeQName(str, prefix, "Transforms"); |
| mp_transformsNode = doc->createElementNS(DSIGConstants::s_unicodeStrURIDSIG, str.rawXMLChBuffer()); |
| mp_referenceNode->insertBefore(mp_transformsNode, mp_referenceNode->getFirstChild()); |
| if (mp_env->getPrettyPrintFlag() == true) |
| mp_referenceNode->insertBefore(doc->createTextNode(DSIGConstants::s_unicodeStrNL), mp_transformsNode); |
| mp_env->doPrettyPrint(mp_transformsNode); |
| |
| // Create the list |
| XSECnew(mp_transformList, DSIGTransformList()); |
| } |
| |
| } |
| |
| void DSIGReference::addTransform(DSIGTransform * txfm, DOMElement * txfmElt) { |
| |
| if (mp_transformList == NULL) |
| createTransformList(); |
| |
| mp_transformsNode->appendChild(txfmElt); |
| mp_env->doPrettyPrint(mp_transformsNode); |
| |
| mp_transformList->addTransform(txfm); |
| } |
| |
| |
| DSIGTransformEnvelope * DSIGReference::appendEnvelopedSignatureTransform() { |
| |
| DOMElement *txfmElt; |
| DSIGTransformEnvelope * txfm; |
| |
| XSECnew(txfm, DSIGTransformEnvelope(mp_env)); |
| txfmElt = txfm->createBlankTransform(mp_env->getParentDocument()); |
| |
| addTransform(txfm, txfmElt); |
| |
| return txfm; |
| |
| } |
| |
| DSIGTransformBase64 * DSIGReference::appendBase64Transform() { |
| |
| DOMElement *txfmElt; |
| DSIGTransformBase64 * txfm; |
| |
| XSECnew(txfm, DSIGTransformBase64(mp_env)); |
| txfmElt = txfm->createBlankTransform(mp_env->getParentDocument()); |
| |
| addTransform(txfm, txfmElt); |
| |
| return txfm; |
| |
| } |
| |
| DSIGTransformXSL * DSIGReference::appendXSLTransform(DOMNode * stylesheet) { |
| |
| DOMElement *txfmElt; |
| DSIGTransformXSL * txfm; |
| |
| XSECnew(txfm, DSIGTransformXSL(mp_env)); |
| txfmElt = txfm->createBlankTransform(mp_env->getParentDocument()); |
| txfm->setStylesheet(stylesheet); |
| |
| addTransform(txfm, txfmElt); |
| |
| return txfm; |
| |
| } |
| |
| DSIGTransformC14n * DSIGReference::appendCanonicalizationTransform(canonicalizationMethod cm) { |
| |
| DOMElement *txfmElt; |
| DSIGTransformC14n * txfm; |
| |
| XSECnew(txfm, DSIGTransformC14n(mp_env)); |
| txfmElt = txfm->createBlankTransform(mp_env->getParentDocument()); |
| txfm->setCanonicalizationMethod(cm); |
| |
| addTransform(txfm, txfmElt); |
| |
| return txfm; |
| |
| } |
| |
| DSIGTransformC14n * DSIGReference::appendCanonicalizationTransform( |
| const XMLCh * canonicalizationAlgorithmURI) { |
| |
| canonicalizationMethod cm; |
| XSECmapURIToCanonicalizationMethod(canonicalizationAlgorithmURI, cm); |
| |
| return appendCanonicalizationTransform(cm); |
| |
| } |
| |
| DSIGTransformXPath * DSIGReference::appendXPathTransform(const char * expr) { |
| |
| DOMElement *txfmElt; |
| DSIGTransformXPath * txfm; |
| |
| XSECnew(txfm, DSIGTransformXPath(mp_env)); |
| txfmElt = txfm->createBlankTransform(mp_env->getParentDocument()); |
| txfm->setExpression(expr); |
| |
| addTransform(txfm, txfmElt); |
| |
| return txfm; |
| } |
| |
| DSIGTransformXPathFilter * DSIGReference::appendXPathFilterTransform(void) { |
| |
| DOMElement *txfmElt; |
| DSIGTransformXPathFilter * txfm; |
| |
| XSECnew(txfm, DSIGTransformXPathFilter(mp_env)); |
| txfmElt = txfm->createBlankTransform(mp_env->getParentDocument()); |
| |
| addTransform(txfm, txfmElt); |
| mp_env->doPrettyPrint(txfmElt); |
| |
| return txfm; |
| } |
| |
| |
| |
| // -------------------------------------------------------------------------------- |
| // Creation of blanks |
| // -------------------------------------------------------------------------------- |
| |
| |
| DOMElement *DSIGReference::createBlankReference(const XMLCh * URI, |
| const XMLCh * hashAlgorithmURI, |
| const XMLCh * type) { |
| |
| // Reset this Reference just in case |
| |
| m_isManifest = false; |
| mp_preHash = NULL; |
| mp_manifestList = NULL; |
| mp_transformsNode = NULL; |
| mp_transformList = NULL; |
| |
| XSECmapURIToHashMethod(hashAlgorithmURI, me_hashMethod); |
| |
| safeBuffer str; |
| DOMDocument *doc = mp_env->getParentDocument(); |
| const XMLCh * prefix = mp_env->getDSIGNSPrefix(); |
| |
| makeQName(str, prefix, "Reference"); |
| |
| DOMElement *ret = doc->createElementNS(DSIGConstants::s_unicodeStrURIDSIG, str.rawXMLChBuffer()); |
| mp_referenceNode = ret; |
| |
| // Set type |
| if (type != NULL) |
| ret->setAttributeNS(NULL, MAKE_UNICODE_STRING("Type"), type); |
| |
| // Set URI |
| if (URI != NULL) { |
| ret->setAttributeNS(NULL, s_unicodeStrURI, URI); |
| mp_URI = ret->getAttributeNS(NULL, s_unicodeStrURI); // Used later on as a pointer |
| } |
| else { |
| // Anonymous reference |
| mp_URI = NULL; |
| } |
| |
| // Create hash and hashValue nodes |
| makeQName(str, prefix, "DigestMethod"); |
| DOMElement *digestMethod = doc->createElementNS(DSIGConstants::s_unicodeStrURIDSIG, str.rawXMLChBuffer()); |
| mp_env->doPrettyPrint(ret); |
| ret->appendChild(digestMethod); |
| mp_env->doPrettyPrint(ret); |
| |
| digestMethod->setAttributeNS(NULL, DSIGConstants::s_unicodeStrAlgorithm, |
| hashAlgorithmURI); |
| |
| // Retrieve the attribute value for later use |
| mp_algorithmURI = |
| digestMethod->getAttributeNS(NULL, DSIGConstants::s_unicodeStrAlgorithm); |
| |
| |
| // DigestValue |
| |
| makeQName(str, prefix, "DigestValue"); |
| mp_hashValueNode = doc->createElementNS(DSIGConstants::s_unicodeStrURIDSIG, str.rawXMLChBuffer()); |
| ret->appendChild(mp_hashValueNode); |
| mp_env->doPrettyPrint(ret); |
| mp_hashValueNode->appendChild(doc->createTextNode(MAKE_UNICODE_STRING("Not yet calculated"))); |
| |
| m_loaded = true; |
| return ret; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // setPreHashTransform - to set a transform to be used pre-hash |
| // -------------------------------------------------------------------------------- |
| |
| |
| void DSIGReference::setPreHashTXFM(TXFMBase * t) { |
| |
| mp_preHash = t; |
| |
| } |
| |
| // setId |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGReference::setId(const XMLCh *id) { |
| |
| if (mp_referenceNode) |
| ((DOMElement*)mp_referenceNode)->setAttributeNS(NULL, MAKE_UNICODE_STRING("Id"), id); |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // setType |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGReference::setType(const XMLCh *type) { |
| |
| if (mp_referenceNode) |
| ((DOMElement*)mp_referenceNode)->setAttributeNS(NULL, MAKE_UNICODE_STRING("Type"), type); |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| |
| // -------------------------------------------------------------------------------- |
| // isManifest |
| // -------------------------------------------------------------------------------- |
| |
| bool DSIGReference::isManifest() const { |
| |
| return m_isManifest; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // getURI |
| // -------------------------------------------------------------------------------- |
| |
| const XMLCh * DSIGReference::getURI() const { |
| |
| return mp_URI; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // getManifestReferenceList |
| // -------------------------------------------------------------------------------- |
| |
| DSIGReferenceList * DSIGReference::getManifestReferenceList() const { |
| |
| return mp_manifestList; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // getURIBaseTransform |
| // -------------------------------------------------------------------------------- |
| |
| TXFMBase * DSIGReference::getURIBaseTXFM(DOMDocument * doc, |
| const XMLCh * URI, |
| const XSECEnv * env) { |
| |
| // Determine if this is a full URL or a pointer to a URL |
| |
| if (URI == NULL || (URI[0] != 0 && |
| URI[0] != XERCES_CPP_NAMESPACE_QUALIFIER chPound)) { |
| |
| TXFMURL * retTransform; |
| |
| // Have a URL! |
| |
| XSECnew(retTransform, TXFMURL(doc, env->getURIResolver())); |
| |
| try { |
| ((TXFMURL *) retTransform)->setInput(URI); |
| } |
| catch (...) { |
| |
| delete retTransform; |
| throw; |
| |
| } |
| |
| return retTransform; |
| |
| } |
| |
| // Have a fragment URI from the local document |
| TXFMDocObject * to; |
| XSECnew(to, TXFMDocObject(doc)); |
| Janitor<TXFMDocObject> j_to(to); |
| to->setEnv(env); |
| |
| // Find out what sort of object pointer this is. |
| |
| if (URI[0] == 0) { |
| |
| // empty pointer - use the document itself |
| to->setInput(doc); |
| to->stripComments(); |
| |
| } |
| |
| else if (XMLString::compareNString(&URI[1], s_unicodeStrxpointer, 8) == 0) { |
| |
| // Have an xpointer |
| if (strEquals(s_unicodeStrRootNode, &URI[9]) == true) { |
| // Root node |
| to->setInput(doc); |
| |
| } |
| |
| else if (URI[9] == XERCES_CPP_NAMESPACE_QUALIFIER chOpenParen && |
| URI[10] == XERCES_CPP_NAMESPACE_QUALIFIER chLatin_i && |
| URI[11] == XERCES_CPP_NAMESPACE_QUALIFIER chLatin_d && |
| URI[12] == XERCES_CPP_NAMESPACE_QUALIFIER chOpenParen && |
| URI[13] == XERCES_CPP_NAMESPACE_QUALIFIER chSingleQuote) { |
| |
| XMLSize_t len = XMLString::stringLen(&URI[14]); |
| |
| XMLCh* tmp = new XMLCh[len + 1]; |
| ArrayJanitor<XMLCh> j_tmp(tmp); |
| |
| XMLSize_t j = 14, i = 0; |
| |
| // Have an ID |
| while (i < len && URI[j] != '\'') { |
| tmp[i++] = URI[j++]; |
| } |
| |
| tmp[i] = XERCES_CPP_NAMESPACE_QUALIFIER chNull; |
| |
| if (URI[j] != '\'') { |
| throw XSECException(XSECException::UnsupportedXpointerExpr); |
| } |
| |
| to->setInput(doc, tmp); |
| |
| } |
| |
| else { |
| |
| throw XSECException(XSECException::UnsupportedXpointerExpr); |
| |
| } |
| |
| // Keep comments in these situations |
| to->activateComments(); |
| } |
| |
| else { |
| |
| to->setInput(doc, &URI[1]); |
| |
| // Remove comments |
| to->stripComments(); |
| |
| } |
| |
| j_to.release(); |
| return to; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // load |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGReference::load(void) { |
| |
| // Load reference info from XML |
| |
| DOMNamedNodeMap *atts = mp_referenceNode->getAttributes(); |
| DOMNode *tmpElt; |
| |
| const XMLCh * name; |
| safeBuffer sbName; |
| |
| if (atts != 0) { |
| |
| XMLSize_t size = atts->getLength(); |
| |
| for (XMLSize_t i = 0; i < size; ++i) { |
| |
| name = atts->item(i)->getNodeName(); |
| sbName << (*mp_formatter << atts->item(i)->getNodeName()); |
| |
| if (strEquals(name, s_unicodeStrURI)) { |
| mp_URI = atts->item(i)->getNodeValue(); |
| } |
| |
| else if (strEquals(name, "Type")) { |
| |
| // Check if a manifest, otherwise ignore for now |
| if (strEquals(atts->item(i)->getNodeValue(), DSIGConstants::s_unicodeStrURIMANIFEST)) |
| m_isManifest = true; |
| |
| } |
| |
| else if (strEquals(name, "Id")) { |
| |
| // For now ignore |
| |
| } |
| |
| else if (sbName.sbStrncmp("xmlns", 5) == 0) { |
| |
| // Ignore name spaces |
| |
| } |
| |
| else { |
| //safeBuffer tmp, error; |
| |
| //error << (*mp_formatter << name); |
| //tmp.sbStrcpyIn("Unknown attribute in <Reference> Element : "); |
| //tmp.sbStrcatIn(error); |
| |
| throw XSECException(XSECException::UnknownDSIGAttribute, |
| "Unknown attribute in <Reference> Element"); |
| |
| } |
| |
| } |
| |
| } |
| |
| // Now check for Transforms |
| tmpElt = mp_referenceNode->getFirstChild(); |
| |
| while (tmpElt != 0 && (tmpElt->getNodeType() != DOMNode::ELEMENT_NODE)) { |
| if (tmpElt->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE) { |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "EntityReference nodes in <Reference> are unsupported."); |
| } |
| // Skip text and comments |
| tmpElt = tmpElt->getNextSibling(); |
| } |
| |
| if (tmpElt == 0) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <Transforms> or <DigestMethod> within <Reference>"); |
| |
| } |
| |
| if (strEquals(getDSIGLocalName(tmpElt), "Transforms")) { |
| |
| // Store node for later use |
| mp_transformsNode = tmpElt; |
| |
| // Load the transforms |
| mp_transformList = loadTransforms(tmpElt, mp_formatter, mp_env); |
| |
| // Find next node |
| tmpElt = tmpElt->getNextSibling(); |
| while (tmpElt != 0 && (tmpElt->getNodeType() != DOMNode::ELEMENT_NODE)) { |
| if (tmpElt->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE) { |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "EntityReference nodes in <Reference> are unsupported."); |
| } |
| tmpElt = tmpElt->getNextSibling(); |
| } |
| |
| |
| } /* if tmpElt node type = transforms */ |
| else { |
| mp_transformList = NULL; |
| } |
| |
| |
| if (tmpElt == NULL || !strEquals(getDSIGLocalName(tmpElt), "DigestMethod")) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <DigestMethod> element"); |
| |
| } |
| |
| // Determine what the digest method actually is |
| |
| atts = tmpElt->getAttributes(); |
| unsigned int i; |
| |
| for (i = 0; i < atts->getLength() && |
| !strEquals(atts->item(i)->getNodeName(), DSIGConstants::s_unicodeStrAlgorithm); ++i); |
| |
| |
| if (i == atts->getLength()) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected 'Algorithm' attribute in <DigestMethod>"); |
| |
| } |
| |
| mp_algorithmURI = atts->item(i)->getNodeValue(); |
| |
| // Determine hashing algorithm |
| XSECmapURIToHashMethod(mp_algorithmURI, me_hashMethod); |
| |
| // Find the hash value node |
| |
| tmpElt = tmpElt->getNextSibling(); |
| |
| while (tmpElt != 0 && |
| (tmpElt->getNodeType() != DOMNode::ELEMENT_NODE || !strEquals(getDSIGLocalName(tmpElt), "DigestValue"))) { |
| if (tmpElt->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE) { |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "EntityReference nodes in <Reference> are unsupported."); |
| } |
| tmpElt = tmpElt->getNextSibling(); |
| } |
| |
| if (tmpElt == 0) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <DigestValue> within <Reference>"); |
| |
| } |
| |
| mp_hashValueNode = tmpElt; |
| |
| // If we are a manifest, then we need to load the manifest references |
| |
| if (m_isManifest) { |
| |
| // Find the manifest node - we cheat and use a transform |
| TXFMBase * docObject; |
| DOMNode * manifestNode, * referenceNode; |
| |
| docObject = getURIBaseTXFM(mp_referenceNode->getOwnerDocument(), mp_URI, |
| mp_env); |
| |
| manifestNode = docObject->getFragmentNode(); |
| delete docObject; |
| |
| // Now search downwards to find a <Manifest> |
| if (manifestNode == 0 || manifestNode->getNodeType() != DOMNode::ELEMENT_NODE || |
| (!strEquals(getDSIGLocalName(manifestNode), "Object") && !strEquals(getDSIGLocalName(manifestNode), "Manifest"))) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <Manifest> or <Object> URI for Manifest Type <Reference>"); |
| |
| } |
| |
| if (strEquals(getDSIGLocalName(manifestNode), "Object")) { |
| |
| // Find Manifest child |
| manifestNode = manifestNode->getFirstChild(); |
| while (manifestNode != 0 && manifestNode->getNodeType() != DOMNode::ELEMENT_NODE) { |
| if (manifestNode->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE) { |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "EntityReference nodes in <Reference> are unsupported."); |
| } |
| manifestNode = manifestNode->getNextSibling(); |
| } |
| |
| if (manifestNode == 0 || !strEquals(getDSIGLocalName(manifestNode), "Manifest")) |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <Manifest> as child of <Object> for Manifest Type <Reference>"); |
| |
| } |
| |
| // Now have the manifest node, find the first reference and load! |
| referenceNode = manifestNode->getFirstChild(); |
| |
| while (referenceNode != 0 && |
| (referenceNode->getNodeType() != DOMNode::ELEMENT_NODE || !strEquals(getDSIGLocalName(referenceNode), "Reference"))) { |
| if (referenceNode->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE) { |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "EntityReference nodes in <Reference> are unsupported."); |
| } |
| referenceNode = referenceNode->getNextSibling(); |
| } |
| |
| if (referenceNode == 0) |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <Reference> as child of <Manifest>"); |
| |
| // Have reference node, so lets create a list! |
| mp_manifestList = DSIGReference::loadReferenceListFromXML(mp_env, referenceNode); |
| |
| } /* m_isManifest */ |
| |
| m_loaded = true; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // createReferenceListFromXML |
| // -------------------------------------------------------------------------------- |
| |
| DSIGReferenceList *DSIGReference::loadReferenceListFromXML(const XSECEnv * env, DOMNode *firstReference) { |
| |
| // Have the first reference element in the document, |
| // so want to find and load them all |
| |
| DOMNode *tmpRef = firstReference; |
| DSIGReferenceList * refList; |
| DSIGReference * r; |
| |
| XSECnew(refList, DSIGReferenceList()); |
| Janitor<DSIGReferenceList> j_refList(refList); |
| |
| while (tmpRef != 0) { |
| |
| // Must be an element node |
| |
| if (tmpRef->getNodeType() != DOMNode::ELEMENT_NODE || |
| !strEquals(getDSIGLocalName(tmpRef), "Reference")) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <Reference> as child of <SignedInfo>"); |
| |
| } |
| |
| XSECnew(r, DSIGReference(env, tmpRef)); |
| |
| refList->addReference(r); |
| |
| // Load the reference before moving on |
| r->load(); |
| |
| // Find next element Node |
| tmpRef = tmpRef->getNextSibling(); |
| |
| while (tmpRef != 0 && tmpRef->getNodeType() != DOMNode::ELEMENT_NODE) { |
| if (tmpRef->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE) { |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "EntityReference nodes in <Reference> are unsupported."); |
| } |
| tmpRef = tmpRef->getNextSibling(); |
| } |
| |
| } |
| |
| j_refList.release(); |
| return refList; |
| |
| } |
| // -------------------------------------------------------------------------------- |
| // Get the Canonicalised BYTE_STREAM of the reference data (and TXFMS) |
| // -------------------------------------------------------------------------------- |
| |
| XSECBinTXFMInputStream * DSIGReference::makeBinInputStream(void) const { |
| |
| // First set up for input |
| |
| TXFMChain * txfmChain; |
| TXFMBase * currentTxfm; |
| |
| if (m_loaded == false) { |
| |
| throw XSECException(XSECException::NotLoaded, |
| "calculateHash() called in DSIGReference before load()"); |
| |
| } |
| |
| // Find base transform |
| currentTxfm = getURIBaseTXFM(mp_referenceNode->getOwnerDocument(), mp_URI, |
| mp_env); |
| |
| // Set up the transform chain |
| |
| txfmChain = createTXFMChainFromList(currentTxfm, mp_transformList); |
| Janitor<TXFMChain> j_txfmChain(txfmChain); |
| |
| DOMDocument *d = mp_referenceNode->getOwnerDocument(); |
| |
| // All transforms done. If necessary, change the type from nodes to bytes |
| |
| if (txfmChain->getLastTxfm()->getOutputType() == TXFMBase::DOM_NODES) { |
| |
| TXFMC14n * c14n; |
| XSECnew(c14n, TXFMC14n(d)); |
| txfmChain->appendTxfm(c14n); |
| |
| } |
| |
| // Now create the InputStream |
| |
| XSECBinTXFMInputStream * ret; |
| ret = new XSECBinTXFMInputStream(txfmChain); // Probs with MSVC++ mean no XSECnew |
| j_txfmChain.release(); // Now owned by "ret" |
| |
| return ret; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Hash a reference list |
| // -------------------------------------------------------------------------------- |
| |
| |
| void DSIGReference::hashReferenceList(const DSIGReferenceList *lst, bool interlocking) { |
| |
| // Run through a list of hashes and checkHash for each one |
| |
| DSIGReference * r; |
| int i = (int) lst->getSize(); |
| safeBuffer errStr; |
| errStr.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty); |
| |
| // Run a VERY naieve process at the moment that assumes the list will "settle" |
| // after N iterations through the list. This will settle any inter-locking references |
| // Where a hash in a later calculated reference could impact an already calculated hash |
| // in a previous references |
| // |
| // If interlocking is set to false, assume there are no interacting <Reference> nodes |
| |
| do { |
| |
| for (int j = 0; j < i; ++j) { |
| |
| r = lst->item(j); |
| |
| // If this is a manifest we need to set all the references in the manifest as well |
| |
| if (r->isManifest()) |
| hashReferenceList(r->getManifestReferenceList()); |
| |
| // Re-ordered as per suggestion by Peter Gubis to make it more likely |
| // that hashes are correct on first pass when manifests are involved |
| |
| r->setHash(); |
| |
| } |
| |
| } while (interlocking && !DSIGReference::verifyReferenceList(lst, errStr) && i-- >= 0); |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Verify reference list |
| // -------------------------------------------------------------------------------- |
| |
| bool DSIGReference::verifyReferenceList(const DSIGReferenceList * lst, safeBuffer &errStr) { |
| |
| // Run through a list of hashes and checkHash for each one |
| |
| XSEC_USING_XERCES(NetAccessorException); |
| |
| DSIGReference * r; |
| bool res = true; |
| |
| int size = (lst ? (int) lst->getSize() : 0); |
| |
| for (int i = 0; i < size; ++i) { |
| |
| r = lst->item(i); |
| |
| try { |
| if (!r->checkHash()) { |
| |
| // Failed |
| errStr.sbXMLChCat("Reference URI=\""); |
| errStr.sbXMLChCat(r->getURI()); |
| errStr.sbXMLChCat("\" failed to verify\n"); |
| |
| res = false; |
| |
| } |
| } |
| catch (const NetAccessorException&) { |
| |
| res = false; |
| |
| errStr.sbXMLChCat("Error accessing network URI=\""); |
| errStr.sbXMLChCat(r->getURI()); |
| errStr.sbXMLChCat("\". Reference failed to verify\n"); |
| |
| } |
| catch (const XSECException& e) { |
| |
| if (e.getType() != XSECException::HTTPURIInputStreamError) |
| throw; |
| |
| res = false; |
| |
| errStr.sbXMLChCat("Error accessing network URI=\""); |
| errStr.sbXMLChCat(r->getURI()); |
| errStr.sbXMLChCat("\". Reference failed to verify\n"); |
| |
| } |
| |
| // if a manifest, check the manifest list |
| if (r->isManifest()) |
| res = res & verifyReferenceList(r->getManifestReferenceList(), errStr); |
| |
| } |
| |
| return res; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // processTransforms |
| // -------------------------------------------------------------------------------- |
| |
| TXFMChain * DSIGReference::createTXFMChainFromList(TXFMBase * input, |
| DSIGTransformList * lst) { |
| |
| TXFMChain * ret; |
| XSECnew(ret, TXFMChain(input)); |
| |
| if (lst == NULL) |
| return ret; |
| |
| Janitor<TXFMChain> j_ret(ret); |
| |
| DSIGTransformList::TransformListVectorType::size_type size, i; |
| |
| size = lst->getSize(); |
| |
| if (size > 0) { |
| |
| // Iterate through the list |
| |
| for (i = 0; i < size; ++i) { |
| |
| lst->item(i)->appendTransformer(ret); |
| |
| } |
| |
| } |
| |
| j_ret.release(); |
| return ret; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // loadTransforms |
| // -------------------------------------------------------------------------------- |
| |
| DSIGTransformList * DSIGReference::loadTransforms( |
| DOMNode *transformsNode, |
| XSECSafeBufferFormatter * formatter, |
| const XSECEnv * env) { |
| |
| // This is defined as a static function, not because it makes use of any static variables |
| // in the DSIGReference class, but to neatly link it to the other users |
| |
| if (transformsNode == 0 || (!strEquals(getDSIGLocalName(transformsNode), "Transforms") && |
| !strEquals(getXENCLocalName(transformsNode), "Transforms"))) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Expected <Transforms> in function DSIGReference::processTransforms"); |
| |
| } |
| |
| // Create the list |
| DSIGTransformList * lst; |
| XSECnew(lst, DSIGTransformList()); |
| Janitor<DSIGTransformList> j_lst(lst); |
| |
| // Find First transform |
| |
| DOMNode * transforms = transformsNode->getFirstChild(); |
| while (transforms != NULL && transforms->getNodeType() != DOMNode::ELEMENT_NODE) |
| transforms = transforms->getNextSibling(); |
| |
| while (transforms != NULL) { |
| |
| // Process each transform in turn |
| if (!strEquals(getDSIGLocalName(transforms), "Transform")) { |
| |
| // Not what we expected to see! |
| safeBuffer tmp, error; |
| |
| error << (*formatter << getDSIGLocalName(transforms)); |
| tmp.sbStrcpyIn("Unknown attribute in <Transforms> - Expected <Transform> found "); |
| tmp.sbStrcatIn(error); |
| tmp.sbStrcatIn(">."); |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, error.rawCharBuffer()); |
| |
| } |
| |
| DOMNamedNodeMap * transformAtts = transforms->getAttributes(); |
| |
| unsigned int i; |
| |
| for (i = 0; i < transformAtts->getLength() && |
| !strEquals(transformAtts->item(i)->getNodeName(), DSIGConstants::s_unicodeStrAlgorithm); ++i); |
| |
| if (i == transformAtts->getLength()) { |
| |
| throw XSECException(XSECException::ExpectedDSIGChildNotFound, |
| "Algorithm attribute not found in <Transform> element"); |
| |
| } |
| |
| safeBuffer algorithm; |
| algorithm << (*formatter << transformAtts->item(i)->getNodeValue()); |
| |
| // Determine what the transform is |
| |
| if (algorithm.sbStrcmp(URI_ID_BASE64) == 0) { |
| |
| DSIGTransformBase64 * b; |
| XSECnew(b, DSIGTransformBase64(env, transforms)); |
| lst->addTransform(b); |
| b->load(); |
| } |
| |
| else if (algorithm.sbStrcmp(URI_ID_XPATH) == 0) { |
| |
| DSIGTransformXPath * x; |
| XSECnew(x, DSIGTransformXPath(env, transforms)); |
| lst->addTransform(x); |
| x->load(); |
| } |
| |
| else if (algorithm.sbStrcmp(URI_ID_XPF) == 0) { |
| |
| DSIGTransformXPathFilter * xpf; |
| |
| XSECnew(xpf, DSIGTransformXPathFilter(env, transforms)); |
| lst->addTransform(xpf); |
| xpf->load(); |
| |
| } |
| |
| else if (algorithm.sbStrcmp(URI_ID_ENVELOPE) == 0) { |
| |
| DSIGTransformEnvelope * e; |
| XSECnew(e, DSIGTransformEnvelope(env, transforms)); |
| lst->addTransform(e); |
| e->load(); |
| } |
| |
| else if (algorithm.sbStrcmp(URI_ID_XSLT) == 0) { |
| |
| DSIGTransformXSL * x; |
| XSECnew(x, DSIGTransformXSL(env, transforms)); |
| lst->addTransform(x); |
| x->load(); |
| |
| } |
| |
| |
| else if (algorithm.sbStrcmp(URI_ID_C14N_COM) == 0 || |
| algorithm.sbStrcmp(URI_ID_C14N_NOC) == 0 || |
| algorithm.sbStrcmp(URI_ID_C14N11_COM) == 0 || |
| algorithm.sbStrcmp(URI_ID_C14N11_NOC) == 0 || |
| algorithm.sbStrcmp(URI_ID_EXC_C14N_COM) == 0 || |
| algorithm.sbStrcmp(URI_ID_EXC_C14N_NOC) == 0) { |
| |
| DSIGTransformC14n * c; |
| XSECnew(c, DSIGTransformC14n(env, transforms)); |
| lst->addTransform(c); |
| c->load(); |
| |
| } |
| |
| else { |
| |
| // Not what we expected to see! |
| safeBuffer tmp; |
| |
| tmp.sbStrcpyIn("Unknown transform : "); |
| tmp.sbStrcatIn(algorithm); |
| tmp.sbStrcatIn(" found."); |
| |
| throw XSECException(XSECException::UnknownTransform, tmp.rawCharBuffer()); |
| } |
| |
| // Now find next element |
| |
| transforms = transforms->getNextSibling(); |
| while (transforms != NULL && transforms->getNodeType() != DOMNode::ELEMENT_NODE) |
| transforms = transforms->getNextSibling(); |
| |
| } /* while (transforms != NULL) */ |
| |
| j_lst.release(); |
| return lst; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Set hash |
| // -------------------------------------------------------------------------------- |
| |
| void DSIGReference::setHash(void) { |
| |
| // Set up |
| |
| if (mp_hashValueNode == 0) { |
| throw XSECException(XSECException::NotLoaded, |
| "setHash() called in DSIGReference before load()"); |
| } |
| |
| unsigned int maxHashSize = XSECPlatformUtils::g_cryptoProvider->getMaxHashSize(); |
| |
| XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64(); |
| if (!b64) { |
| throw XSECException(XSECException::CryptoProviderError, |
| "Error requesting Base64 object from Crypto Provider"); |
| } |
| |
| Janitor<XSECCryptoBase64> j_b64(b64); |
| |
| // First determine the hash value |
| XMLByte* calculatedHashVal = new XMLByte[maxHashSize]; |
| XMLByte* base64Hash = new XMLByte[maxHashSize * 2]; |
| |
| unsigned int base64HashLen = 0; |
| |
| try { |
| unsigned int calculatedHashLen = calculateHash(calculatedHashVal, maxHashSize); |
| |
| // Calculate the base64 value |
| b64->encodeInit(); |
| base64HashLen = b64->encode(calculatedHashVal, |
| calculatedHashLen, |
| base64Hash, |
| maxHashSize * 2); |
| base64HashLen += b64->encodeFinish(&base64Hash[base64HashLen], |
| (maxHashSize * 2) - base64HashLen); |
| } |
| catch (...) { |
| delete[] calculatedHashVal; |
| delete[] base64Hash; |
| throw; |
| } |
| |
| delete[] calculatedHashVal; |
| |
| // Ensure the string is terminated |
| if (base64Hash[base64HashLen-1] == '\n') |
| base64Hash[base64HashLen-1] = '\0'; |
| else |
| base64Hash[base64HashLen] = '\0'; |
| |
| // Now find the correct text node to re-set |
| |
| DOMNode* tmpElt = mp_hashValueNode->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_referenceNode->getOwnerDocument(); |
| tmpElt = doc->createTextNode(MAKE_UNICODE_STRING((char *) base64Hash)); |
| mp_hashValueNode->appendChild(tmpElt); |
| } |
| else { |
| tmpElt->setNodeValue(MAKE_UNICODE_STRING((char *) base64Hash)); |
| } |
| |
| delete[] base64Hash; |
| } |
| |
| |
| |
| |
| // -------------------------------------------------------------------------------- |
| // Create hash |
| // -------------------------------------------------------------------------------- |
| |
| unsigned int DSIGReference::calculateHash(XMLByte *toFill, unsigned int maxToFill) const { |
| |
| // Determine the hash value of the element |
| |
| // First set up for input |
| |
| TXFMBase * currentTxfm; |
| TXFMChain * chain; |
| |
| unsigned int size; |
| |
| if (m_loaded == false) { |
| |
| throw XSECException(XSECException::NotLoaded, |
| "calculateHash() called in DSIGReference before load()"); |
| |
| } |
| |
| // Find base transform |
| currentTxfm = getURIBaseTXFM(mp_referenceNode->getOwnerDocument(), mp_URI, |
| mp_env); |
| |
| // Now build the transforms list |
| // Note this passes ownership of currentTxfm to the function, so it is the |
| // responsibility of createTXFMChain to ensure it gets deleted if this throws. |
| |
| chain = createTXFMChainFromList(currentTxfm, mp_transformList); |
| Janitor<TXFMChain> j_chain(chain); |
| |
| DOMDocument *d = mp_referenceNode->getOwnerDocument(); |
| |
| // All transforms done. If necessary, change the type from nodes to bytes |
| |
| if (chain->getLastTxfm()->getOutputType() == TXFMBase::DOM_NODES) { |
| |
| TXFMC14n * c14n; |
| XSECnew(c14n, TXFMC14n(d)); |
| chain->appendTxfm(c14n); |
| |
| } |
| |
| // Check to see if there is a final "application" transform prior to the hash |
| |
| if (mp_preHash != NULL) { |
| |
| chain->appendTxfm(mp_preHash); |
| mp_preHash = NULL; // Can't be re-used |
| |
| } |
| |
| // Check for debugging sink for the data |
| TXFMBase* sink = XSECPlatformUtils::GetReferenceLoggingSink(d); |
| if (sink) |
| chain->appendTxfm(sink); |
| |
| |
| // Get the mapping for the hash transform |
| |
| XSECAlgorithmHandler * handler = |
| XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(mp_algorithmURI); |
| |
| if (handler == NULL) { |
| |
| |
| throw XSECException(XSECException::SigVfyError, |
| "Hash method unknown in DSIGReference::calculateHash()"); |
| |
| } |
| |
| if (!handler->appendHashTxfm(chain, mp_algorithmURI)) { |
| |
| throw XSECException(XSECException::SigVfyError, |
| "Unexpected error in handler whilst appending Hash transform"); |
| |
| } |
| |
| // Now we have the hashing transform, run it. |
| |
| size = chain->getLastTxfm()->readBytes(toFill, maxToFill); |
| |
| // Clean out document if necessary |
| chain->getLastTxfm()->deleteExpandedNameSpaces(); |
| |
| return size; |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Read hash |
| // -------------------------------------------------------------------------------- |
| |
| unsigned int DSIGReference::readHash(XMLByte *toFill, unsigned int maxToFill) const { |
| |
| // Determine the hash value stored in the reference |
| |
| // First set up for input |
| |
| unsigned int size; |
| DOMNode *tmpElt; |
| //const XMLCh * stringHash; |
| |
| TXFMBase * nextInput; |
| |
| DOMDocument *d = mp_referenceNode->getOwnerDocument(); |
| |
| safeBuffer b64HashVal; |
| |
| // Find the hash value |
| |
| tmpElt = mp_referenceNode->getFirstChild(); |
| |
| while (tmpElt != 0 && !strEquals(getDSIGLocalName(tmpElt), "DigestValue")) |
| tmpElt = tmpElt->getNextSibling(); |
| |
| if (tmpElt == NULL) |
| // ERROR |
| return 0; |
| |
| // Now read the DOMString of the hash |
| |
| tmpElt = tmpElt->getFirstChild(); |
| while (tmpElt != NULL && tmpElt->getNodeType() != DOMNode::TEXT_NODE) |
| tmpElt = tmpElt->getNextSibling(); |
| |
| if (tmpElt == NULL) |
| // Something wrong with the underlying XML if no text was found |
| throw XSECException(XSECException::NoHashFoundInDigestValue); |
| |
| b64HashVal << (*mp_formatter << tmpElt->getNodeValue()); |
| |
| // Now have the value of the string - create a transform around it |
| |
| XSECnew(nextInput, TXFMSB(d)); |
| ((TXFMSB *) nextInput)->setInput(b64HashVal); |
| |
| // Create a transform chain (really as a janitor for the entire list) |
| TXFMChain * chain; |
| XSECnew(chain, TXFMChain(nextInput)); |
| Janitor<TXFMChain> j_chain(chain); |
| |
| // Now create the base64 transform |
| |
| XSECnew(nextInput, TXFMBase64(d)); |
| chain->appendTxfm(nextInput); |
| |
| // Now get the value |
| |
| size = chain->getLastTxfm()->readBytes(toFill, maxToFill); |
| |
| // Clear any documentat modifications |
| |
| chain->getLastTxfm()->deleteExpandedNameSpaces(); |
| |
| return size; |
| |
| } |
| |
| |
| |
| // -------------------------------------------------------------------------------- |
| // Check a reference |
| // -------------------------------------------------------------------------------- |
| |
| bool DSIGReference::checkHash() const { |
| |
| // Determine the hash value of the element and check if matches that stored in the |
| // DigestValue part of the element |
| |
| // First set up for input |
| |
| unsigned int maxHashSize = XSECPlatformUtils::g_cryptoProvider->getMaxHashSize(); |
| |
| XMLByte* calculatedHashVal = new XMLByte[maxHashSize]; // The hash that we determined |
| |
| unsigned int calculatedHashSize; |
| |
| try { |
| if ((calculatedHashSize = calculateHash(calculatedHashVal, maxHashSize)) == 0) |
| return false; |
| } |
| catch (...) { |
| delete[] calculatedHashVal; |
| throw; |
| } |
| |
| XMLByte* readHashVal = new XMLByte [maxHashSize]; // The hash in the element |
| |
| if (readHash(readHashVal, maxHashSize) != calculatedHashSize) { |
| delete[] calculatedHashVal; |
| delete[] readHashVal; |
| return false; |
| } |
| |
| for (unsigned int i = 0; i < calculatedHashSize; ++i) { |
| if (calculatedHashVal[i] != readHashVal[i]) { |
| delete[] calculatedHashVal; |
| delete[] readHashVal; |
| return false; |
| } |
| |
| } |
| |
| delete[] calculatedHashVal; |
| delete[] readHashVal; |
| |
| // Got through with flying colours! |
| return true; |
| |
| } |