File: System\IdentityModel\Tokens\XmlDsigSep2000.cs
Web Access
Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Xml;
using KeyIdentifierEntry = System.IdentityModel.Selectors.SecurityTokenSerializer.KeyIdentifierEntry;
 
namespace System.IdentityModel.Tokens
{
    internal class XmlDsigSep2000 : SecurityTokenSerializer.SerializerEntries
    {
        private KeyInfoSerializer _securityTokenSerializer;
 
        public XmlDsigSep2000(KeyInfoSerializer securityTokenSerializer)
        {
            _securityTokenSerializer = securityTokenSerializer;
        }
 
        public override void PopulateKeyIdentifierEntries(IList<KeyIdentifierEntry> keyIdentifierEntries)
        {
            keyIdentifierEntries.Add(new KeyInfoEntry(_securityTokenSerializer));
        }
 
        public override void PopulateKeyIdentifierClauseEntries(IList<SecurityTokenSerializer.KeyIdentifierClauseEntry> keyIdentifierClauseEntries)
        {
            keyIdentifierClauseEntries.Add(new X509CertificateClauseEntry());
        }
 
        internal class KeyInfoEntry : KeyIdentifierEntry
        {
            private KeyInfoSerializer _securityTokenSerializer;
 
            public KeyInfoEntry(KeyInfoSerializer securityTokenSerializer)
            {
                _securityTokenSerializer = securityTokenSerializer;
            }
 
            protected override XmlDictionaryString LocalName
            {
                get
                {
                    return XD.XmlSignatureDictionary.KeyInfo;
                }
            }
 
            protected override XmlDictionaryString NamespaceUri
            {
                get
                {
                    return XD.XmlSignatureDictionary.Namespace;
                }
            }
 
