Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / clr / src / ManagedLibraries / Security / System / Security / Cryptography / Xml / SignedXml.cs / 1 / SignedXml.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // // SignedXml.cs // // 21 [....] 2000 // namespace System.Security.Cryptography.Xml { using System; using System.Collections; using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Permissions; using System.Xml; [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public class SignedXml { ///protected Signature m_signature; /// protected string m_strSigningKeyName; private AsymmetricAlgorithm m_signingKey; private XmlDocument m_containingDocument = null; private IEnumerator m_keyInfoEnum = null; private X509Certificate2Collection m_x509Collection = null; private IEnumerator m_x509Enum = null; private bool[] m_refProcessed = null; private int[] m_refLevelCache = null; internal XmlResolver m_xmlResolver = null; internal XmlElement m_context = null; private bool m_bResolverSet = false; // additional HMAC Url identifiers private const string XmlDsigMoreHMACMD5Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-md5"; private const string XmlDsigMoreHMACSHA256Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"; private const string XmlDsigMoreHMACSHA384Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384"; private const string XmlDsigMoreHMACSHA512Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512"; private const string XmlDsigMoreHMACRIPEMD160Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160"; // defines the XML encryption processing rules private EncryptedXml m_exml = null; // // public constant Url identifiers most frequently used within the XML Signature classes // public const string XmlDsigNamespaceUrl = "http://www.w3.org/2000/09/xmldsig#"; public const string XmlDsigMinimalCanonicalizationUrl = "http://www.w3.org/2000/09/xmldsig#minimal"; public const string XmlDsigCanonicalizationUrl = XmlDsigC14NTransformUrl; public const string XmlDsigCanonicalizationWithCommentsUrl = XmlDsigC14NWithCommentsTransformUrl; public const string XmlDsigSHA1Url = "http://www.w3.org/2000/09/xmldsig#sha1"; public const string XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; public const string XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; public const string XmlDsigHMACSHA1Url = "http://www.w3.org/2000/09/xmldsig#hmac-sha1"; public const string XmlDsigC14NTransformUrl = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; public const string XmlDsigC14NWithCommentsTransformUrl = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"; public const string XmlDsigExcC14NTransformUrl = "http://www.w3.org/2001/10/xml-exc-c14n#"; public const string XmlDsigExcC14NWithCommentsTransformUrl = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"; public const string XmlDsigBase64TransformUrl = "http://www.w3.org/2000/09/xmldsig#base64"; public const string XmlDsigXPathTransformUrl = "http://www.w3.org/TR/1999/REC-xpath-19991116"; public const string XmlDsigXsltTransformUrl = "http://www.w3.org/TR/1999/REC-xslt-19991116"; public const string XmlDsigEnvelopedSignatureTransformUrl = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"; public const string XmlDecryptionTransformUrl = "http://www.w3.org/2002/07/decrypt#XML"; public const string XmlLicenseTransformUrl = "urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform"; // // public constructors // public SignedXml() { Initialize(null); } public SignedXml(XmlDocument document) { if (document == null) throw new ArgumentNullException("document"); Initialize(document.DocumentElement); } public SignedXml(XmlElement elem) { if (elem == null) throw new ArgumentNullException("elem"); Initialize(elem); } private void Initialize (XmlElement element) { m_containingDocument = (element == null ? null : element.OwnerDocument); m_context = element; m_signature = new Signature(); m_signature.SignedXml = this; m_signature.SignedInfo = new SignedInfo(); m_signingKey = null; } // // public properties // /// public string SigningKeyName { get { return m_strSigningKeyName; } set { m_strSigningKeyName = value; } } [ComVisible(false)] public XmlResolver Resolver { // This property only has a setter. The rationale for this is that we don't have a good value // to return when it has not been explicitely set, as we are using XmlSecureResolver by default set { m_xmlResolver = value; m_bResolverSet = true; } } internal bool ResolverSet { get { return m_bResolverSet; } } public AsymmetricAlgorithm SigningKey { get { return m_signingKey; } set { m_signingKey = value; } } [ComVisible(false)] public EncryptedXml EncryptedXml { get { if (m_exml == null) m_exml = new EncryptedXml(m_containingDocument); // default processing rules return m_exml; } set { m_exml = value; } } public Signature Signature { get { return m_signature; } } public SignedInfo SignedInfo { get { return m_signature.SignedInfo; } } public string SignatureMethod { get { return m_signature.SignedInfo.SignatureMethod; } } public string SignatureLength { get { return m_signature.SignedInfo.SignatureLength; } } public byte[] SignatureValue { get { return m_signature.SignatureValue; } } public KeyInfo KeyInfo { get { return m_signature.KeyInfo; } set { m_signature.KeyInfo = value; } } public XmlElement GetXml() { // If we have a document context, then return a signature element in this context if (m_containingDocument != null) return m_signature.GetXml(m_containingDocument); else return m_signature.GetXml(); } public void LoadXml(XmlElement value) { if (value == null) throw new ArgumentNullException("value"); m_signature.LoadXml(value); m_context = value; bCacheValid = false; } // // public methods // public void AddReference(Reference reference) { m_signature.SignedInfo.AddReference(reference); } public void AddObject(DataObject dataObject) { m_signature.AddObject(dataObject); } public bool CheckSignature() { bool bRet = false; AsymmetricAlgorithm key; do { key = GetPublicKey(); if (key != null) bRet = CheckSignature(key); } while (key != null && bRet == false); return bRet; } public bool CheckSignatureReturningKey(out AsymmetricAlgorithm signingKey) { bool bRet = false; AsymmetricAlgorithm key = null; do { key = GetPublicKey(); if (key != null) bRet = CheckSignature(key); } while (key != null && bRet == false); signingKey = key; return bRet; } public bool CheckSignature(AsymmetricAlgorithm key) { if (!CheckSignedInfo(key)) return false; // Now is the time to go through all the references and see if their DigestValues are good return CheckDigestedReferences(); } public bool CheckSignature(KeyedHashAlgorithm macAlg) { if (!CheckSignedInfo(macAlg)) return false; return CheckDigestedReferences(); } [ComVisible(false)] public bool CheckSignature(X509Certificate2 certificate, bool verifySignatureOnly) { if (!CheckSignedInfo(certificate.PublicKey.Key)) return false; // Now is the time to go through all the references and see if their DigestValues are good if (!CheckDigestedReferences()) return false; if (verifySignatureOnly) return true; // Check key usages to make sure it is good for signing. foreach (X509Extension extension in certificate.Extensions) { if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) { X509KeyUsageExtension keyUsage = new X509KeyUsageExtension(); keyUsage.CopyFrom(extension); if ((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == 0 && (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0) { return false; } break; } } // Do the chain verification to make sure the certificate is valid. X509Chain chain = new X509Chain(); chain.ChainPolicy.ExtraStore.AddRange(BuildBagOfCerts()); return chain.Build(certificate); } public void ComputeSignature() { BuildDigestedReferences(); // Load the key AsymmetricAlgorithm key = SigningKey; if (key == null) throw new CryptographicException(SecurityResources.GetResourceString("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 = XmlDsigRSASHA1Url; } else { throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_CreatedKeyFailed")); } } // See if there is a signature description class defined in the Config file SignatureDescription signatureDescription = CryptoConfig.CreateFromName(SignedInfo.SignatureMethod) as SignatureDescription; if (signatureDescription == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureDescriptionNotCreated")); HashAlgorithm hashAlg = signatureDescription.CreateDigest(); if (hashAlg == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_CreateHashAlgorithmFailed")); byte[] hashvalue = GetC14NDigest(hashAlg); AsymmetricSignatureFormatter asymmetricSignatureFormatter = signatureDescription.CreateFormatter(key); m_signature.SignatureValue = asymmetricSignatureFormatter.CreateSignature(hashAlg); } public void ComputeSignature(KeyedHashAlgorithm macAlg) { if (macAlg == null) throw new ArgumentNullException("macAlg"); HMAC hash = macAlg as HMAC; if(hash == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureMethodKeyMismatch")); int signatureLength; if (m_signature.SignedInfo.SignatureLength == null) signatureLength = hash.HashSize; else signatureLength = Convert.ToInt32(m_signature.SignedInfo.SignatureLength, null); // signatureLength should be less than hash size if (signatureLength < 0 || signatureLength > hash.HashSize) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength")); if (signatureLength % 8 != 0) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength2")); BuildDigestedReferences(); switch (hash.HashName) { case "SHA1": SignedInfo.SignatureMethod = SignedXml.XmlDsigHMACSHA1Url; break; case "SHA256": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA256Url; break; case "SHA384": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA384Url; break; case "SHA512": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA512Url; break; case "MD5": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACMD5Url; break; case "RIPEMD160": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACRIPEMD160Url; break; default: throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureMethodKeyMismatch")); } byte[] hashValue = GetC14NDigest(hash); m_signature.SignatureValue = new byte[signatureLength / 8]; Buffer.BlockCopy(hashValue, 0, m_signature.SignatureValue, 0, signatureLength / 8); } // // virtual methods // protected virtual AsymmetricAlgorithm GetPublicKey() { if (KeyInfo == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_KeyInfoRequired")); if (m_x509Enum != null) { AsymmetricAlgorithm key = GetNextCertificatePublicKey(); if (key != null) return key; } if (m_keyInfoEnum == null) m_keyInfoEnum = KeyInfo.GetEnumerator(); // In our implementation, we move to the next KeyInfo clause which is an RSAKeyValue, DSAKeyValue or KeyInfoX509Data while (m_keyInfoEnum.MoveNext()) { RSAKeyValue rsaKeyValue = m_keyInfoEnum.Current as RSAKeyValue; if (rsaKeyValue != null) return rsaKeyValue.Key; DSAKeyValue dsaKeyValue = m_keyInfoEnum.Current as DSAKeyValue; if (dsaKeyValue != null) return dsaKeyValue.Key; KeyInfoX509Data x509Data = m_keyInfoEnum.Current as KeyInfoX509Data; if (x509Data != null) { m_x509Collection = Utils.BuildBagOfCerts (x509Data, CertUsageType.Verification); if (m_x509Collection.Count > 0) { m_x509Enum = m_x509Collection.GetEnumerator(); AsymmetricAlgorithm key = GetNextCertificatePublicKey(); if (key != null) return key; } } } return null; } private X509Certificate2Collection BuildBagOfCerts () { X509Certificate2Collection collection = new X509Certificate2Collection(); if (this.KeyInfo != null) { foreach (KeyInfoClause clause in this.KeyInfo) { KeyInfoX509Data x509Data = clause as KeyInfoX509Data; if (x509Data != null) collection.AddRange(Utils.BuildBagOfCerts(x509Data, CertUsageType.Verification)); } } return collection; } private AsymmetricAlgorithm GetNextCertificatePublicKey () { while (m_x509Enum.MoveNext()) { X509Certificate2 certificate = (X509Certificate2) m_x509Enum.Current; if (certificate != null) return certificate.PublicKey.Key; } return null; } public virtual XmlElement GetIdElement (XmlDocument document, string idValue) { if (document == null) return null; // Get the element with idValue XmlElement elem = document.GetElementById(idValue); if (elem != null) return elem; elem = document.SelectSingleNode("//*[@Id=\"" + idValue + "\"]") as XmlElement; if (elem != null) return elem; elem = document.SelectSingleNode("//*[@id=\"" + idValue + "\"]") as XmlElement; if (elem != null) return elem; elem = document.SelectSingleNode("//*[@ID=\"" + idValue + "\"]") as XmlElement; return elem; } // // private methods // private bool bCacheValid = false; private byte[] _digestedSignedInfo = null; private byte[] GetC14NDigest (HashAlgorithm hash) { if (!bCacheValid || !this.SignedInfo.CacheValid) { string baseUri = (m_containingDocument == null ? null : m_containingDocument.BaseURI); XmlResolver resolver = (m_bResolverSet ? m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri)); XmlDocument doc = Utils.PreProcessElementInput(SignedInfo.GetXml(), resolver, baseUri); // Add non default namespaces in scope CanonicalXmlNodeList namespaces = (m_context == null ? null : Utils.GetPropagatedAttributes(m_context)); Utils.AddNamespaces(doc.DocumentElement, namespaces); Transform c14nMethodTransform = SignedInfo.CanonicalizationMethodObject; c14nMethodTransform.Resolver = resolver; c14nMethodTransform.BaseURI = baseUri; c14nMethodTransform.LoadInput(doc); _digestedSignedInfo = c14nMethodTransform.GetDigestedOutput(hash); bCacheValid = true; } return _digestedSignedInfo; } private int GetReferenceLevel (int index, ArrayList references) { if (m_refProcessed[index]) return m_refLevelCache[index]; m_refProcessed[index] = true; Reference reference = (Reference) references[index]; if (reference.Uri == null || reference.Uri.Length == 0 || (reference.Uri.Length > 0 && reference.Uri[0] != '#')) { m_refLevelCache[index] = 0; return 0; } if (reference.Uri.Length > 0 && reference.Uri[0] == '#') { String idref = Utils.ExtractIdFromLocalUri(reference.Uri); if (idref == "xpointer(/)") { m_refLevelCache[index] = 0; return 0; } // If this is pointing to another reference for (int j=0; j < references.Count; ++j) { if (((Reference)references[j]).Id == idref) { m_refLevelCache[index] = GetReferenceLevel(j, references) + 1; return (m_refLevelCache[index]); } } // Then the reference points to an object tag m_refLevelCache[index] = 0; return 0; } // Malformed reference throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidReference")); } private class ReferenceLevelSortOrder : IComparer { private ArrayList m_references = null; public ReferenceLevelSortOrder() {} public ArrayList References { get { return m_references; } set { m_references = value; } } public int Compare(Object a, Object b) { Reference referenceA = a as Reference; Reference referenceB = b as Reference; // Get the indexes int iIndexA = 0; int iIndexB = 0; int i = 0; foreach (Reference reference in References) { if (reference == referenceA) iIndexA = i; if (reference == referenceB) iIndexB = i; i++; } int iLevelA = referenceA.SignedXml.GetReferenceLevel(iIndexA, References); int iLevelB = referenceB.SignedXml.GetReferenceLevel(iIndexB, References); return iLevelA.CompareTo(iLevelB); } } private void BuildDigestedReferences() { // Default the DigestMethod and Canonicalization ArrayList references = SignedInfo.References; // Reset the cache m_refProcessed = new bool[references.Count]; m_refLevelCache = new int[references.Count]; ReferenceLevelSortOrder sortOrder = new ReferenceLevelSortOrder(); sortOrder.References = references; // Don't alter the order of the references array list ArrayList sortedReferences = new ArrayList(); foreach (Reference reference in references) { sortedReferences.Add(reference); } sortedReferences.Sort(sortOrder); CanonicalXmlNodeList nodeList = new CanonicalXmlNodeList(); foreach (DataObject obj in m_signature.ObjectList) { nodeList.Add(obj.GetXml()); } foreach (Reference reference in sortedReferences) { // If no DigestMethod has yet been set, default it to sha1 if (reference.DigestMethod == null) reference.DigestMethod = XmlDsigSHA1Url; reference.UpdateHashValue(m_containingDocument, nodeList); // If this reference has an Id attribute, add it if (reference.Id != null) nodeList.Add(reference.GetXml()); } } private bool CheckDigestedReferences () { ArrayList references = m_signature.SignedInfo.References; for (int i = 0; i < references.Count; ++i) { Reference digestedReference = (Reference) references[i]; byte[] calculatedHash = digestedReference.CalculateHashValue(m_containingDocument, m_signature.ReferencedItems); // Compare both hashes if (calculatedHash.Length != digestedReference.DigestValue.Length) return false; byte[] rgb1 = calculatedHash; byte[] rgb2 = digestedReference.DigestValue; for (int j = 0; j < rgb1.Length; ++j) { if (rgb1[j] != rgb2[j]) return false; } } return true; } private bool CheckSignedInfo (AsymmetricAlgorithm key) { if (key == null) throw new ArgumentNullException("key"); SignatureDescription signatureDescription = CryptoConfig.CreateFromName(SignatureMethod) as SignatureDescription; if (signatureDescription == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureDescriptionNotCreated")); // Let's see if the key corresponds with the SignatureMethod Type ta = Type.GetType(signatureDescription.KeyAlgorithm); Type tb = key.GetType(); if ((ta != tb) && !ta.IsSubclassOf(tb) && !tb.IsSubclassOf(ta)) // Signature method key mismatch return false; HashAlgorithm hashAlgorithm = signatureDescription.CreateDigest(); if (hashAlgorithm == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_CreateHashAlgorithmFailed")); byte[] hashval = GetC14NDigest(hashAlgorithm); AsymmetricSignatureDeformatter asymmetricSignatureDeformatter = signatureDescription.CreateDeformatter(key); return asymmetricSignatureDeformatter.VerifySignature(hashval, m_signature.SignatureValue); } private bool CheckSignedInfo (KeyedHashAlgorithm macAlg) { if (macAlg == null) throw new ArgumentNullException("macAlg"); int signatureLength; if (m_signature.SignedInfo.SignatureLength == null) signatureLength = macAlg.HashSize; else signatureLength = Convert.ToInt32(m_signature.SignedInfo.SignatureLength, null); // signatureLength should be less than hash size if (signatureLength < 0 || signatureLength > macAlg.HashSize) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength")); if (signatureLength % 8 != 0) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength2")); if (m_signature.SignatureValue == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureValueRequired")); if (m_signature.SignatureValue.Length != signatureLength / 8) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength")); // Calculate the hash byte[] hashValue = GetC14NDigest(macAlg); for (int i=0; i protected Signature m_signature; /// protected string m_strSigningKeyName; private AsymmetricAlgorithm m_signingKey; private XmlDocument m_containingDocument = null; private IEnumerator m_keyInfoEnum = null; private X509Certificate2Collection m_x509Collection = null; private IEnumerator m_x509Enum = null; private bool[] m_refProcessed = null; private int[] m_refLevelCache = null; internal XmlResolver m_xmlResolver = null; internal XmlElement m_context = null; private bool m_bResolverSet = false; // additional HMAC Url identifiers private const string XmlDsigMoreHMACMD5Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-md5"; private const string XmlDsigMoreHMACSHA256Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"; private const string XmlDsigMoreHMACSHA384Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384"; private const string XmlDsigMoreHMACSHA512Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512"; private const string XmlDsigMoreHMACRIPEMD160Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160"; // defines the XML encryption processing rules private EncryptedXml m_exml = null; // // public constant Url identifiers most frequently used within the XML Signature classes // public const string XmlDsigNamespaceUrl = "http://www.w3.org/2000/09/xmldsig#"; public const string XmlDsigMinimalCanonicalizationUrl = "http://www.w3.org/2000/09/xmldsig#minimal"; public const string XmlDsigCanonicalizationUrl = XmlDsigC14NTransformUrl; public const string XmlDsigCanonicalizationWithCommentsUrl = XmlDsigC14NWithCommentsTransformUrl; public const string XmlDsigSHA1Url = "http://www.w3.org/2000/09/xmldsig#sha1"; public const string XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; public const string XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; public const string XmlDsigHMACSHA1Url = "http://www.w3.org/2000/09/xmldsig#hmac-sha1"; public const string XmlDsigC14NTransformUrl = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; public const string XmlDsigC14NWithCommentsTransformUrl = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"; public const string XmlDsigExcC14NTransformUrl = "http://www.w3.org/2001/10/xml-exc-c14n#"; public const string XmlDsigExcC14NWithCommentsTransformUrl = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"; public const string XmlDsigBase64TransformUrl = "http://www.w3.org/2000/09/xmldsig#base64"; public const string XmlDsigXPathTransformUrl = "http://www.w3.org/TR/1999/REC-xpath-19991116"; public const string XmlDsigXsltTransformUrl = "http://www.w3.org/TR/1999/REC-xslt-19991116"; public const string XmlDsigEnvelopedSignatureTransformUrl = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"; public const string XmlDecryptionTransformUrl = "http://www.w3.org/2002/07/decrypt#XML"; public const string XmlLicenseTransformUrl = "urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform"; // // public constructors // public SignedXml() { Initialize(null); } public SignedXml(XmlDocument document) { if (document == null) throw new ArgumentNullException("document"); Initialize(document.DocumentElement); } public SignedXml(XmlElement elem) { if (elem == null) throw new ArgumentNullException("elem"); Initialize(elem); } private void Initialize (XmlElement element) { m_containingDocument = (element == null ? null : element.OwnerDocument); m_context = element; m_signature = new Signature(); m_signature.SignedXml = this; m_signature.SignedInfo = new SignedInfo(); m_signingKey = null; } // // public properties // /// public string SigningKeyName { get { return m_strSigningKeyName; } set { m_strSigningKeyName = value; } } [ComVisible(false)] public XmlResolver Resolver { // This property only has a setter. The rationale for this is that we don't have a good value // to return when it has not been explicitely set, as we are using XmlSecureResolver by default set { m_xmlResolver = value; m_bResolverSet = true; } } internal bool ResolverSet { get { return m_bResolverSet; } } public AsymmetricAlgorithm SigningKey { get { return m_signingKey; } set { m_signingKey = value; } } [ComVisible(false)] public EncryptedXml EncryptedXml { get { if (m_exml == null) m_exml = new EncryptedXml(m_containingDocument); // default processing rules return m_exml; } set { m_exml = value; } } public Signature Signature { get { return m_signature; } } public SignedInfo SignedInfo { get { return m_signature.SignedInfo; } } public string SignatureMethod { get { return m_signature.SignedInfo.SignatureMethod; } } public string SignatureLength { get { return m_signature.SignedInfo.SignatureLength; } } public byte[] SignatureValue { get { return m_signature.SignatureValue; } } public KeyInfo KeyInfo { get { return m_signature.KeyInfo; } set { m_signature.KeyInfo = value; } } public XmlElement GetXml() { // If we have a document context, then return a signature element in this context if (m_containingDocument != null) return m_signature.GetXml(m_containingDocument); else return m_signature.GetXml(); } public void LoadXml(XmlElement value) { if (value == null) throw new ArgumentNullException("value"); m_signature.LoadXml(value); m_context = value; bCacheValid = false; } // // public methods // public void AddReference(Reference reference) { m_signature.SignedInfo.AddReference(reference); } public void AddObject(DataObject dataObject) { m_signature.AddObject(dataObject); } public bool CheckSignature() { bool bRet = false; AsymmetricAlgorithm key; do { key = GetPublicKey(); if (key != null) bRet = CheckSignature(key); } while (key != null && bRet == false); return bRet; } public bool CheckSignatureReturningKey(out AsymmetricAlgorithm signingKey) { bool bRet = false; AsymmetricAlgorithm key = null; do { key = GetPublicKey(); if (key != null) bRet = CheckSignature(key); } while (key != null && bRet == false); signingKey = key; return bRet; } public bool CheckSignature(AsymmetricAlgorithm key) { if (!CheckSignedInfo(key)) return false; // Now is the time to go through all the references and see if their DigestValues are good return CheckDigestedReferences(); } public bool CheckSignature(KeyedHashAlgorithm macAlg) { if (!CheckSignedInfo(macAlg)) return false; return CheckDigestedReferences(); } [ComVisible(false)] public bool CheckSignature(X509Certificate2 certificate, bool verifySignatureOnly) { if (!CheckSignedInfo(certificate.PublicKey.Key)) return false; // Now is the time to go through all the references and see if their DigestValues are good if (!CheckDigestedReferences()) return false; if (verifySignatureOnly) return true; // Check key usages to make sure it is good for signing. foreach (X509Extension extension in certificate.Extensions) { if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) { X509KeyUsageExtension keyUsage = new X509KeyUsageExtension(); keyUsage.CopyFrom(extension); if ((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == 0 && (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0) { return false; } break; } } // Do the chain verification to make sure the certificate is valid. X509Chain chain = new X509Chain(); chain.ChainPolicy.ExtraStore.AddRange(BuildBagOfCerts()); return chain.Build(certificate); } public void ComputeSignature() { BuildDigestedReferences(); // Load the key AsymmetricAlgorithm key = SigningKey; if (key == null) throw new CryptographicException(SecurityResources.GetResourceString("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 = XmlDsigRSASHA1Url; } else { throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_CreatedKeyFailed")); } } // See if there is a signature description class defined in the Config file SignatureDescription signatureDescription = CryptoConfig.CreateFromName(SignedInfo.SignatureMethod) as SignatureDescription; if (signatureDescription == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureDescriptionNotCreated")); HashAlgorithm hashAlg = signatureDescription.CreateDigest(); if (hashAlg == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_CreateHashAlgorithmFailed")); byte[] hashvalue = GetC14NDigest(hashAlg); AsymmetricSignatureFormatter asymmetricSignatureFormatter = signatureDescription.CreateFormatter(key); m_signature.SignatureValue = asymmetricSignatureFormatter.CreateSignature(hashAlg); } public void ComputeSignature(KeyedHashAlgorithm macAlg) { if (macAlg == null) throw new ArgumentNullException("macAlg"); HMAC hash = macAlg as HMAC; if(hash == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureMethodKeyMismatch")); int signatureLength; if (m_signature.SignedInfo.SignatureLength == null) signatureLength = hash.HashSize; else signatureLength = Convert.ToInt32(m_signature.SignedInfo.SignatureLength, null); // signatureLength should be less than hash size if (signatureLength < 0 || signatureLength > hash.HashSize) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength")); if (signatureLength % 8 != 0) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength2")); BuildDigestedReferences(); switch (hash.HashName) { case "SHA1": SignedInfo.SignatureMethod = SignedXml.XmlDsigHMACSHA1Url; break; case "SHA256": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA256Url; break; case "SHA384": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA384Url; break; case "SHA512": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA512Url; break; case "MD5": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACMD5Url; break; case "RIPEMD160": SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACRIPEMD160Url; break; default: throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureMethodKeyMismatch")); } byte[] hashValue = GetC14NDigest(hash); m_signature.SignatureValue = new byte[signatureLength / 8]; Buffer.BlockCopy(hashValue, 0, m_signature.SignatureValue, 0, signatureLength / 8); } // // virtual methods // protected virtual AsymmetricAlgorithm GetPublicKey() { if (KeyInfo == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_KeyInfoRequired")); if (m_x509Enum != null) { AsymmetricAlgorithm key = GetNextCertificatePublicKey(); if (key != null) return key; } if (m_keyInfoEnum == null) m_keyInfoEnum = KeyInfo.GetEnumerator(); // In our implementation, we move to the next KeyInfo clause which is an RSAKeyValue, DSAKeyValue or KeyInfoX509Data while (m_keyInfoEnum.MoveNext()) { RSAKeyValue rsaKeyValue = m_keyInfoEnum.Current as RSAKeyValue; if (rsaKeyValue != null) return rsaKeyValue.Key; DSAKeyValue dsaKeyValue = m_keyInfoEnum.Current as DSAKeyValue; if (dsaKeyValue != null) return dsaKeyValue.Key; KeyInfoX509Data x509Data = m_keyInfoEnum.Current as KeyInfoX509Data; if (x509Data != null) { m_x509Collection = Utils.BuildBagOfCerts (x509Data, CertUsageType.Verification); if (m_x509Collection.Count > 0) { m_x509Enum = m_x509Collection.GetEnumerator(); AsymmetricAlgorithm key = GetNextCertificatePublicKey(); if (key != null) return key; } } } return null; } private X509Certificate2Collection BuildBagOfCerts () { X509Certificate2Collection collection = new X509Certificate2Collection(); if (this.KeyInfo != null) { foreach (KeyInfoClause clause in this.KeyInfo) { KeyInfoX509Data x509Data = clause as KeyInfoX509Data; if (x509Data != null) collection.AddRange(Utils.BuildBagOfCerts(x509Data, CertUsageType.Verification)); } } return collection; } private AsymmetricAlgorithm GetNextCertificatePublicKey () { while (m_x509Enum.MoveNext()) { X509Certificate2 certificate = (X509Certificate2) m_x509Enum.Current; if (certificate != null) return certificate.PublicKey.Key; } return null; } public virtual XmlElement GetIdElement (XmlDocument document, string idValue) { if (document == null) return null; // Get the element with idValue XmlElement elem = document.GetElementById(idValue); if (elem != null) return elem; elem = document.SelectSingleNode("//*[@Id=\"" + idValue + "\"]") as XmlElement; if (elem != null) return elem; elem = document.SelectSingleNode("//*[@id=\"" + idValue + "\"]") as XmlElement; if (elem != null) return elem; elem = document.SelectSingleNode("//*[@ID=\"" + idValue + "\"]") as XmlElement; return elem; } // // private methods // private bool bCacheValid = false; private byte[] _digestedSignedInfo = null; private byte[] GetC14NDigest (HashAlgorithm hash) { if (!bCacheValid || !this.SignedInfo.CacheValid) { string baseUri = (m_containingDocument == null ? null : m_containingDocument.BaseURI); XmlResolver resolver = (m_bResolverSet ? m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri)); XmlDocument doc = Utils.PreProcessElementInput(SignedInfo.GetXml(), resolver, baseUri); // Add non default namespaces in scope CanonicalXmlNodeList namespaces = (m_context == null ? null : Utils.GetPropagatedAttributes(m_context)); Utils.AddNamespaces(doc.DocumentElement, namespaces); Transform c14nMethodTransform = SignedInfo.CanonicalizationMethodObject; c14nMethodTransform.Resolver = resolver; c14nMethodTransform.BaseURI = baseUri; c14nMethodTransform.LoadInput(doc); _digestedSignedInfo = c14nMethodTransform.GetDigestedOutput(hash); bCacheValid = true; } return _digestedSignedInfo; } private int GetReferenceLevel (int index, ArrayList references) { if (m_refProcessed[index]) return m_refLevelCache[index]; m_refProcessed[index] = true; Reference reference = (Reference) references[index]; if (reference.Uri == null || reference.Uri.Length == 0 || (reference.Uri.Length > 0 && reference.Uri[0] != '#')) { m_refLevelCache[index] = 0; return 0; } if (reference.Uri.Length > 0 && reference.Uri[0] == '#') { String idref = Utils.ExtractIdFromLocalUri(reference.Uri); if (idref == "xpointer(/)") { m_refLevelCache[index] = 0; return 0; } // If this is pointing to another reference for (int j=0; j < references.Count; ++j) { if (((Reference)references[j]).Id == idref) { m_refLevelCache[index] = GetReferenceLevel(j, references) + 1; return (m_refLevelCache[index]); } } // Then the reference points to an object tag m_refLevelCache[index] = 0; return 0; } // Malformed reference throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidReference")); } private class ReferenceLevelSortOrder : IComparer { private ArrayList m_references = null; public ReferenceLevelSortOrder() {} public ArrayList References { get { return m_references; } set { m_references = value; } } public int Compare(Object a, Object b) { Reference referenceA = a as Reference; Reference referenceB = b as Reference; // Get the indexes int iIndexA = 0; int iIndexB = 0; int i = 0; foreach (Reference reference in References) { if (reference == referenceA) iIndexA = i; if (reference == referenceB) iIndexB = i; i++; } int iLevelA = referenceA.SignedXml.GetReferenceLevel(iIndexA, References); int iLevelB = referenceB.SignedXml.GetReferenceLevel(iIndexB, References); return iLevelA.CompareTo(iLevelB); } } private void BuildDigestedReferences() { // Default the DigestMethod and Canonicalization ArrayList references = SignedInfo.References; // Reset the cache m_refProcessed = new bool[references.Count]; m_refLevelCache = new int[references.Count]; ReferenceLevelSortOrder sortOrder = new ReferenceLevelSortOrder(); sortOrder.References = references; // Don't alter the order of the references array list ArrayList sortedReferences = new ArrayList(); foreach (Reference reference in references) { sortedReferences.Add(reference); } sortedReferences.Sort(sortOrder); CanonicalXmlNodeList nodeList = new CanonicalXmlNodeList(); foreach (DataObject obj in m_signature.ObjectList) { nodeList.Add(obj.GetXml()); } foreach (Reference reference in sortedReferences) { // If no DigestMethod has yet been set, default it to sha1 if (reference.DigestMethod == null) reference.DigestMethod = XmlDsigSHA1Url; reference.UpdateHashValue(m_containingDocument, nodeList); // If this reference has an Id attribute, add it if (reference.Id != null) nodeList.Add(reference.GetXml()); } } private bool CheckDigestedReferences () { ArrayList references = m_signature.SignedInfo.References; for (int i = 0; i < references.Count; ++i) { Reference digestedReference = (Reference) references[i]; byte[] calculatedHash = digestedReference.CalculateHashValue(m_containingDocument, m_signature.ReferencedItems); // Compare both hashes if (calculatedHash.Length != digestedReference.DigestValue.Length) return false; byte[] rgb1 = calculatedHash; byte[] rgb2 = digestedReference.DigestValue; for (int j = 0; j < rgb1.Length; ++j) { if (rgb1[j] != rgb2[j]) return false; } } return true; } private bool CheckSignedInfo (AsymmetricAlgorithm key) { if (key == null) throw new ArgumentNullException("key"); SignatureDescription signatureDescription = CryptoConfig.CreateFromName(SignatureMethod) as SignatureDescription; if (signatureDescription == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureDescriptionNotCreated")); // Let's see if the key corresponds with the SignatureMethod Type ta = Type.GetType(signatureDescription.KeyAlgorithm); Type tb = key.GetType(); if ((ta != tb) && !ta.IsSubclassOf(tb) && !tb.IsSubclassOf(ta)) // Signature method key mismatch return false; HashAlgorithm hashAlgorithm = signatureDescription.CreateDigest(); if (hashAlgorithm == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_CreateHashAlgorithmFailed")); byte[] hashval = GetC14NDigest(hashAlgorithm); AsymmetricSignatureDeformatter asymmetricSignatureDeformatter = signatureDescription.CreateDeformatter(key); return asymmetricSignatureDeformatter.VerifySignature(hashval, m_signature.SignatureValue); } private bool CheckSignedInfo (KeyedHashAlgorithm macAlg) { if (macAlg == null) throw new ArgumentNullException("macAlg"); int signatureLength; if (m_signature.SignedInfo.SignatureLength == null) signatureLength = macAlg.HashSize; else signatureLength = Convert.ToInt32(m_signature.SignedInfo.SignatureLength, null); // signatureLength should be less than hash size if (signatureLength < 0 || signatureLength > macAlg.HashSize) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength")); if (signatureLength % 8 != 0) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength2")); if (m_signature.SignatureValue == null) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_SignatureValueRequired")); if (m_signature.SignatureValue.Length != signatureLength / 8) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidSignatureLength")); // Calculate the hash byte[] hashValue = GetC14NDigest(macAlg); for (int i=0; i
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Page.cs
- ReachDocumentReferenceSerializer.cs
- DataListItem.cs
- ExpressionNode.cs
- DataGridViewLinkCell.cs
- BitmapEffectvisualstate.cs
- FileDialogCustomPlaces.cs
- SubMenuStyle.cs
- GridView.cs
- RectangleHotSpot.cs
- DisplayMemberTemplateSelector.cs
- XmlDataProvider.cs
- BaseTemplateCodeDomTreeGenerator.cs
- ConsumerConnectionPointCollection.cs
- MatrixUtil.cs
- SmiEventSink_Default.cs
- DateTimeUtil.cs
- GridViewRow.cs
- VisualCollection.cs
- FixedStringLookup.cs
- BaseTemplateParser.cs
- ScalarOps.cs
- XmlSchemaProviderAttribute.cs
- Constant.cs
- BaseUriHelper.cs
- EntityException.cs
- DataFormats.cs
- ToolStripItem.cs
- _DomainName.cs
- ToolbarAUtomationPeer.cs
- DockPattern.cs
- DerivedKeyCachingSecurityTokenSerializer.cs
- DataPagerCommandEventArgs.cs
- EncoderReplacementFallback.cs
- HwndSourceKeyboardInputSite.cs
- DataGridColumn.cs
- SystemFonts.cs
- _LoggingObject.cs
- FontFamilyIdentifier.cs
- ServicePointManagerElement.cs
- EDesignUtil.cs
- PropertyEmitter.cs
- CustomAttributeSerializer.cs
- MachineSettingsSection.cs
- SessionIDManager.cs
- MethodToken.cs
- SerializationInfo.cs
- VScrollBar.cs
- XamlClipboardData.cs
- MatchAttribute.cs
- BeginStoryboard.cs
- DbConnectionStringBuilder.cs
- FormViewPagerRow.cs
- LoginName.cs
- Binding.cs
- ReferenceTypeElement.cs
- LockCookie.cs
- InputLanguageProfileNotifySink.cs
- Journal.cs
- BindingContext.cs
- Zone.cs
- TrackingLocationCollection.cs
- SecurityContextSecurityTokenResolver.cs
- XmlReturnWriter.cs
- BroadcastEventHelper.cs
- Accessors.cs
- ListBox.cs
- HttpHandlerAction.cs
- CollectionViewSource.cs
- ExceptionHandlers.cs
- MetadataUtil.cs
- MetadataItemEmitter.cs
- XPathDocumentIterator.cs
- Triplet.cs
- WebServiceTypeData.cs
- OleDbPropertySetGuid.cs
- WebPartAddingEventArgs.cs
- BrowserCapabilitiesFactoryBase.cs
- EventLogWatcher.cs
- DnsPermission.cs
- XamlFilter.cs
- Codec.cs
- TdsParserStateObject.cs
- ListItemCollection.cs
- ObjectAnimationUsingKeyFrames.cs
- QueryOutputWriter.cs
- WebColorConverter.cs
- OperationGenerator.cs
- isolationinterop.cs
- translator.cs
- PersistenceProviderElement.cs
- SecureUICommand.cs
- Size3D.cs
- CompiledELinqQueryState.cs
- Listen.cs
- EntityCollection.cs
- CodeDirectionExpression.cs
- InvokeWebService.cs
- DictionaryBase.cs
- DeferrableContentConverter.cs