Ejemplo n.º 1
0
        // 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);
        }