            public override SecurityKeyIdentifier ReadKeyIdentifierCore(XmlDictionaryReader reader)
            {
                reader.ReadStartElement(LocalName, NamespaceUri);
                SecurityKeyIdentifier keyIdentifier = new SecurityKeyIdentifier();
                while (reader.IsStartElement())
                {
                    SecurityKeyIdentifierClause clause = _securityTokenSerializer.ReadKeyIdentifierClause(reader);
                    if (clause == null)
                    {
                        reader.Skip();
                    }
                    else
                    {
                        keyIdentifier.Add(clause);
                    }
                }
                if (keyIdentifier.Count == 0)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SRP.ErrorDeserializingKeyIdentifierClause));
                }
                reader.ReadEndElement();
                return keyIdentifier;
            }
 
            public override bool SupportsCore(SecurityKeyIdentifier keyIdentifier)
            {
                return true;
            }
 
            public override void WriteKeyIdentifierCore(XmlDictionaryWriter writer, SecurityKeyIdentifier keyIdentifier)
            {
                writer.WriteStartElement(XD.XmlSignatureDictionary.Prefix.Value, LocalName, NamespaceUri);
                bool clauseWritten = false;
                foreach (SecurityKeyIdentifierClause clause in keyIdentifier)
                {
                    _securityTokenSerializer.InnerSecurityTokenSerializer.WriteKeyIdentifierClause(writer, clause);
                    clauseWritten = true;
                }
                writer.WriteEndElement(); // KeyInfo
                if (!clauseWritten)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityMessageSerializationException(SRP.NoKeyInfoClausesToWrite));
                }
            }
        }
 
        // so far, we only support two types of X509Data directly under KeyInfo  - X509Certificate and X509SKI
        //   <ds:X509Data>
        //     <ds:X509Certificate>...</ds:X509Certificate>
        //      or
        //     <X509SKI>... </X509SKI>
        //   </ds:X509Data>
        // only support 1 certificate right now
        internal class X509CertificateClauseEntry : SecurityTokenSerializer.KeyIdentifierClauseEntry
        {
            protected override XmlDictionaryString LocalName
            {
                get
                {
                    return XD.XmlSignatureDictionary.X509Data;
                }
            }
 
            protected override XmlDictionaryString NamespaceUri
            {
                get
                {
                    return XD.XmlSignatureDictionary.Namespace;
                }
            }
 
            public override SecurityKeyIdentifierClause ReadKeyIdentifierClauseCore(XmlDictionaryReader reader)
            {
                SecurityKeyIdentifierClause ski = null;
                reader.ReadStartElement(XD.XmlSignatureDictionary.X509Data, NamespaceUri);
                while (reader.IsStartElement())
                {
                    if (ski == null && reader.IsStartElement(XD.XmlSignatureDictionary.X509Certificate, NamespaceUri))
                    {
                        X509Certificate2 certificate = null;
                        if (!SecurityUtils.TryCreateX509CertificateFromRawData(reader.ReadElementContentAsBase64(), out certificate))
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityMessageSerializationException(SRP.InvalidX509RawData));
                        }
                        ski = new X509RawDataKeyIdentifierClause(certificate);
                    }
                    else if (ski == null && reader.IsStartElement(XmlSignatureStrings.X509Ski, NamespaceUri.ToString()))
                    {
                        ski = new X509SubjectKeyIdentifierClause(reader.ReadElementContentAsBase64());
                    }
                    else if ((ski == null) && reader.IsStartElement(XD.XmlSignatureDictionary.X509IssuerSerial, XD.XmlSignatureDictionary.Namespace))
                    {
                        reader.ReadStartElement(XD.XmlSignatureDictionary.X509IssuerSerial, XD.XmlSignatureDictionary.Namespace);
                        reader.ReadStartElement(XD.XmlSignatureDictionary.X509IssuerName, XD.XmlSignatureDictionary.Namespace);
                        string issuerName = reader.ReadContentAsString();
                        reader.ReadEndElement();
                        reader.ReadStartElement(XD.XmlSignatureDictionary.X509SerialNumber, XD.XmlSignatureDictionary.Namespace);
                        string serialNumber = reader.ReadContentAsString();
                        reader.ReadEndElement();
                        reader.ReadEndElement();
 
                        ski = new X509IssuerSerialKeyIdentifierClause(issuerName, serialNumber);
                    }
                    else
                    {
                        reader.Skip();
                    }
                }
                reader.ReadEndElement();
                return ski;
            }
 
            public override bool SupportsCore(SecurityKeyIdentifierClause keyIdentifierClause)
            {
                return (keyIdentifierClause is X509RawDataKeyIdentifierClause);
                // This method should not write X509IssuerSerialKeyIdentifierClause or X509SubjectKeyIdentifierClause as that should be written by the WSSecurityXXX classes with SecurityTokenReference tag. 
                // The XmlDsig entries are written by the X509SecurityTokenHandler.
            }
 
            public override void WriteKeyIdentifierClauseCore(XmlDictionaryWriter writer, SecurityKeyIdentifierClause keyIdentifierClause)
            {
                X509RawDataKeyIdentifierClause x509Clause = keyIdentifierClause as X509RawDataKeyIdentifierClause;
 
                if (x509Clause != null)
                {
                    writer.WriteStartElement(XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.X509Data, NamespaceUri);
 
                    writer.WriteStartElement(XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.X509Certificate, NamespaceUri);
                    byte[] certBytes = x509Clause.GetX509RawData();
                    writer.WriteBase64(certBytes, 0, certBytes.Length);
                    writer.WriteEndElement();
 
                    writer.WriteEndElement();
                }
 
                X509IssuerSerialKeyIdentifierClause issuerSerialClause = keyIdentifierClause as X509IssuerSerialKeyIdentifierClause;
                if (issuerSerialClause != null)
                {
                    writer.WriteStartElement(XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.X509Data, XD.XmlSignatureDictionary.Namespace);
                    writer.WriteStartElement(XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.X509IssuerSerial, XD.XmlSignatureDictionary.Namespace);
                    writer.WriteElementString(XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.X509IssuerName, XD.XmlSignatureDictionary.Namespace, issuerSerialClause.IssuerName);
                    writer.WriteElementString(XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.X509SerialNumber, XD.XmlSignatureDictionary.Namespace, issuerSerialClause.IssuerSerialNumber);
                    writer.WriteEndElement();
                    writer.WriteEndElement();
                    return;
                }
 
                X509SubjectKeyIdentifierClause skiClause = keyIdentifierClause as X509SubjectKeyIdentifierClause;
                if (skiClause != null)
                {
                    writer.WriteStartElement(XmlSignatureConstants.Prefix, XmlSignatureConstants.Elements.X509Data, XmlSignatureConstants.Namespace);
                    writer.WriteStartElement(XmlSignatureConstants.Prefix, XmlSignatureConstants.Elements.X509SKI, XmlSignatureConstants.Namespace);
                    byte[] ski = skiClause.GetX509SubjectKeyIdentifier();
                    writer.WriteBase64(ski, 0, ski.Length);
                    writer.WriteEndElement();
                    writer.WriteEndElement();
                    return;
                }
            }
        }
    }
}