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