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
- ControlSerializer.cs
- FlowLayoutSettings.cs
- PreProcessInputEventArgs.cs
- CompilerGeneratedAttribute.cs
- OutputCacheProfileCollection.cs
- DocumentOrderComparer.cs
- SafeNativeMethods.cs
- TextTreeFixupNode.cs
- precedingquery.cs
- HtmlControlDesigner.cs
- ColumnHeader.cs
- PagesChangedEventArgs.cs
- UpdateEventArgs.cs
- SQLGuid.cs
- FileCodeGroup.cs
- FindResponse.cs
- EntityCommand.cs
- ExtensibleClassFactory.cs
- ToolStripPanelRenderEventArgs.cs
- DataColumnPropertyDescriptor.cs
- ListControlBuilder.cs
- ObjectSet.cs
- GridViewPageEventArgs.cs
- wmiprovider.cs
- OdbcConnectionFactory.cs
- CodeExpressionCollection.cs
- Operator.cs
- DispatcherHooks.cs
- CompilationSection.cs
- SoapFormatterSinks.cs
- ColumnMapTranslator.cs
- XmlAttributeCache.cs
- EmptyQuery.cs
- SqlNamer.cs
- EventSetter.cs
- HtmlToClrEventProxy.cs
- ClientBuildManagerCallback.cs
- DbgCompiler.cs
- ComponentEditorForm.cs
- SqlDataSourceFilteringEventArgs.cs
- VectorCollectionValueSerializer.cs
- Interlocked.cs
- SafeLocalMemHandle.cs
- ExtensionElement.cs
- ChangeToolStripParentVerb.cs
- BaseDataListActionList.cs
- SqlCaseSimplifier.cs
- x509store.cs
- SvcMapFileLoader.cs
- _NegoState.cs
- WindowsListViewSubItem.cs
- Repeater.cs
- InternalsVisibleToAttribute.cs
- XmlDocumentType.cs
- LocatorPart.cs
- WS2007HttpBinding.cs
- TypeValidationEventArgs.cs
- SettingsPropertyNotFoundException.cs
- QilGeneratorEnv.cs
- InvariantComparer.cs
- SyndicationCategory.cs
- ModulesEntry.cs
- RichTextBox.cs
- MimeBasePart.cs
- Events.cs
- GatewayDefinition.cs
- ByeMessageApril2005.cs
- AuthorizationRuleCollection.cs
- LineUtil.cs
- PingReply.cs
- GraphicsContext.cs
- QueueProcessor.cs
- StringBuilder.cs
- HttpModule.cs
- EventLogEntryCollection.cs
- XmlBufferReader.cs
- NamespaceDecl.cs
- IRCollection.cs
- PageRequestManager.cs
- StyleXamlTreeBuilder.cs
- DesignTimeHTMLTextWriter.cs
- PrePrepareMethodAttribute.cs
- CaseInsensitiveComparer.cs
- Drawing.cs
- TableItemPattern.cs
- EntityDataSource.cs
- StylusPointCollection.cs
- UrlMapping.cs
- GridItemCollection.cs
- CurrentChangingEventArgs.cs
- ComponentChangingEvent.cs
- _NegoState.cs
- Journaling.cs
- EdmToObjectNamespaceMap.cs
- HiddenField.cs
- IgnoreDeviceFilterElement.cs
- MetadataSource.cs
- ValidatingReaderNodeData.cs
- DiscoveryRequestHandler.cs
- ImageKeyConverter.cs