// 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 _hashAlgorithm = CryptoHelpers.CreateFromName <HashAlgorithm>(_digestMethod); if (_hashAlgorithm == null) { throw new CryptographicException(SR.Cryptography_Xml_CreateHashAlgorithmFailed); } // Let's go get the target. string baseUri = (document == null ? System.Environment.CurrentDirectory + "\\" : document.BaseURI); Stream hashInputStream = null; WebResponse response = null; Stream inputStream = null; XmlResolver resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri)); byte[] hashval = null; try { switch (_refTargetType) { case ReferenceTargetType.Stream: // This is the easiest case. We already have a stream, so just pump it through the TransformChain hashInputStream = TransformChain.TransformToOctetStream((Stream)_refTarget, resolver, baseUri); 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 (_uri == null) { // In the case of a Uri-less reference, we will simply pass null to the transform chain. // The first transform in the chain is expected to know how to retrieve the data to hash. hashInputStream = TransformChain.TransformToOctetStream((Stream)null, resolver, baseUri); } else if (_uri.Length == 0 || _uri == "#xpointer(/)") { // This is the self-referential case. First, check that we have a document context. // The Enveloped Signature does not discard comments as per spec; those will be omitted during the transform chain process if (document == null) { throw new CryptographicException(SR.Format(SR.Cryptography_Xml_SelfReferenceRequiresContext, _uri)); } // Normalize the containing document XmlDocument doc = Utils.PreProcessDocumentInput(document, resolver, baseUri); // Remove comments only if URI is "" if (_uri.Length == 0) { Utils.DiscardComments(doc); } hashInputStream = TransformChain.TransformToOctetStream(doc, resolver, baseUri); } else if (_uri[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 bool discardComments = true; string idref = Utils.GetIdFromLocalUri(_uri, out discardComments); XmlElement elem = 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.SelectSingleNode("//*[@Id='" + idref + "']") as XmlElement; //XmlElement tempElem = node as XmlElement; //if ((tempElem != null) && (Utils.HasAttribute(tempElem, "Id", SignedXml.XmlDsigNamespaceUrl)) // && (Utils.GetAttribute(tempElem, "Id", SignedXml.XmlDsigNamespaceUrl).Equals(idref))) if (tempElem != null) { // copy fragment to document with root, create nodelsit elem = tempElem; XmlDocument doc = Utils.PreProcessElementInput(elem, resolver, baseUri); if (_signedXml._context != null) { CanonicalXmlNodeList namespaces = Utils.GetPropagatedAttributes(_signedXml._context); Utils.AddNamespaces(doc.DocumentElement, namespaces); } elem = doc.DocumentElement.FirstChild as XmlElement; break; } } } if (elem == null) { throw new CryptographicException(SR.Cryptography_Xml_InvalidReference); } } else { // create node list from document XmlDocument doc = Utils.PreProcessElementInput(elem, resolver, baseUri); CanonicalXmlNodeList namespaces = Utils.GetPropagatedAttributes(elem); Utils.AddNamespaces(doc.DocumentElement, namespaces); elem = doc.DocumentElement.FirstChild as XmlElement; } hashInputStream = TransformChain.TransformToOctetStream(Utils.AllDescendantNodes(elem, !discardComments), typeof(XmlNodeList), resolver, baseUri); } else { throw new CryptographicException(SR.Cryptography_Xml_UriNotResolved, _uri); } break; case ReferenceTargetType.XmlElement: // We need to create a DocumentNavigator out of the XmlElement hashInputStream = TransformChain.TransformToOctetStream(Utils.AllDescendantNodes((XmlNode)_refTarget, true), typeof(XmlNodeList), resolver, baseUri); break; default: throw new CryptographicException(SR.Cryptography_Xml_UriNotResolved, _uri); } // Compute the new hash value hashInputStream = SignedXmlDebugLog.LogReferenceData(this, hashInputStream); hashval = _hashAlgorithm.ComputeHash(hashInputStream); } finally { if (hashInputStream != null) { hashInputStream.Close(); } if (response != null) { response.Close(); } if (inputStream != null) { inputStream.Close(); } } return(hashval); }
/// <summary> /// Log that an X509 chain is being built for a certificate /// </summary> /// <param name="signedXml">SignedXml object building the chain</param> /// <param name="chain">chain built for the certificate</param> /// <param name="certificate">certificate having the chain built for it</param> internal static void LogVerifyX509Chain(SignedXml signedXml, X509Chain chain, X509Certificate certificate) { Debug.Assert(signedXml != null, "signedXml != null"); Debug.Assert(certificate != null, "certificate != null"); Debug.Assert(chain != null, "chain != null"); if (InformationLoggingEnabled) { string buildMessage = SR.Format(CultureInfo.InvariantCulture, SR.Log_BuildX509Chain, GetKeyName(certificate)); WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.X509Verification, buildMessage); } if (VerboseLoggingEnabled) { // Dump out the flags and other miscelanious information used for building string revocationMode = SR.Format(CultureInfo.InvariantCulture, SR.Log_RevocationMode, chain.ChainPolicy.RevocationFlag); WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, revocationMode); string revocationFlag = SR.Format(CultureInfo.InvariantCulture, SR.Log_RevocationFlag, chain.ChainPolicy.RevocationFlag); WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, revocationFlag); string verificationFlags = SR.Format(CultureInfo.InvariantCulture, SR.Log_VerificationFlag, chain.ChainPolicy.VerificationFlags); WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, verificationFlags); string verificationTime = SR.Format(CultureInfo.InvariantCulture, SR.Log_VerificationTime, chain.ChainPolicy.VerificationTime); WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, verificationTime); string urlTimeout = SR.Format(CultureInfo.InvariantCulture, SR.Log_UrlTimeout, chain.ChainPolicy.UrlRetrievalTimeout); WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, urlTimeout); } // If there were any errors in the chain, make sure to dump those out if (InformationLoggingEnabled) { foreach (X509ChainStatus status in chain.ChainStatus) { if (status.Status != X509ChainStatusFlags.NoError) { string logMessage = SR.Format(CultureInfo.InvariantCulture, SR.Log_X509ChainError, status.Status, status.StatusInformation); WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.X509Verification, logMessage); } } } // Finally, dump out the chain itself if (VerboseLoggingEnabled) { StringBuilder chainElements = new StringBuilder(); chainElements.Append(SR.Log_CertificateChain); foreach (X509ChainElement element in chain.ChainElements) { chainElements.AppendFormat(CultureInfo.InvariantCulture, " {0}", GetKeyName(element.Certificate)); } WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.X509Verification, chainElements.ToString()); } }