SignedXml.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / IdentityModel / System / IdentityModel / SignedXml.cs / 1 / SignedXml.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.IdentityModel 
{
    using System.Collections.Generic; 
    using System.Diagnostics; 
    using System.IO;
    using System.IdentityModel.Tokens; 
    using System.IdentityModel.Selectors;
    using System.Security.Cryptography;
    using System.Text;
    using System.Xml; 

    sealed class SignedXml : ISignatureValueSecurityElement 
    { 
        internal const string DefaultPrefix = XmlSignatureStrings.Prefix;
 
        SecurityTokenSerializer tokenSerializer;
        readonly Signature signature;
        TransformFactory transformFactory;
        DictionaryManager dictionaryManager; 

        public SignedXml(DictionaryManager dictionaryManager, SecurityTokenSerializer tokenSerializer) 
            : this(new StandardSignedInfo(dictionaryManager), dictionaryManager, tokenSerializer) 
        {
        } 

        internal SignedXml(SignedInfo signedInfo, DictionaryManager dictionaryManager, SecurityTokenSerializer tokenSerializer)
        {
            if (signedInfo == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("signedInfo")); 
            } 
            if (dictionaryManager == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryManager");
            }
            if (tokenSerializer == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenSerializer");
            } 
            this.transformFactory = StandardTransformFactory.Instance; 
            this.tokenSerializer = tokenSerializer;
            this.signature = new Signature(this, signedInfo); 
            this.dictionaryManager = dictionaryManager;
        }

        public bool HasId 
        {
            get { return true; } 
        } 

        public string Id 
        {
            get { return this.signature.Id; }
            set { this.signature.Id = value; }
        } 

        public SecurityTokenSerializer SecurityTokenSerializer 
        { 
            get { return this.tokenSerializer; }
        } 

        public Signature Signature
        {
            get { return this.signature; } 
        }
 
        public TransformFactory TransformFactory 
        {
            get { return this.transformFactory; } 
            set { this.transformFactory = value; }
        }

        void ComputeSignature(HashAlgorithm hash, AsymmetricSignatureFormatter formatter) 
        {
            this.Signature.SignedInfo.ComputeReferenceDigests(); 
            this.Signature.SignedInfo.ComputeHash(hash); 
            byte[] signature = formatter.CreateSignature(hash);
            this.Signature.SetSignatureValue(signature); 
        }

        void ComputeSignature(KeyedHashAlgorithm hash)
        { 
            this.Signature.SignedInfo.ComputeReferenceDigests();
            this.Signature.SignedInfo.ComputeHash(hash); 
            byte[] signature = hash.Hash; 
            this.Signature.SetSignatureValue(signature);
        } 

        public void ComputeSignature(SecurityKey signingKey)
        {
            string signatureMethod = this.Signature.SignedInfo.SignatureMethod; 
            SymmetricSecurityKey symmetricKey = signingKey as SymmetricSecurityKey;
            if (symmetricKey != null) 
            { 
                using (KeyedHashAlgorithm algorithm = symmetricKey.GetKeyedHashAlgorithm(signatureMethod))
                { 
                    if (algorithm == null)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR.GetString(SR.UnableToCreateKeyedHashAlgorithm, symmetricKey, signatureMethod))); 
                    }
                    ComputeSignature(algorithm); 
                } 
            }
            else 
            {
                AsymmetricSecurityKey asymmetricKey = signingKey as AsymmetricSecurityKey;
                if (asymmetricKey == null)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                        SR.GetString(SR.UnknownICryptoType, signingKey))); 
                } 
                using (HashAlgorithm hash = asymmetricKey.GetHashAlgorithmForSignature(signatureMethod))
                { 
                    if (hash == null)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR.GetString(SR.UnableToCreateHashAlgorithmFromAsymmetricCrypto, signatureMethod, asymmetricKey))); 
                    }
                    AsymmetricSignatureFormatter formatter = asymmetricKey.GetSignatureFormatter(signatureMethod); 
                    if (formatter == null) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( 
                            SR.GetString(SR.UnableToCreateSignatureFormatterFromAsymmetricCrypto, signatureMethod, asymmetricKey)));
                    }
                    ComputeSignature(hash, formatter);
                } 
            }
        } 
 
        public void CompleteSignatureVerification()
        { 
            this.Signature.SignedInfo.EnsureAllReferencesVerified();
        }

        public void EnsureDigestValidity(string id, object resolvedXmlSource) 
        {
            this.Signature.SignedInfo.EnsureDigestValidity(id, resolvedXmlSource); 
        } 

        public byte[] GetSignatureValue() 
        {
            return this.Signature.GetSignatureBytes();
        }
 
        public void ReadFrom(XmlReader reader)
        { 
            ReadFrom(XmlDictionaryReader.CreateDictionaryReader(reader)); 
        }
 
        public void ReadFrom(XmlDictionaryReader reader)
        {
            this.signature.ReadFrom(reader, this.dictionaryManager);
        } 

        void VerifySignature(KeyedHashAlgorithm hash) 
        { 
            this.Signature.SignedInfo.ComputeHash(hash);
            if (!CryptoHelper.IsEqual(hash.Hash, GetSignatureValue())) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.SignatureVerificationFailed)));
            }
        } 

        void VerifySignature(HashAlgorithm hash, AsymmetricSignatureDeformatter deformatter) 
        { 
            this.Signature.SignedInfo.ComputeHash(hash);
            if (!deformatter.VerifySignature(hash, GetSignatureValue())) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.SignatureVerificationFailed)));
            }
        } 

        public void StartSignatureVerification(SecurityKey verificationKey) 
        { 
            string signatureMethod = this.Signature.SignedInfo.SignatureMethod;
            SymmetricSecurityKey symmetricKey = verificationKey as SymmetricSecurityKey; 
            if (symmetricKey != null)
            {
                using (KeyedHashAlgorithm hash = symmetricKey.GetKeyedHashAlgorithm(signatureMethod))
                { 
                    if (hash == null)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException( 
                            SR.GetString(SR.UnableToCreateKeyedHashAlgorithmFromSymmetricCrypto, signatureMethod, symmetricKey)));
                    } 
                    VerifySignature(hash);
                }
            }
            else 
            {
                AsymmetricSecurityKey asymmetricKey = verificationKey as AsymmetricSecurityKey; 
                if (asymmetricKey == null) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnknownICryptoType, verificationKey))); 
                }
                using (HashAlgorithm hash = asymmetricKey.GetHashAlgorithmForSignature(signatureMethod))
                {
                     if (hash == null) 
                     {
                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException( 
                             SR.GetString(SR.UnableToCreateHashAlgorithmFromAsymmetricCrypto, signatureMethod, asymmetricKey))); 
                     }
                     AsymmetricSignatureDeformatter deformatter = asymmetricKey.GetSignatureDeformatter(signatureMethod); 
                     if (deformatter == null)
                     {
                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
                             SR.GetString(SR.UnableToCreateSignatureDeformatterFromAsymmetricCrypto, signatureMethod, asymmetricKey))); 
                     }
                     VerifySignature(hash, deformatter); 
                 } 
            }
        } 

        public void WriteTo(XmlDictionaryWriter writer)
        {
            this.WriteTo(writer, this.dictionaryManager); 
        }
 
        public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager) 
        {
            this.signature.WriteTo(writer, dictionaryManager); 
        }
    }

    sealed class Signature 
    {
        SignedXml signedXml; 
        string id; 
        SecurityKeyIdentifier keyIdentifier;
        string prefix = SignedXml.DefaultPrefix; 
        readonly SignatureValueElement signatureValueElement = new SignatureValueElement();
        readonly SignedInfo signedInfo;

        public Signature(SignedXml signedXml, SignedInfo signedInfo) 
        {
            this.signedXml = signedXml; 
            this.signedInfo = signedInfo; 
        }
 
        public string Id
        {
            get { return this.id; }
            set { this.id = value; } 
        }
 
        public SecurityKeyIdentifier KeyIdentifier 
        {
            get { return this.keyIdentifier; } 
            set { this.keyIdentifier = value; }
        }

        public SignedInfo SignedInfo 
        {
            get { return this.signedInfo; } 
        } 

        public ISignatureValueSecurityElement SignatureValue 
        {
            get { return this.signatureValueElement; }
        }
 
        public byte[] GetSignatureBytes()
        { 
            return this.signatureValueElement.Value; 
        }
 
        public void ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
        {
            reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.Signature, dictionaryManager.XmlSignatureDictionary.Namespace);
            this.prefix = reader.Prefix; 
            this.Id = reader.GetAttribute(dictionaryManager.UtilityDictionary.IdAttribute, null);
            reader.Read(); 
 
            this.signedInfo.ReadFrom(reader, signedXml.TransformFactory, dictionaryManager);
            this.signatureValueElement.ReadFrom(reader, dictionaryManager); 
            if (signedXml.SecurityTokenSerializer.CanReadKeyIdentifier(reader))
            {
                this.keyIdentifier = signedXml.SecurityTokenSerializer.ReadKeyIdentifier(reader);
            } 
            reader.ReadEndElement(); // Signature
        } 
 
        public void SetSignatureValue(byte[] signatureValue)
        { 
            this.signatureValueElement.Value = signatureValue;
        }

        public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager) 
        {
            writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.Signature, dictionaryManager.XmlSignatureDictionary.Namespace); 
            if (this.id != null) 
            {
                writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.id); 
            }
            this.signedInfo.WriteTo(writer, dictionaryManager);
            this.signatureValueElement.WriteTo(writer, dictionaryManager);
            if (this.keyIdentifier != null) 
            {
                this.signedXml.SecurityTokenSerializer.WriteKeyIdentifier(writer, this.keyIdentifier); 
            } 

            writer.WriteEndElement(); // Signature 
        }

        sealed class SignatureValueElement : ISignatureValueSecurityElement
        { 
            string id;
            string prefix = SignedXml.DefaultPrefix; 
            byte[] signatureValue; 
            string signatureText;
 
            public bool HasId
            {
                get { return true; }
            } 

            public string Id 
            { 
                get { return this.id; }
                set { this.id = value; } 
            }

            internal byte[] Value
            { 
                get { return this.signatureValue; }
                set 
                { 
                    this.signatureValue = value;
                    this.signatureText = null; 
                }
            }

            public void ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager) 
            {
                reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.SignatureValue, dictionaryManager.XmlSignatureDictionary.Namespace); 
                this.prefix = reader.Prefix; 
                this.Id = reader.GetAttribute(UtilityStrings.IdAttribute, null);
                reader.Read(); 

                this.signatureText = reader.ReadString();
                this.signatureValue = System.Convert.FromBase64String(signatureText.Trim());
 
                reader.ReadEndElement(); // SignatureValue
            } 
 
            public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
            { 
                writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.SignatureValue, dictionaryManager.XmlSignatureDictionary.Namespace);
                if (this.id != null)
                {
                    writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.id); 
                }
                if (this.signatureText != null) 
                { 
                    writer.WriteString(this.signatureText);
                } 
                else
                {
                    writer.WriteBase64(this.signatureValue, 0, this.signatureValue.Length);
                } 
                writer.WriteEndElement(); // SignatureValue
            } 
 
            byte[] ISignatureValueSecurityElement.GetSignatureValue()
            { 
                return this.Value;
            }
        }
    } 

    internal interface ISignatureReaderProvider 
    { 
        XmlDictionaryReader GetReader(object callbackContext);
    } 

    abstract class SignedInfo : ISecurityElement
    {
        readonly ExclusiveCanonicalizationTransform canonicalizationMethodElement = new ExclusiveCanonicalizationTransform(true); 
        string id;
        ElementWithAlgorithmAttribute signatureMethodElement; 
        SignatureResourcePool resourcePool; 
        DictionaryManager dictionaryManager;
        MemoryStream canonicalStream; 
        ISignatureReaderProvider readerProvider;
        object signatureReaderProviderCallbackContext;
        bool sendSide = true;
 
        protected SignedInfo(DictionaryManager dictionaryManager)
        { 
            if (dictionaryManager == null) 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryManager");
 
            this.signatureMethodElement = new ElementWithAlgorithmAttribute(dictionaryManager.XmlSignatureDictionary.SignatureMethod);
            this.dictionaryManager = dictionaryManager;
        }
 
        protected DictionaryManager DictionaryManager
        { 
            get { return this.dictionaryManager; } 
        }
 
        protected MemoryStream CanonicalStream
        {
            get { return this.canonicalStream; }
            set { this.canonicalStream = value; } 
        }
 
        protected bool SendSide 
        {
            get { return this.sendSide; } 
            set { this.sendSide = value; }
        }

        public ISignatureReaderProvider ReaderProvider 
        {
            get { return this.readerProvider; } 
            set { this.readerProvider = value; } 
        }
 
        public object SignatureReaderProviderCallbackContext
        {
            get { return this.signatureReaderProviderCallbackContext; }
            set { this.signatureReaderProviderCallbackContext = value; } 
        }
 
        public string CanonicalizationMethod 
        {
            get { return this.canonicalizationMethodElement.Algorithm; } 
            set
            {
                if (value != this.canonicalizationMethodElement.Algorithm)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedTransformAlgorithm)));
                } 
            } 
        }
 
        public XmlDictionaryString CanonicalizationMethodDictionaryString
        {
            set
            { 
                if (value != null && value.Value != this.canonicalizationMethodElement.Algorithm)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedTransformAlgorithm))); 
                }
            } 
        }

        public bool HasId
        { 
            get { return true; }
        } 
 
        public string Id
        { 
            get { return this.id; }
            set { this.id = value; }
        }
 
        public abstract int ReferenceCount
        { 
            get; 
        }
 
        public string SignatureMethod
        {
            get { return this.signatureMethodElement.Algorithm; }
            set { this.signatureMethodElement.Algorithm = value; } 
        }
 
        public XmlDictionaryString SignatureMethodDictionaryString 
        {
            get { return this.signatureMethodElement.AlgorithmDictionaryString; } 
            set { this.signatureMethodElement.AlgorithmDictionaryString = value; }
        }

        public SignatureResourcePool ResourcePool 
        {
            get 
            { 
                if (this.resourcePool == null)
                { 
                    this.resourcePool = new SignatureResourcePool();
                }
                return this.resourcePool;
            } 
            set
            { 
                this.resourcePool = value; 
            }
        } 

        public void ComputeHash(HashAlgorithm algorithm)
        {
            if (this.CanonicalizationMethod != SecurityAlgorithms.ExclusiveC14n) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.UnsupportedTransformAlgorithm))); 
            } 
            HashStream hashStream = this.ResourcePool.TakeHashStream(algorithm);
            ComputeHash(hashStream); 
            hashStream.FlushHash();
        }

        protected virtual void ComputeHash(HashStream hashStream) 
        {
            if (this.sendSide) 
            { 
                XmlDictionaryWriter utf8Writer = this.ResourcePool.TakeUtf8Writer();
                utf8Writer.StartCanonicalization(hashStream, false, null); 
                WriteTo(utf8Writer, this.dictionaryManager);
                utf8Writer.EndCanonicalization();
            }
            else if (this.canonicalStream != null) 
            {
                this.canonicalStream.WriteTo(hashStream); 
            } 
            else
            { 
                if (this.readerProvider == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.InclusiveNamespacePrefixRequiresSignatureReader)));

                XmlDictionaryReader signatureReader = this.readerProvider.GetReader(this.signatureReaderProviderCallbackContext); 

                DiagnosticUtility.DebugAssert(signatureReader != null, "Require a Signature reader to validate signature."); 
 
                if (!signatureReader.CanCanonicalize)
                { 
                    MemoryStream stream = new MemoryStream();
                    XmlDictionaryWriter bufferingWriter = XmlDictionaryWriter.CreateBinaryWriter(stream, this.DictionaryManager.ParentDictionary);
                    string[] inclusivePrefix = GetInclusivePrefixes();
                    if (inclusivePrefix != null) 
                    {
                        bufferingWriter.WriteStartElement("a"); 
                        for (int i = 0; i < inclusivePrefix.Length; ++i) 
                        {
                            string ns = GetNamespaceForInclusivePrefix(inclusivePrefix[i]); 
                            if (ns != null)
                            {
                                bufferingWriter.WriteXmlnsAttribute(inclusivePrefix[i], ns);
                            } 
                        }
                    } 
                    signatureReader.MoveToContent(); 
                    bufferingWriter.WriteNode(signatureReader, false);
                    if (inclusivePrefix != null) 
                        bufferingWriter.WriteEndElement();
                    bufferingWriter.Flush();
                    byte[] buffer = stream.ToArray();
                    int bufferLength = (int)stream.Length; 
                    bufferingWriter.Close();
 
                    signatureReader.Close(); 

                    // Create a reader around the buffering Stream. 
                    signatureReader = XmlDictionaryReader.CreateBinaryReader(buffer, 0, bufferLength, this.DictionaryManager.ParentDictionary, XmlDictionaryReaderQuotas.Max);
                    if (inclusivePrefix != null)
                        signatureReader.ReadStartElement("a");
                } 
                signatureReader.ReadStartElement(dictionaryManager.XmlSignatureDictionary.Signature, dictionaryManager.XmlSignatureDictionary.Namespace);
                signatureReader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.SignedInfo, dictionaryManager.XmlSignatureDictionary.Namespace); 
                signatureReader.StartCanonicalization(hashStream, false, GetInclusivePrefixes()); 
                signatureReader.Skip();
                signatureReader.EndCanonicalization(); 
                signatureReader.Close();
            }
        }
 
        public abstract void ComputeReferenceDigests();
 
        protected string[] GetInclusivePrefixes() 
        {
            return this.canonicalizationMethodElement.GetInclusivePrefixes(); 
        }

        protected virtual string GetNamespaceForInclusivePrefix(string prefix)
        { 
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
        } 
 
        public abstract void EnsureAllReferencesVerified();
 
        public void EnsureDigestValidity(string id, object resolvedXmlSource)
        {
            if (!EnsureDigestValidityIfIdMatches(id, resolvedXmlSource))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
                    SR.GetString(SR.RequiredTargetNotSigned, id))); 
            } 
        }
 
        public abstract bool EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource);

        public virtual bool HasUnverifiedReference(string id)
        { 
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
        } 
 
        protected void ReadCanonicalizationMethod(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
        { 
            this.canonicalizationMethodElement.ReadFrom(reader, dictionaryManager);
        }

        public abstract void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager); 

        protected void ReadSignatureMethod(XmlDictionaryReader reader, DictionaryManager dictionaryManager) 
        { 
            this.signatureMethodElement.ReadFrom(reader, dictionaryManager);
        } 

        protected void WriteCanonicalizationMethod(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
        {
            this.canonicalizationMethodElement.WriteTo(writer, dictionaryManager); 
        }
 
        protected void WriteSignatureMethod(XmlDictionaryWriter writer, DictionaryManager dictionaryManager) 
        {
            this.signatureMethodElement.WriteTo(writer, dictionaryManager); 
        }

        public abstract void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager);
    } 

    // whitespace preservation convention: ws1 immediately inside open tag; ws2 immediately after end tag. 
    sealed class StandardSignedInfo : SignedInfo 
    {
        string prefix = SignedXml.DefaultPrefix; 
        List references;
        Dictionary context;

        public StandardSignedInfo(DictionaryManager dictionaryManager) 
            : base(dictionaryManager)
        { 
            this.references = new List(); 
        }
 
        public override int ReferenceCount
        {
            get { return this.references.Count; }
        } 

        public Reference this[int index] 
        { 
            get { return this.references[index]; }
        } 

        public void AddReference(Reference reference)
        {
            reference.ResourcePool = this.ResourcePool; 
            this.references.Add(reference);
        } 
 
        public override void EnsureAllReferencesVerified()
        { 
            for (int i = 0; i < this.references.Count; i++)
            {
                if (!this.references[i].Verified)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new CryptographicException(SR.GetString(SR.UnableToResolveReferenceUriForSignature, this.references[i].Uri))); 
                } 
            }
        } 

        public override bool EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)
        {
            for (int i = 0; i < this.references.Count; i++) 
            {
                if (this.references[i].EnsureDigestValidityIfIdMatches(id, resolvedXmlSource)) 
                { 
                    return true;
                } 
            }
            return false;
        }
 
        public override bool HasUnverifiedReference(string id)
        { 
            for (int i = 0; i < this.references.Count; i++) 
            {
                if (!this.references[i].Verified && this.references[i].ExtractReferredId() == id) 
                {
                    return true;
                }
            } 
            return false;
        } 
 
        public override void ComputeReferenceDigests()
        { 
            if (this.references.Count == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.AtLeastOneReferenceRequired)));
            } 
            for (int i = 0; i < this.references.Count; i++)
            { 
                this.references[i].ComputeAndSetDigest(); 
            }
        } 

        public override void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)
        {
            this.SendSide = false; 
            if (reader.CanCanonicalize)
            { 
                this.CanonicalStream = new MemoryStream(); 
                reader.StartCanonicalization(this.CanonicalStream, false, null);
            } 

            reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.SignedInfo, dictionaryManager.XmlSignatureDictionary.Namespace);
            this.prefix = reader.Prefix;
            this.Id = reader.GetAttribute(dictionaryManager.UtilityDictionary.IdAttribute, null); 
            reader.Read();
 
            ReadCanonicalizationMethod(reader, dictionaryManager); 
            ReadSignatureMethod(reader, dictionaryManager);
            while (reader.IsStartElement(dictionaryManager.XmlSignatureDictionary.Reference, dictionaryManager.XmlSignatureDictionary.Namespace)) 
            {
                Reference reference = new Reference(dictionaryManager);
                reference.ReadFrom(reader, transformFactory, dictionaryManager);
                AddReference(reference); 
            }
            reader.ReadEndElement(); // SignedInfo 
 
            if (reader.CanCanonicalize)
                reader.EndCanonicalization(); 

            string[] inclusivePrefixes = GetInclusivePrefixes();
            if (inclusivePrefixes != null)
            { 
                // Clear the canonicalized stream. We cannot use this while inclusive prefixes are
                // specified. 
                this.CanonicalStream = null; 
                this.context = new Dictionary(inclusivePrefixes.Length);
                for (int i = 0; i < inclusivePrefixes.Length; i++) 
                {
                    this.context.Add(inclusivePrefixes[i], reader.LookupNamespace(inclusivePrefixes[i]));
                }
            } 
        }
 
        public override void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager) 
        {
            writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.SignedInfo, dictionaryManager.XmlSignatureDictionary.Namespace); 
            if (this.Id != null)
            {
                writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.Id);
            } 
            WriteCanonicalizationMethod(writer, dictionaryManager);
            WriteSignatureMethod(writer, dictionaryManager); 
            for (int i = 0; i < this.references.Count; i++) 
            {
                this.references[i].WriteTo(writer, dictionaryManager); 
            }
            writer.WriteEndElement(); // SignedInfo
        }
 
        protected override string GetNamespaceForInclusivePrefix(string prefix)
        { 
            if (this.context == null) 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
 
            if (prefix == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("prefix");

            return context[prefix]; 
        }
 
    } 

    sealed class Reference 
    {
        ElementWithAlgorithmAttribute digestMethodElement;
        DigestValueElement digestValueElement = new DigestValueElement();
        string id; 
        string prefix = SignedXml.DefaultPrefix;
        object resolvedXmlSource; 
        readonly TransformChain transformChain = new TransformChain(); 
        string type;
        string uri; 
        SignatureResourcePool resourcePool;
        bool verified;
        string referredId;
        DictionaryManager dictionaryManager; 

        public Reference(DictionaryManager dictionaryManager) 
            : this(dictionaryManager, null) 
        {
        } 

        public Reference(DictionaryManager dictionaryManager, string uri)
            : this(dictionaryManager, uri, null)
        { 
        }
 
        public Reference(DictionaryManager dictionaryManager, string uri, object resolvedXmlSource) 
        {
            if (dictionaryManager == null) 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryManager");

            this.dictionaryManager = dictionaryManager;
            this.digestMethodElement = new ElementWithAlgorithmAttribute(dictionaryManager.XmlSignatureDictionary.DigestMethod); 
            this.uri = uri;
            this.resolvedXmlSource = resolvedXmlSource; 
        } 

        public string DigestMethod 
        {
            get { return this.digestMethodElement.Algorithm; }
            set { this.digestMethodElement.Algorithm = value; }
        } 

        public XmlDictionaryString DigestMethodDictionaryString 
        { 
            get { return this.digestMethodElement.AlgorithmDictionaryString; }
            set { this.digestMethodElement.AlgorithmDictionaryString = value; } 
        }

        public string Id
        { 
            get { return this.id; }
            set { this.id = value; } 
        } 

        public SignatureResourcePool ResourcePool 
        {
            get { return this.resourcePool; }
            set { this.resourcePool = value; }
        } 

        public TransformChain TransformChain 
        { 
            get { return this.transformChain; }
        } 

        public int TransformCount
        {
            get { return this.transformChain.TransformCount; } 
        }
 
        public string Type 
        {
            get { return this.type; } 
            set { this.type = value; }
        }

        public string Uri 
        {
            get { return this.uri; } 
            set { this.uri = value; } 
        }
 
        public bool Verified
        {
            get { return this.verified; }
        } 

        public void AddTransform(Transform transform) 
        { 
            this.transformChain.Add(transform);
        } 

        public void EnsureDigestValidity(string id, byte[] computedDigest)
        {
            if (!EnsureDigestValidityIfIdMatches(id, computedDigest)) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException( 
                    SR.GetString(SR.RequiredTargetNotSigned, id))); 
            }
        } 

        public void EnsureDigestValidity(string id, object resolvedXmlSource)
        {
            if (!EnsureDigestValidityIfIdMatches(id, resolvedXmlSource)) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException( 
                    SR.GetString(SR.RequiredTargetNotSigned, id))); 
            }
        } 

        public bool EnsureDigestValidityIfIdMatches(string id, byte[] computedDigest)
        {
            if (this.verified || id != ExtractReferredId()) 
            {
                return false; 
            } 
            if (!CryptoHelper.IsEqual(computedDigest, GetDigestValue()))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new CryptographicException(SR.GetString(SR.DigestVerificationFailedForReference, this.uri)));
            }
            this.verified = true; 
            return true;
        } 
 
        public bool EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)
        { 
            if (this.verified || id != ExtractReferredId())
            {
                return false;
            } 
            this.resolvedXmlSource = resolvedXmlSource;
            if (!CheckDigest()) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new CryptographicException(SR.GetString(SR.DigestVerificationFailedForReference, this.uri))); 
            }
            this.verified = true;
            return true;
        } 

        public string ExtractReferredId() 
        { 
            if (this.referredId == null)
            { 
                if (this.uri == null || this.uri.Length < 2 || this.uri[0] != '#')
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new CryptographicException(SR.GetString(SR.UnableToResolveReferenceUriForSignature, this.uri))); 
                }
                this.referredId = this.uri.Substring(1); 
            } 
            return this.referredId;
        } 

        public bool CheckDigest()
        {
            byte[] computedDigest = ComputeDigest(); 
            bool result = CryptoHelper.IsEqual(computedDigest, GetDigestValue());
#if LOG_DIGESTS 
            Console.WriteLine(">>> Checking digest for reference '{0}', result {1}", uri, result); 
            Console.WriteLine("    Computed digest {0}", Convert.ToBase64String(computedDigest));
            Console.WriteLine("    Received digest {0}", Convert.ToBase64String(GetDigestValue())); 
#endif
            return result;
        }
 
        public void ComputeAndSetDigest()
        { 
            this.digestValueElement.Value = ComputeDigest(); 
        }
 
        public byte[] ComputeDigest()
        {
            if (this.transformChain.TransformCount == 0)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.EmptyTransformChainNotSupported)));
            } 
 
            if (this.resolvedXmlSource == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
                    SR.GetString(SR.UnableToResolveReferenceUriForSignature, this.uri)));
            }
            return this.transformChain.TransformToDigest(this.resolvedXmlSource, this.ResourcePool, this.DigestMethod, this.dictionaryManager); 
        }
 
        public byte[] GetDigestValue() 
        {
            return this.digestValueElement.Value; 
        }

        public void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)
        { 
            reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.Reference, dictionaryManager.XmlSignatureDictionary.Namespace);
            this.prefix = reader.Prefix; 
            this.Id = reader.GetAttribute(UtilityStrings.IdAttribute, null); 
            this.Uri = reader.GetAttribute(dictionaryManager.XmlSignatureDictionary.URI, null);
            this.Type = reader.GetAttribute(dictionaryManager.XmlSignatureDictionary.Type, null); 
            reader.Read();

            if (reader.IsStartElement(dictionaryManager.XmlSignatureDictionary.Transforms, dictionaryManager.XmlSignatureDictionary.Namespace))
            { 
                this.transformChain.ReadFrom(reader, transformFactory, dictionaryManager);
            } 
            this.digestMethodElement.ReadFrom(reader, dictionaryManager); 
            this.digestValueElement.ReadFrom(reader, dictionaryManager);
 
            reader.MoveToContent();
            reader.ReadEndElement(); // Reference
        }
 
        public void SetResolvedXmlSource(object resolvedXmlSource)
        { 
            this.resolvedXmlSource = resolvedXmlSource; 
        }
 
        public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
        {
            writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.Reference, dictionaryManager.XmlSignatureDictionary.Namespace);
            if (this.id != null) 
            {
                writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.id); 
            } 
            if (this.uri != null)
            { 
                writer.WriteAttributeString(dictionaryManager.XmlSignatureDictionary.URI, null, this.uri);
            }
            if (this.type != null)
            { 
                writer.WriteAttributeString(dictionaryManager.XmlSignatureDictionary.Type, null, this.type);
            } 
 
            if (this.transformChain.TransformCount > 0)
            { 
                this.transformChain.WriteTo(writer, dictionaryManager);
            }

            this.digestMethodElement.WriteTo(writer, dictionaryManager); 
            this.digestValueElement.WriteTo(writer, dictionaryManager);
 
            writer.WriteEndElement(); // Reference 
        }
 
        struct DigestValueElement
        {
            byte[] digestValue;
            string digestText; 
            string prefix;
 
            internal byte[] Value 
            {
                get { return this.digestValue; } 
                set
                {
                    this.digestValue = value;
                    this.digestText = null; 
                }
            } 
 
            public void ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
            { 
                reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.DigestValue, dictionaryManager.XmlSignatureDictionary.Namespace);
                this.prefix = reader.Prefix;
                reader.Read();
                reader.MoveToContent(); 

                this.digestText = reader.ReadString(); 
                this.digestValue = System.Convert.FromBase64String(digestText.Trim()); 

                reader.MoveToContent(); 
                reader.ReadEndElement(); // DigestValue
            }

            public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager) 
            {
                writer.WriteStartElement(this.prefix ?? XmlSignatureStrings.Prefix, dictionaryManager.XmlSignatureDictionary.DigestValue, dictionaryManager.XmlSignatureDictionary.Namespace); 
                if (this.digestText != null) 
                {
                    writer.WriteString(this.digestText); 
                }
                else
                {
                    writer.WriteBase64(this.digestValue, 0, this.digestValue.Length); 
                }
                writer.WriteEndElement(); // DigestValue 
            } 
        }
    } 

    sealed class TransformChain
    {
        string prefix = SignedXml.DefaultPrefix; 
        MostlySingletonList transforms;
 
        public TransformChain() 
        {
        } 

        public int TransformCount
        {
            get { return this.transforms.Count; } 
        }
 
        public Transform this[int index] 
        {
            get 
            {
                return this.transforms[index];
            }
        } 

        public bool NeedsInclusiveContext 
        { 
            get
            { 
                for (int i = 0; i < this.TransformCount; i++)
                {
                    if (this[i].NeedsInclusiveContext)
                    { 
                        return true;
                    } 
                } 
                return false;
            } 
        }

        public void Add(Transform transform)
        { 
            this.transforms.Add(transform);
        } 
 
        public void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)
        { 
            reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.Transforms, dictionaryManager.XmlSignatureDictionary.Namespace);
            this.prefix = reader.Prefix;
            reader.Read();
 
            while (reader.IsStartElement(dictionaryManager.XmlSignatureDictionary.Transform, dictionaryManager.XmlSignatureDictionary.Namespace))
            { 
                string transformAlgorithmUri = reader.GetAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null); 
                Transform transform = transformFactory.CreateTransform(transformAlgorithmUri);
                transform.ReadFrom(reader, dictionaryManager); 
                Add(transform);
            }
            reader.MoveToContent();
            reader.ReadEndElement(); // Transforms 
            if (this.TransformCount == 0)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.AtLeastOneTransformRequired))); 
            }
        } 

        public byte[] TransformToDigest(object data, SignatureResourcePool resourcePool, string digestMethod, DictionaryManager dictionaryManager)
        {
            DiagnosticUtility.DebugAssert(TransformCount > 0, ""); 
            for (int i = 0; i < this.TransformCount - 1; i++)
            { 
                data = this[i].Process(data, resourcePool, dictionaryManager); 
            }
            return this[this.TransformCount - 1].ProcessAndDigest(data, resourcePool, digestMethod, dictionaryManager); 
        }

        public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
        { 
            writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.Transforms, dictionaryManager.XmlSignatureDictionary.Namespace);
            for (int i = 0; i < this.TransformCount; i++) 
            { 
                this[i].WriteTo(writer, dictionaryManager);
            } 
            writer.WriteEndElement(); // Transforms
        }
    }
 
    struct ElementWithAlgorithmAttribute
    { 
        readonly XmlDictionaryString elementName; 
        string algorithm;
        XmlDictionaryString algorithmDictionaryString; 
        string prefix;

        public ElementWithAlgorithmAttribute(XmlDictionaryString elementName)
        { 
            if (elementName == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("elementName")); 
            }
            this.elementName = elementName; 
            this.algorithm = null;
            this.algorithmDictionaryString = null;
            this.prefix = SignedXml.DefaultPrefix;
        } 

        public string Algorithm 
        { 
            get { return this.algorithm; }
            set { this.algorithm = value; } 
        }

        public XmlDictionaryString AlgorithmDictionaryString
        { 
            get { return this.algorithmDictionaryString; }
            set { this.algorithmDictionaryString = value; } 
        } 

        public void ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager) 
        {
            reader.MoveToStartElement(this.elementName, dictionaryManager.XmlSignatureDictionary.Namespace);
            this.prefix = reader.Prefix;
            bool isEmptyElement = reader.IsEmptyElement; 
            this.algorithm = reader.GetAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null);
            if (this.algorithm == null) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
                    SR.GetString(SR.RequiredAttributeMissing, dictionaryManager.XmlSignatureDictionary.Algorithm, this.elementName))); 
            }
            reader.Read();
            reader.MoveToContent();
 
            if (!isEmptyElement)
            { 
                reader.MoveToContent(); 
                reader.ReadEndElement();
            } 
        }

        public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
        { 
            writer.WriteStartElement(this.prefix, this.elementName, dictionaryManager.XmlSignatureDictionary.Namespace);
            writer.WriteStartAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null); 
            if (this.algorithmDictionaryString != null) 
            {
                writer.WriteString(this.algorithmDictionaryString); 
            }
            else
            {
                writer.WriteString(this.algorithm); 
            }
            writer.WriteEndAttribute(); 
            writer.WriteEndElement(); 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK