//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.IdentityModel.Tokens { using System; using System.Collections.Generic; using System.IdentityModel.Selectors; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.ServiceModel.Security; using System.Xml; using KeyIdentifierEntry = System.IdentityModel.Selectors.SecurityTokenSerializer.KeyIdentifierEntry; class XmlDsigSep2000 : SecurityTokenSerializer.SerializerEntries { KeyInfoSerializer securityTokenSerializer; public XmlDsigSep2000( KeyInfoSerializer securityTokenSerializer ) { this.securityTokenSerializer = securityTokenSerializer; } public override void PopulateKeyIdentifierEntries( IList keyIdentifierEntries ) { keyIdentifierEntries.Add( new KeyInfoEntry( this.securityTokenSerializer ) ); } public override void PopulateKeyIdentifierClauseEntries( IList keyIdentifierClauseEntries ) { keyIdentifierClauseEntries.Add( new KeyNameClauseEntry() ); keyIdentifierClauseEntries.Add( new KeyValueClauseEntry() ); keyIdentifierClauseEntries.Add( new X509CertificateClauseEntry() ); } internal class KeyInfoEntry : KeyIdentifierEntry { KeyInfoSerializer securityTokenSerializer; public KeyInfoEntry( KeyInfoSerializer securityTokenSerializer ) { this.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 = this.securityTokenSerializer.ReadKeyIdentifierClause( reader ); if ( clause == null ) { reader.Skip(); } else { keyIdentifier.Add( clause ); } } if ( keyIdentifier.Count == 0 ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new XmlException( SR.GetString( SR.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 ) { this.securityTokenSerializer.InnerSecurityTokenSerializer.WriteKeyIdentifierClause( writer, clause ); clauseWritten = true; } writer.WriteEndElement(); // KeyInfo if ( !clauseWritten ) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityMessageSerializationException( SR.GetString( SR.NoKeyInfoClausesToWrite ) ) ); } } } // name internal class KeyNameClauseEntry : SecurityTokenSerializer.KeyIdentifierClauseEntry { protected override XmlDictionaryString LocalName { get { return XD.XmlSignatureDictionary.KeyName; } } protected override XmlDictionaryString NamespaceUri { get { return XD.XmlSignatureDictionary.Namespace; } } public override SecurityKeyIdentifierClause ReadKeyIdentifierClauseCore( XmlDictionaryReader reader ) { reader.ReadStartElement( XD.XmlSignatureDictionary.KeyName, NamespaceUri ); string name = reader.ReadString(); reader.ReadEndElement(); return new KeyNameIdentifierClause( name ); } public override bool SupportsCore( SecurityKeyIdentifierClause keyIdentifierClause ) { return keyIdentifierClause is KeyNameIdentifierClause; } public override void WriteKeyIdentifierClauseCore( XmlDictionaryWriter writer, SecurityKeyIdentifierClause keyIdentifierClause ) { KeyNameIdentifierClause nameClause = keyIdentifierClause as KeyNameIdentifierClause; writer.WriteElementString( XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.KeyName, NamespaceUri, nameClause.KeyName ); } } // so far, we only support one type of KeyValue - RSAKeyValue // // // xA7SEU+... // AQAB // // internal class KeyValueClauseEntry : SecurityTokenSerializer.KeyIdentifierClauseEntry { protected override XmlDictionaryString LocalName { get { return XD.XmlSignatureDictionary.KeyValue; } } protected override XmlDictionaryString NamespaceUri { get { return XD.XmlSignatureDictionary.Namespace; } } public override SecurityKeyIdentifierClause ReadKeyIdentifierClauseCore( XmlDictionaryReader reader ) { reader.ReadStartElement( XD.XmlSignatureDictionary.KeyValue, NamespaceUri ); reader.ReadStartElement( XD.XmlSignatureDictionary.RsaKeyValue, NamespaceUri ); reader.ReadStartElement( XD.XmlSignatureDictionary.Modulus, NamespaceUri ); byte[] modulus = Convert.FromBase64String( reader.ReadString() ); reader.ReadEndElement(); reader.ReadStartElement( XD.XmlSignatureDictionary.Exponent, NamespaceUri ); byte[] exponent = Convert.FromBase64String( reader.ReadString() ); reader.ReadEndElement(); reader.ReadEndElement(); reader.ReadEndElement(); RSA rsa = new RSACryptoServiceProvider(); RSAParameters rsaParameters = new RSAParameters(); rsaParameters.Modulus = modulus; rsaParameters.Exponent = exponent; rsa.ImportParameters( rsaParameters ); return new RsaKeyIdentifierClause( rsa ); } public override bool SupportsCore( SecurityKeyIdentifierClause keyIdentifierClause ) { return keyIdentifierClause is RsaKeyIdentifierClause; } public override void WriteKeyIdentifierClauseCore( XmlDictionaryWriter writer, SecurityKeyIdentifierClause keyIdentifierClause ) { RsaKeyIdentifierClause rsaClause = keyIdentifierClause as RsaKeyIdentifierClause; writer.WriteStartElement( XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.KeyValue, NamespaceUri ); writer.WriteStartElement( XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.RsaKeyValue, NamespaceUri ); writer.WriteStartElement( XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.Modulus, NamespaceUri ); rsaClause.WriteModulusAsBase64( writer ); writer.WriteEndElement(); writer.WriteStartElement( XD.XmlSignatureDictionary.Prefix.Value, XD.XmlSignatureDictionary.Exponent, NamespaceUri ); rsaClause.WriteExponentAsBase64( writer ); writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndElement(); } } // so far, we only support two types of X509Data directly under KeyInfo - X509Certificate and X509SKI // // ... // or // ... // // 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( SR.GetString( SR.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; } } } } }