internal void LoadXml(XmlElement value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } XmlNamespaceManager nsm = new XmlNamespaceManager(value.OwnerDocument.NameTable); nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); XmlNodeList transformNodes = value.SelectNodes("ds:Transform", nsm); if (transformNodes.Count == 0) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Transforms"); } _transforms.Clear(); for (int i = 0; i < transformNodes.Count; ++i) { XmlElement transformElement = (XmlElement)transformNodes.Item(i); string algorithm = Utils.GetAttribute(transformElement, "Algorithm", SignedXml.XmlDsigNamespaceUrl); Transform transform = CryptoHelpers.CreateFromName <Transform>(algorithm); if (transform == null) { throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform); } // let the transform read the children of the transformElement for data transform.LoadInnerXml(transformElement.ChildNodes); _transforms.Add(transform); } }
/// <summary> /// Log the hash comparison when verifying a reference /// </summary> /// <param name="signedXml">SignedXml object verifying the signature</param> /// <param name="reference">reference being verified</param> /// <param name="actualHash">actual hash value of the reference</param> /// <param name="expectedHash">hash value the signature expected the reference to have</param> internal static void LogVerifyReferenceHash(SignedXml signedXml, Reference reference, byte[] actualHash, byte[] expectedHash) { Debug.Assert(signedXml != null, "signedXml != null"); Debug.Assert(reference != null, "reference != null"); Debug.Assert(actualHash != null, "actualHash != null"); Debug.Assert(expectedHash != null, "expectedHash != null"); if (VerboseLoggingEnabled) { HashAlgorithm hashAlgorithm = CryptoHelpers.CreateFromName <HashAlgorithm>(reference.DigestMethod); string hashAlgorithmName = hashAlgorithm == null ? "null" : hashAlgorithm.GetType().Name; string logMessage = SR.Format(CultureInfo.InvariantCulture, SR.Log_ReferenceHash, GetObjectId(reference), reference.DigestMethod, hashAlgorithmName, FormatBytes(actualHash), FormatBytes(expectedHash)); WriteLine(signedXml, TraceEventType.Verbose, SignedXmlDebugEvent.VerifyReference, logMessage); } }
// Validation function to see if the current signature is signed with a truncated HMAC - one which // has a signature length of fewer bits than the whole HMAC output. private bool DoesSignatureUseTruncatedHmac() { // If we're not using the SignatureLength property, then we're not truncating the signature length if (SignedInfo.SignatureLength == null) { return(false); } // See if we're signed witn an HMAC algorithm HMAC hmac = CryptoHelpers.CreateFromName <HMAC>(SignatureMethod); if (hmac == null) { // We aren't signed with an HMAC algorithm, so we cannot have a truncated HMAC return(false); } // Figure out how many bits the signature is using int actualSignatureSize = 0; if (!int.TryParse(SignedInfo.SignatureLength, out actualSignatureSize)) { // If the value wasn't a valid integer, then we'll conservatively reject it all together return(true); } // Make sure the full HMAC signature size is the same size that was specified in the XML // signature. If the actual signature size is not exactly the same as the full HMAC size, then // reject the signature. return(actualSignatureSize != hmac.HashSize); }
public void LoadXml(XmlElement value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } XmlElement keyInfoElement = value; _id = Utils.GetAttribute(keyInfoElement, "Id", SignedXml.XmlDsigNamespaceUrl); if (!Utils.VerifyAttributes(keyInfoElement, "Id")) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "KeyInfo"); } XmlNode child = keyInfoElement.FirstChild; while (child != null) { XmlElement elem = child as XmlElement; if (elem != null) { // Create the right type of KeyInfoClause; we use a combination of the namespace and tag name (local name) string kicString = elem.NamespaceURI + " " + elem.LocalName; // Special-case handling for KeyValue -- we have to go one level deeper if (kicString == "http://www.w3.org/2000/09/xmldsig# KeyValue") { if (!Utils.VerifyAttributes(elem, (string[])null)) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "KeyInfo/KeyValue"); } XmlNodeList nodeList2 = elem.ChildNodes; foreach (XmlNode node2 in nodeList2) { XmlElement elem2 = node2 as XmlElement; if (elem2 != null) { kicString += "/" + elem2.LocalName; break; } } } KeyInfoClause keyInfoClause = CryptoHelpers.CreateFromName <KeyInfoClause>(kicString); // if we don't know what kind of KeyInfoClause we're looking at, use a generic KeyInfoNode: if (keyInfoClause == null) { keyInfoClause = new KeyInfoNode(); } // Ask the create clause to fill itself with the corresponding XML keyInfoClause.LoadXml(elem); // Add it to our list of KeyInfoClauses AddClause(keyInfoClause); } child = child.NextSibling; } }
public void ComputeSignature() { SignedXmlDebugLog.LogBeginSignatureComputation(this, _context); BuildDigestedReferences(); // Load the key AsymmetricAlgorithm key = SigningKey; if (key == null) { throw new CryptographicException(SR.Cryptography_Xml_LoadKeyFailed); } // Check the signature algorithm associated with the key so that we can accordingly set the signature method if (SignedInfo.SignatureMethod == null) { if (key is DSA) { SignedInfo.SignatureMethod = XmlDsigDSAUrl; } else if (key is RSA) { // Default to RSA-SHA1 if (SignedInfo.SignatureMethod == null) { SignedInfo.SignatureMethod = XmlDsigRSASHA256Url; } } else { throw new CryptographicException(SR.Cryptography_Xml_CreatedKeyFailed); } } // See if there is a signature description class defined in the Config file SignatureDescription signatureDescription = CryptoHelpers.CreateFromName <SignatureDescription>(SignedInfo.SignatureMethod); if (signatureDescription == null) { throw new CryptographicException(SR.Cryptography_Xml_SignatureDescriptionNotCreated); } HashAlgorithm hashAlg = signatureDescription.CreateDigest(); if (hashAlg == null) { throw new CryptographicException(SR.Cryptography_Xml_CreateHashAlgorithmFailed); } byte[] hashvalue = GetC14NDigest(hashAlg); AsymmetricSignatureFormatter asymmetricSignatureFormatter = signatureDescription.CreateFormatter(key); SignedXmlDebugLog.LogSigning(this, key, signatureDescription, hashAlg, asymmetricSignatureFormatter); m_signature.SignatureValue = asymmetricSignatureFormatter.CreateSignature(hashAlg); }
private bool CheckSignedInfo(AsymmetricAlgorithm key) { if (key == null) { throw new ArgumentNullException(nameof(key)); } SignedXmlDebugLog.LogBeginCheckSignedInfo(this, m_signature.SignedInfo); SignatureDescription signatureDescription = CryptoHelpers.CreateFromName <SignatureDescription>(SignatureMethod); if (signatureDescription == null) { throw new CryptographicException(SR.Cryptography_Xml_SignatureDescriptionNotCreated); } // Let's see if the key corresponds with the SignatureMethod Type ta = Type.GetType(signatureDescription.KeyAlgorithm); if (!IsKeyTheCorrectAlgorithm(key, ta)) { return(false); } HashAlgorithm hashAlgorithm = signatureDescription.CreateDigest(); if (hashAlgorithm == null) { throw new CryptographicException(SR.Cryptography_Xml_CreateHashAlgorithmFailed); } byte[] hashval = GetC14NDigest(hashAlgorithm); AsymmetricSignatureDeformatter asymmetricSignatureDeformatter = signatureDescription.CreateDeformatter(key); SignedXmlDebugLog.LogVerifySignedInfo(this, key, signatureDescription, hashAlgorithm, asymmetricSignatureDeformatter, hashval, m_signature.SignatureValue); return(asymmetricSignatureDeformatter.VerifySignature(hashval, m_signature.SignatureValue)); }
/// <summary> /// Write information when user hits the Signed XML recursion depth limit issue. /// This is helpful in debugging this kind of issues. /// </summary> /// <param name="signedXml">SignedXml object verifying the signature</param> /// <param name="reference">reference being verified</param> internal static void LogSignedXmlRecursionLimit(SignedXml signedXml, Reference reference) { Debug.Assert(signedXml != null, "signedXml != null"); Debug.Assert(reference != null, "reference != null"); if (InformationLoggingEnabled) { HashAlgorithm hashAlgorithm = CryptoHelpers.CreateFromName <HashAlgorithm>(reference.DigestMethod); string hashAlgorithmName = hashAlgorithm == null ? "null" : hashAlgorithm.GetType().Name; string logMessage = SR.Format(CultureInfo.InvariantCulture, SR.Log_SignedXmlRecursionLimit, GetObjectId(reference), reference.DigestMethod, hashAlgorithmName); WriteLine(signedXml, TraceEventType.Information, SignedXmlDebugEvent.VerifySignedInfo, logMessage); } }
// Try to decrypt the EncryptedKey given the key mapping public virtual byte[] DecryptEncryptedKey(EncryptedKey encryptedKey) { if (encryptedKey == null) { throw new ArgumentNullException(nameof(encryptedKey)); } if (encryptedKey.KeyInfo == null) { return(null); } IEnumerator keyInfoEnum = encryptedKey.KeyInfo.GetEnumerator(); KeyInfoName kiName; KeyInfoX509Data kiX509Data; KeyInfoRetrievalMethod kiRetrievalMethod; KeyInfoEncryptedKey kiEncKey; EncryptedKey ek = null; bool fOAEP = false; while (keyInfoEnum.MoveNext()) { kiName = keyInfoEnum.Current as KeyInfoName; if (kiName != null) { // Get the decryption key from the key mapping string keyName = kiName.Value; object kek = _keyNameMapping[keyName]; if (kek != null) { if (encryptedKey.CipherData == null || encryptedKey.CipherData.CipherValue == null) { throw new CryptographicException(SR.Cryptography_Xml_MissingAlgorithm); } // kek is either a SymmetricAlgorithm or an RSA key, otherwise, we wouldn't be able to insert it in the hash table if (kek is SymmetricAlgorithm) { return(EncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, (SymmetricAlgorithm)kek)); } // kek is an RSA key: get fOAEP from the algorithm, default to false fOAEP = (encryptedKey.EncryptionMethod != null && encryptedKey.EncryptionMethod.KeyAlgorithm == EncryptedXml.XmlEncRSAOAEPUrl); return(EncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, (RSA)kek, fOAEP)); } break; } kiX509Data = keyInfoEnum.Current as KeyInfoX509Data; if (kiX509Data != null) { X509Certificate2Collection collection = Utils.BuildBagOfCerts(kiX509Data, CertUsageType.Decryption); foreach (X509Certificate2 certificate in collection) { using (RSA privateKey = certificate.GetRSAPrivateKey()) { if (privateKey != null) { if (encryptedKey.CipherData == null || encryptedKey.CipherData.CipherValue == null) { throw new CryptographicException(SR.Cryptography_Xml_MissingAlgorithm); } fOAEP = (encryptedKey.EncryptionMethod != null && encryptedKey.EncryptionMethod.KeyAlgorithm == EncryptedXml.XmlEncRSAOAEPUrl); return(EncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, privateKey, fOAEP)); } } } break; } kiRetrievalMethod = keyInfoEnum.Current as KeyInfoRetrievalMethod; if (kiRetrievalMethod != null) { string idref = Utils.ExtractIdFromLocalUri(kiRetrievalMethod.Uri); ek = new EncryptedKey(); ek.LoadXml(GetIdElement(_document, idref)); try { //Following checks if XML dsig processing is in loop and within the limit defined by machine // admin or developer. Once the recursion depth crosses the defined limit it will throw exception. _xmlDsigSearchDepthCounter++; if (IsOverXmlDsigRecursionLimit()) { //Throw exception once recursion limit is hit. throw new CryptoSignedXmlRecursionException(); } else { return(DecryptEncryptedKey(ek)); } } finally { _xmlDsigSearchDepthCounter--; } } kiEncKey = keyInfoEnum.Current as KeyInfoEncryptedKey; if (kiEncKey != null) { ek = kiEncKey.EncryptedKey; // recursively process EncryptedKey elements byte[] encryptionKey = DecryptEncryptedKey(ek); if (encryptionKey != null) { // this is a symmetric algorithm for sure SymmetricAlgorithm symAlg = CryptoHelpers.CreateFromName <SymmetricAlgorithm>(encryptedKey.EncryptionMethod.KeyAlgorithm); if (symAlg == null) { throw new CryptographicException(SR.Cryptography_Xml_MissingAlgorithm); } symAlg.Key = encryptionKey; if (encryptedKey.CipherData == null || encryptedKey.CipherData.CipherValue == null) { throw new CryptographicException(SR.Cryptography_Xml_MissingAlgorithm); } symAlg.Key = encryptionKey; return(EncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, symAlg)); } } } return(null); }
// default behaviour is to look for keys defined by an EncryptedKey clause // either directly or through a KeyInfoRetrievalMethod, and key names in the key mapping public virtual SymmetricAlgorithm GetDecryptionKey(EncryptedData encryptedData, string symmetricAlgorithmUri) { if (encryptedData == null) { throw new ArgumentNullException(nameof(encryptedData)); } if (encryptedData.KeyInfo == null) { return(null); } IEnumerator keyInfoEnum = encryptedData.KeyInfo.GetEnumerator(); KeyInfoRetrievalMethod kiRetrievalMethod; KeyInfoName kiName; KeyInfoEncryptedKey kiEncKey; EncryptedKey ek = null; while (keyInfoEnum.MoveNext()) { kiName = keyInfoEnum.Current as KeyInfoName; if (kiName != null) { // Get the decryption key from the key mapping string keyName = kiName.Value; if ((SymmetricAlgorithm)_keyNameMapping[keyName] != null) { return((SymmetricAlgorithm)_keyNameMapping[keyName]); } // try to get it from a CarriedKeyName XmlNamespaceManager nsm = new XmlNamespaceManager(_document.NameTable); nsm.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl); XmlNodeList encryptedKeyList = _document.SelectNodes("//enc:EncryptedKey", nsm); if (encryptedKeyList != null) { foreach (XmlNode encryptedKeyNode in encryptedKeyList) { XmlElement encryptedKeyElement = encryptedKeyNode as XmlElement; EncryptedKey ek1 = new EncryptedKey(); ek1.LoadXml(encryptedKeyElement); if (ek1.CarriedKeyName == keyName && ek1.Recipient == Recipient) { ek = ek1; break; } } } break; } kiRetrievalMethod = keyInfoEnum.Current as KeyInfoRetrievalMethod; if (kiRetrievalMethod != null) { string idref = Utils.ExtractIdFromLocalUri(kiRetrievalMethod.Uri); ek = new EncryptedKey(); ek.LoadXml(GetIdElement(_document, idref)); break; } kiEncKey = keyInfoEnum.Current as KeyInfoEncryptedKey; if (kiEncKey != null) { ek = kiEncKey.EncryptedKey; break; } } // if we have an EncryptedKey, decrypt to get the symmetric key if (ek != null) { // now process the EncryptedKey, loop recursively // If the Uri is not provided by the application, try to get it from the EncryptionMethod if (symmetricAlgorithmUri == null) { if (encryptedData.EncryptionMethod == null) { throw new CryptographicException(SR.Cryptography_Xml_MissingAlgorithm); } symmetricAlgorithmUri = encryptedData.EncryptionMethod.KeyAlgorithm; } byte[] key = DecryptEncryptedKey(ek); if (key == null) { throw new CryptographicException(SR.Cryptography_Xml_MissingDecryptionKey); } SymmetricAlgorithm symAlg = CryptoHelpers.CreateFromName <SymmetricAlgorithm>(symmetricAlgorithmUri); if (symAlg == null) { throw new CryptographicException(SR.Cryptography_Xml_MissingAlgorithm); } symAlg.Key = key; return(symAlg); } return(null); }
// 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); }
public void LoadXml(XmlElement value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } _id = Utils.GetAttribute(value, "Id", SignedXml.XmlDsigNamespaceUrl); _uri = Utils.GetAttribute(value, "URI", SignedXml.XmlDsigNamespaceUrl); _type = Utils.GetAttribute(value, "Type", SignedXml.XmlDsigNamespaceUrl); if (!Utils.VerifyAttributes(value, new string[] { "Id", "URI", "Type" })) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference"); } XmlNamespaceManager nsm = new XmlNamespaceManager(value.OwnerDocument.NameTable); nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); // Transforms bool hasTransforms = false; TransformChain = new TransformChain(); XmlNodeList transformsNodes = value.SelectNodes("ds:Transforms", nsm); if (transformsNodes != null && transformsNodes.Count != 0) { if (transformsNodes.Count > 1) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference/Transforms"); } hasTransforms = true; XmlElement transformsElement = transformsNodes[0] as XmlElement; if (!Utils.VerifyAttributes(transformsElement, (string[])null)) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference/Transforms"); } XmlNodeList transformNodes = transformsElement.SelectNodes("ds:Transform", nsm); if (transformNodes != null) { if (transformNodes.Count != transformsElement.SelectNodes("*").Count) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference/Transforms"); } if (transformNodes.Count > Utils.MaxTransformsPerReference) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference/Transforms"); } foreach (XmlNode transformNode in transformNodes) { XmlElement transformElement = transformNode as XmlElement; string algorithm = Utils.GetAttribute(transformElement, "Algorithm", SignedXml.XmlDsigNamespaceUrl); if (algorithm == null || !Utils.VerifyAttributes(transformElement, "Algorithm")) { throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform); } Transform transform = CryptoHelpers.CreateFromName <Transform>(algorithm); if (transform == null) { throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform); } AddTransform(transform); // let the transform read the children of the transformElement for data transform.LoadInnerXml(transformElement.ChildNodes); // Hack! this is done to get around the lack of here() function support in XPath if (transform is XmlDsigEnvelopedSignatureTransform) { // Walk back to the Signature tag. Find the nearest signature ancestor // Signature-->SignedInfo-->Reference-->Transforms-->Transform XmlNode signatureTag = transformElement.SelectSingleNode("ancestor::ds:Signature[1]", nsm); XmlNodeList signatureList = transformElement.SelectNodes("//ds:Signature", nsm); if (signatureList != null) { int position = 0; foreach (XmlNode node in signatureList) { position++; if (node == signatureTag) { ((XmlDsigEnvelopedSignatureTransform)transform).SignaturePosition = position; break; } } } } } } } // DigestMethod XmlNodeList digestMethodNodes = value.SelectNodes("ds:DigestMethod", nsm); if (digestMethodNodes == null || digestMethodNodes.Count == 0 || digestMethodNodes.Count > 1) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference/DigestMethod"); } XmlElement digestMethodElement = digestMethodNodes[0] as XmlElement; _digestMethod = Utils.GetAttribute(digestMethodElement, "Algorithm", SignedXml.XmlDsigNamespaceUrl); if (_digestMethod == null || !Utils.VerifyAttributes(digestMethodElement, "Algorithm")) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference/DigestMethod"); } // DigestValue XmlNodeList digestValueNodes = value.SelectNodes("ds:DigestValue", nsm); if (digestValueNodes == null || digestValueNodes.Count == 0 || digestValueNodes.Count > 1) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference/DigestValue"); } XmlElement digestValueElement = digestValueNodes[0] as XmlElement; _digestValue = Convert.FromBase64String(Utils.DiscardWhiteSpaces(digestValueElement.InnerText)); if (!Utils.VerifyAttributes(digestValueElement, (string[])null)) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference/DigestValue"); } // Verify that there aren't any extra nodes that aren't allowed int expectedChildNodeCount = hasTransforms ? 3 : 2; if (value.SelectNodes("*").Count != expectedChildNodeCount) { throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "Reference"); } // cache the Xml _cachedXml = value; }