1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 namespace System.ServiceModel.Channels 5 { 6 using System.Security.Authentication; 7 using System.ComponentModel; 8 using System.Collections.Generic; 9 using System.Net.Security; 10 using System.ServiceModel.Description; 11 using System.ServiceModel; 12 using System.ServiceModel.Security; 13 using System.ServiceModel.Security.Tokens; 14 using System.Xml; 15 16 public class SslStreamSecurityBindingElement : StreamUpgradeBindingElement, ITransportTokenAssertionProvider, IPolicyExportExtension 17 { 18 IdentityVerifier identityVerifier; 19 bool requireClientCertificate; 20 SslProtocols sslProtocols; 21 SslStreamSecurityBindingElement()22 public SslStreamSecurityBindingElement() 23 { 24 this.requireClientCertificate = TransportDefaults.RequireClientCertificate; 25 this.sslProtocols = TransportDefaults.SslProtocols; 26 } 27 SslStreamSecurityBindingElement(SslStreamSecurityBindingElement elementToBeCloned)28 protected SslStreamSecurityBindingElement(SslStreamSecurityBindingElement elementToBeCloned) 29 : base(elementToBeCloned) 30 { 31 this.identityVerifier = elementToBeCloned.identityVerifier; 32 this.requireClientCertificate = elementToBeCloned.requireClientCertificate; 33 this.sslProtocols = elementToBeCloned.sslProtocols; 34 } 35 36 public IdentityVerifier IdentityVerifier 37 { 38 get 39 { 40 if (this.identityVerifier == null) 41 { 42 this.identityVerifier = IdentityVerifier.CreateDefault(); 43 } 44 45 return this.identityVerifier; 46 } 47 set 48 { 49 if (value == null) 50 { 51 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); 52 } 53 54 this.identityVerifier = value; 55 } 56 } 57 58 [DefaultValue(TransportDefaults.RequireClientCertificate)] 59 public bool RequireClientCertificate 60 { 61 get 62 { 63 return this.requireClientCertificate; 64 } 65 set 66 { 67 this.requireClientCertificate = value; 68 } 69 } 70 71 [DefaultValue(TransportDefaults.OldDefaultSslProtocols)] 72 public SslProtocols SslProtocols 73 { 74 get 75 { 76 return this.sslProtocols; 77 } 78 set 79 { 80 SslProtocolsHelper.Validate(value); 81 this.sslProtocols = value; 82 } 83 } 84 BuildChannelFactory(BindingContext context)85 public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context) 86 { 87 if (context == null) 88 { 89 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); 90 } 91 92 #pragma warning suppress 56506 // Microsoft, BindingContext.BindingParameters cannot be null 93 context.BindingParameters.Add(this); 94 return context.BuildInnerChannelFactory<TChannel>(); 95 } 96 CanBuildChannelFactory(BindingContext context)97 public override bool CanBuildChannelFactory<TChannel>(BindingContext context) 98 { 99 if (context == null) 100 { 101 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); 102 } 103 104 #pragma warning suppress 56506 // Microsoft, BindingContext.BindingParameters cannot be null 105 context.BindingParameters.Add(this); 106 return context.CanBuildInnerChannelFactory<TChannel>(); 107 } 108 BuildChannelListener(BindingContext context)109 public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) 110 { 111 if (context == null) 112 { 113 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); 114 } 115 116 #pragma warning suppress 56506 // Microsoft, BindingContext.BindingParameters cannot be null 117 context.BindingParameters.Add(this); 118 return context.BuildInnerChannelListener<TChannel>(); 119 } 120 CanBuildChannelListener(BindingContext context)121 public override bool CanBuildChannelListener<TChannel>(BindingContext context) 122 { 123 if (context == null) 124 { 125 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); 126 } 127 128 #pragma warning suppress 56506 // Microsoft, BindingContext.BindingParameters cannot be null 129 context.BindingParameters.Add(this); 130 return context.CanBuildInnerChannelListener<TChannel>(); 131 } 132 Clone()133 public override BindingElement Clone() 134 { 135 return new SslStreamSecurityBindingElement(this); 136 } 137 GetProperty(BindingContext context)138 public override T GetProperty<T>(BindingContext context) 139 { 140 if (context == null) 141 { 142 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); 143 } 144 if (typeof(T) == typeof(ISecurityCapabilities)) 145 { 146 return (T)(object)new SecurityCapabilities(this.RequireClientCertificate, true, this.RequireClientCertificate, 147 ProtectionLevel.EncryptAndSign, ProtectionLevel.EncryptAndSign); 148 } 149 else if (typeof(T) == typeof(IdentityVerifier)) 150 { 151 return (T)(object)this.IdentityVerifier; 152 } 153 else 154 { 155 return context.GetInnerProperty<T>(); 156 } 157 } 158 BuildClientStreamUpgradeProvider(BindingContext context)159 public override StreamUpgradeProvider BuildClientStreamUpgradeProvider(BindingContext context) 160 { 161 return SslStreamSecurityUpgradeProvider.CreateClientProvider(this, context); 162 } 163 BuildServerStreamUpgradeProvider(BindingContext context)164 public override StreamUpgradeProvider BuildServerStreamUpgradeProvider(BindingContext context) 165 { 166 return SslStreamSecurityUpgradeProvider.CreateServerProvider(this, context); 167 } 168 169 ImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext)170 internal static void ImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext) 171 { 172 XmlElement assertion = PolicyConversionContext.FindAssertion(policyContext.GetBindingAssertions(), 173 TransportPolicyConstants.SslTransportSecurityName, TransportPolicyConstants.DotNetFramingNamespace, true); 174 175 if (assertion != null) 176 { 177 SslStreamSecurityBindingElement sslBindingElement = new SslStreamSecurityBindingElement(); 178 179 XmlReader reader = new XmlNodeReader(assertion); 180 reader.ReadStartElement(); 181 sslBindingElement.RequireClientCertificate = reader.IsStartElement( 182 TransportPolicyConstants.RequireClientCertificateName, 183 TransportPolicyConstants.DotNetFramingNamespace); 184 if (sslBindingElement.RequireClientCertificate) 185 { 186 reader.ReadElementString(); 187 } 188 189 policyContext.BindingElements.Add(sslBindingElement); 190 } 191 } 192 193 #region ITransportTokenAssertionProvider Members 194 GetTransportTokenAssertion()195 public XmlElement GetTransportTokenAssertion() 196 { 197 XmlDocument document = new XmlDocument(); 198 XmlElement assertion = 199 document.CreateElement(TransportPolicyConstants.DotNetFramingPrefix, 200 TransportPolicyConstants.SslTransportSecurityName, 201 TransportPolicyConstants.DotNetFramingNamespace); 202 if (this.requireClientCertificate) 203 { 204 assertion.AppendChild(document.CreateElement(TransportPolicyConstants.DotNetFramingPrefix, 205 TransportPolicyConstants.RequireClientCertificateName, 206 TransportPolicyConstants.DotNetFramingNamespace)); 207 } 208 return assertion; 209 } 210 211 #endregion 212 IPolicyExportExtension.ExportPolicy(MetadataExporter exporter, PolicyConversionContext context)213 void IPolicyExportExtension.ExportPolicy(MetadataExporter exporter, PolicyConversionContext context) 214 { 215 if (exporter == null) 216 { 217 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exporter"); 218 } 219 if (context == null) 220 { 221 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); 222 } 223 224 SecurityBindingElement.ExportPolicyForTransportTokenAssertionProviders(exporter, context); 225 } 226 IsMatch(BindingElement b)227 internal override bool IsMatch(BindingElement b) 228 { 229 if (b == null) 230 { 231 return false; 232 } 233 SslStreamSecurityBindingElement ssl = b as SslStreamSecurityBindingElement; 234 if (ssl == null) 235 { 236 return false; 237 } 238 239 return this.requireClientCertificate == ssl.requireClientCertificate && this.sslProtocols == ssl.sslProtocols; 240 } 241 242 [EditorBrowsable(EditorBrowsableState.Never)] ShouldSerializeIdentityVerifier()243 public bool ShouldSerializeIdentityVerifier() 244 { 245 // IdentifyVerifier.CreateDefault() grabs the static instance of nested DefaultIdentityVerifier. 246 // DefaultIdentityVerifier can't be serialized directly because it's nested. 247 return (!object.ReferenceEquals(this.IdentityVerifier, IdentityVerifier.CreateDefault())); 248 } 249 } 250 } 251