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
- ObjectConverter.cs
- XmlSchemaImporter.cs
- PseudoWebRequest.cs
- RegexInterpreter.cs
- DynamicResourceExtensionConverter.cs
- PriorityQueue.cs
- VirtualDirectoryMapping.cs
- TextBox.cs
- Attributes.cs
- WMIInterop.cs
- BitmapEffectDrawingContextWalker.cs
- ReadOnlyCollectionBase.cs
- XAMLParseException.cs
- CheckoutException.cs
- ToolboxBitmapAttribute.cs
- DetailsViewRowCollection.cs
- Triplet.cs
- HwndSubclass.cs
- DummyDataSource.cs
- QuestionEventArgs.cs
- ManagementNamedValueCollection.cs
- CodeMemberEvent.cs
- ColorAnimationBase.cs
- WebControlsSection.cs
- TdsParserSessionPool.cs
- HtmlMeta.cs
- IsolatedStorageFilePermission.cs
- UnaryNode.cs
- XmlDataCollection.cs
- UIElementAutomationPeer.cs
- ForeignConstraint.cs
- XmlEnumAttribute.cs
- Calendar.cs
- DeviceContext.cs
- State.cs
- SoapTransportImporter.cs
- XmlUnspecifiedAttribute.cs
- InternalsVisibleToAttribute.cs
- AudioStateChangedEventArgs.cs
- WebScriptMetadataFormatter.cs
- TypeLoadException.cs
- AccessDataSourceWizardForm.cs
- ButtonPopupAdapter.cs
- FieldTemplateFactory.cs
- CalculatedColumn.cs
- ObjectViewQueryResultData.cs
- SqlNotificationEventArgs.cs
- DiscreteKeyFrames.cs
- BaseAutoFormat.cs
- SHA1CryptoServiceProvider.cs
- Button.cs
- PictureBox.cs
- Label.cs
- StringCollection.cs
- GridPatternIdentifiers.cs
- SqlDataSourceFilteringEventArgs.cs
- TextFormatter.cs
- ProviderConnectionPointCollection.cs
- FormViewInsertedEventArgs.cs
- QilBinary.cs
- CheckedPointers.cs
- JoinElimination.cs
- ClientSettingsProvider.cs
- SqlNodeAnnotation.cs
- OptimizedTemplateContentHelper.cs
- ObjectContext.cs
- CodeMethodReturnStatement.cs
- XmlProcessingInstruction.cs
- controlskin.cs
- DesignerSerializerAttribute.cs
- LinqDataSourceSelectEventArgs.cs
- MsmqAppDomainProtocolHandler.cs
- GradientStop.cs
- BoundField.cs
- EncryptedPackageFilter.cs
- ApplicationGesture.cs
- XmlAttributeAttribute.cs
- CompilerGlobalScopeAttribute.cs
- MinMaxParagraphWidth.cs
- CompilerLocalReference.cs
- HtmlTextViewAdapter.cs
- _UriSyntax.cs
- DataGridViewTopRowAccessibleObject.cs
- QualifiedCellIdBoolean.cs
- RightsManagementEncryptionTransform.cs
- HTTPNotFoundHandler.cs
- WebPartEditVerb.cs
- LocatorGroup.cs
- WebEvents.cs
- CommandField.cs
- KoreanLunisolarCalendar.cs
- Utilities.cs
- ChineseLunisolarCalendar.cs
- SynchronousReceiveElement.cs
- DataKeyArray.cs
- ToolbarAUtomationPeer.cs
- PackageDigitalSignature.cs
- FormViewPagerRow.cs
- AttachedPropertyMethodSelector.cs
- SymLanguageType.cs