// What we want to do is pump the input throug the TransformChain and then // hash the output of the chain // document is the document context for resolving relative references internal byte[] CalculateHashValue(XmlDocument document, CanonicalXmlNodeList refList) { // refList is a list of elements that might be targets of references // Now's the time to create our hashing algorithm m_hashAlgorithm = (HashAlgorithm)CryptoConfig.CreateFromName(DigestMethod); if (m_hashAlgorithm == null) { throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_CreateHashAlgorithmFailed")); } string strBaseUri = (document == null ? null : document.BaseURI); // For interop w/ Petteri & IBM -- may not be required by the spec //if (m_transforms.Count == 0) { //if (DataObject != null && DataObject.Data != null) { //AddTransform(new W3cCanonicalization()); //} //} // Let's go get the target. Stream hashInputStream; WebRequest theRequest = null; WebResponse theResponse = null; Stream inputStream = null; XmlResolver resolver = null; switch (m_refTargetType) { case ReferenceTargetType.Stream: // This is the easiest case. We already have a stream, so just pump it through // the TransformChain resolver = (m_signedXml.ResolverSet ? m_signedXml.m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), strBaseUri)); hashInputStream = m_transformChain.TransformToOctetStream((Stream)m_refTarget, resolver, strBaseUri); break; case ReferenceTargetType.UriReference: // Second-easiest case -- dereference the URI & pump through the TransformChain // handle the special cases where the URI is null (meaning whole doc) // or the URI is just a fragment (meaning a reference to an embedded Object) if (m_strUri == "") { // This is the self-referential case. // The Enveloped Signature does not discard comments as per spec; those will be omitted during the transform chain process // First, check that we have a document context. if (document == null) { throw new CryptographicException(String.Format(SecurityResources.GetResourceString("Cryptography_Xml_SelfReferenceRequiresContext"), m_strUri)); } // Normalize the containing document resolver = (m_signedXml.ResolverSet ? m_signedXml.m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), strBaseUri)); XmlDocument docWithNoComments = CanonicalXml.DiscardComments(SignedXml.PreProcessDocumentInput(document, resolver, strBaseUri)); hashInputStream = m_transformChain.TransformToOctetStream(docWithNoComments, resolver, strBaseUri); } else if (m_strUri[0] == '#') { // If we get here, then we are constructing a Reference to an embedded DataObject // referenced by an Id= attribute. Go find the relevant object String idref = m_strUri.Substring(1); bool bDiscardComments = true; // Deal with XPointer of types #xpointer(/) and #xpointer(id("ID")). Other XPointer support isn't handled here and is anyway optional if (idref == "xpointer(/)") { // This is a self referencial case if (document == null) { throw new CryptographicException(String.Format(SecurityResources.GetResourceString("Cryptography_Xml_SelfReferenceRequiresContext"), m_strUri)); } // We should not discard comments here!!! resolver = (m_signedXml.ResolverSet ? m_signedXml.m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), strBaseUri)); hashInputStream = m_transformChain.TransformToOctetStream(SignedXml.PreProcessDocumentInput(document, resolver, strBaseUri), resolver, strBaseUri); goto end; } else if (idref.StartsWith("xpointer(id(")) { int startId = idref.IndexOf("id("); int endId = idref.IndexOf(")"); if (endId < 0 || endId < startId + 3) { throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidReference")); } idref = idref.Substring(startId + 3, endId - startId - 3); idref = idref.Replace("\'", ""); idref = idref.Replace("\"", ""); bDiscardComments = false; } XmlElement elem = m_signedXml.GetIdElement(document, idref); if (elem == null) { // Go throw the referenced items passed in if (refList != null) { foreach (XmlNode node in refList) { XmlElement tempElem = node as XmlElement; if ((tempElem != null) && (tempElem.HasAttribute("Id")) && (tempElem.GetAttribute("Id").Equals(idref))) { elem = tempElem; break; } } } } if (elem == null) { throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidReference")); } // Add the propagated attributes, clone the element first XmlElement elemClone = elem.Clone() as XmlElement; if (m_namespaces != null) { foreach (XmlNode attrib in m_namespaces) { string name = ((attrib.Prefix != String.Empty) ? attrib.Prefix + ":" + attrib.LocalName : attrib.LocalName); // Skip the attribute if one with the same qualified name already exists if (elemClone.HasAttribute(name) || (name.Equals("xmlns") && elemClone.NamespaceURI != String.Empty)) { continue; } XmlAttribute nsattrib = (XmlAttribute)elemClone.OwnerDocument.CreateAttribute(name); nsattrib.Value = attrib.Value; elemClone.SetAttributeNode(nsattrib); } } if (bDiscardComments) { // We should discard comments before going into the transform chain resolver = (m_signedXml.ResolverSet ? m_signedXml.m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), strBaseUri)); XmlDocument docWithNoComments = CanonicalXml.DiscardComments(SignedXml.PreProcessElementInput(elemClone, resolver, strBaseUri)); hashInputStream = m_transformChain.TransformToOctetStream(docWithNoComments, resolver, strBaseUri); } else { // This is an XPointer reference, do not discard comments!!! resolver = (m_signedXml.ResolverSet ? m_signedXml.m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), strBaseUri)); hashInputStream = m_transformChain.TransformToOctetStream(SignedXml.PreProcessElementInput(elemClone, resolver, strBaseUri), resolver, strBaseUri); } } else { theRequest = WebRequest.Create(m_strUri); if (theRequest == null) { goto default; } theResponse = theRequest.GetResponse(); if (theResponse == null) { goto default; } inputStream = theResponse.GetResponseStream(); if (inputStream == null) { goto default; } resolver = (m_signedXml.ResolverSet ? m_signedXml.m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), m_strUri)); hashInputStream = m_transformChain.TransformToOctetStream(inputStream, resolver, m_strUri); } break; case ReferenceTargetType.XmlElement: // We need to create a DocumentNavigator out of the XmlElement resolver = (m_signedXml.ResolverSet ? m_signedXml.m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), strBaseUri)); hashInputStream = m_transformChain.TransformToOctetStream(SignedXml.PreProcessElementInput((XmlElement)m_refTarget, resolver, strBaseUri), resolver, strBaseUri); break; default: throw new CryptographicException(); } end: // Compute the new hash value byte[] hashval = m_hashAlgorithm.ComputeHash(hashInputStream); // Close the response to free resources, before returning if (theResponse != null) { theResponse.Close(); } if (inputStream != null) { inputStream.Close(); } return(hashval); }