1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 
5 namespace System.ServiceModel.Security
6 {
7     using System;
8     using System.Collections.ObjectModel;
9     using System.IdentityModel.Policy;
10     using System.IdentityModel.Selectors;
11     using System.IdentityModel.Tokens;
12     using System.Runtime;
13     using System.Security.Cryptography.X509Certificates;
14     using System.Security.Principal;
15     using System.ServiceModel;
16     using System.Xml;
17     using SchProtocols = System.IdentityModel.SchProtocols;
18 
19     sealed class TlsnegoTokenAuthenticator : SspiNegotiationTokenAuthenticator
20     {
21         SecurityTokenAuthenticator clientTokenAuthenticator;
22         SecurityTokenProvider serverTokenProvider;
23         X509SecurityToken serverToken;
24         bool mapCertificateToWindowsAccount;
25 
TlsnegoTokenAuthenticator()26         public TlsnegoTokenAuthenticator()
27             : base()
28         {
29             // empty
30         }
31 
32         public SecurityTokenAuthenticator ClientTokenAuthenticator
33         {
34             get
35             {
36                 return this.clientTokenAuthenticator;
37             }
38             set
39             {
40                 this.CommunicationObject.ThrowIfDisposedOrImmutable();
41                 this.clientTokenAuthenticator = value;
42             }
43         }
44 
45         public SecurityTokenProvider ServerTokenProvider
46         {
47             get
48             {
49                 return this.serverTokenProvider;
50             }
51             set
52             {
53                 this.CommunicationObject.ThrowIfDisposedOrImmutable();
54                 this.serverTokenProvider = value;
55             }
56         }
57 
58         public bool MapCertificateToWindowsAccount
59         {
60             get
61             {
62                 return this.mapCertificateToWindowsAccount;
63             }
64             set
65             {
66                 this.CommunicationObject.ThrowIfDisposedOrImmutable();
67                 this.mapCertificateToWindowsAccount = value;
68             }
69         }
70 
ValidateX509Token(SecurityToken token)71         X509SecurityToken ValidateX509Token(SecurityToken token)
72         {
73             X509SecurityToken result = token as X509SecurityToken;
74             if (result == null)
75             {
76                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.TokenProviderReturnedBadToken, token == null ? "<null>" : token.GetType().ToString())));
77             }
78             SecurityUtils.EnsureCertificateCanDoKeyExchange(result.Certificate);
79             return result;
80         }
81 
82         // overrides
83         public override XmlDictionaryString NegotiationValueType
84         {
85             get
86             {
87                 if (this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrustFeb2005)
88                 {
89                     return XD.TrustApr2004Dictionary.TlsnegoValueTypeUri;
90                 }
91                 else if (this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrust13)
92                 {
93                     return DXD.TrustDec2005Dictionary.TlsnegoValueTypeUri;
94                 }
95                 // Not supported
96                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
97             }
98         }
99 
OnOpen(TimeSpan timeout)100         public override void OnOpen(TimeSpan timeout)
101         {
102             if (this.serverTokenProvider == null)
103             {
104                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NoServerX509TokenProvider)));
105             }
106             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
107             SecurityUtils.OpenTokenProviderIfRequired(this.serverTokenProvider, timeoutHelper.RemainingTime());
108             if (this.clientTokenAuthenticator != null)
109             {
110                 SecurityUtils.OpenTokenAuthenticatorIfRequired(this.clientTokenAuthenticator, timeoutHelper.RemainingTime());
111             }
112             SecurityToken token = this.serverTokenProvider.GetToken(timeoutHelper.RemainingTime());
113             this.serverToken = ValidateX509Token(token);
114             base.OnOpen(timeoutHelper.RemainingTime());
115         }
116 
OnClose(TimeSpan timeout)117         public override void OnClose(TimeSpan timeout)
118         {
119             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
120             if (this.serverTokenProvider != null)
121             {
122                 SecurityUtils.CloseTokenProviderIfRequired(this.serverTokenProvider, timeoutHelper.RemainingTime());
123                 this.serverTokenProvider = null;
124             }
125             if (this.clientTokenAuthenticator != null)
126             {
127                 SecurityUtils.CloseTokenAuthenticatorIfRequired(this.clientTokenAuthenticator, timeoutHelper.RemainingTime());
128                 this.clientTokenAuthenticator = null;
129             }
130             if (this.serverToken != null)
131             {
132                 this.serverToken = null;
133             }
134             base.OnClose(timeoutHelper.RemainingTime());
135         }
136 
OnAbort()137         public override void OnAbort()
138         {
139             if (this.serverTokenProvider != null)
140             {
141                 SecurityUtils.AbortTokenProviderIfRequired(this.serverTokenProvider);
142                 this.serverTokenProvider = null;
143             }
144             if (this.clientTokenAuthenticator != null)
145             {
146                 SecurityUtils.AbortTokenAuthenticatorIfRequired(this.clientTokenAuthenticator);
147                 this.clientTokenAuthenticator = null;
148             }
149             if (this.serverToken != null)
150             {
151                 this.serverToken = null;
152             }
153             base.OnAbort();
154         }
155 
ValidateIncomingBinaryNegotiation(BinaryNegotiation incomingNego)156         protected override void ValidateIncomingBinaryNegotiation(BinaryNegotiation incomingNego)
157         {
158             // Accept both strings for WSTrustFeb2005
159             if (incomingNego != null &&
160                 incomingNego.ValueTypeUri != this.NegotiationValueType.Value &&
161                 this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrustFeb2005)
162             {
163                 incomingNego.Validate(DXD.TrustDec2005Dictionary.TlsnegoValueTypeUri);
164             }
165             else
166             {
167                 base.ValidateIncomingBinaryNegotiation(incomingNego);
168             }
169         }
170 
CreateSspiState(byte[] incomingBlob, string incomingValueTypeUri)171         protected override SspiNegotiationTokenAuthenticatorState CreateSspiState(byte[] incomingBlob, string incomingValueTypeUri)
172         {
173             TlsSspiNegotiation tlsNegotiation = null;
174             if (LocalAppContextSwitches.DisableUsingServicePointManagerSecurityProtocols)
175             {
176                 tlsNegotiation = new TlsSspiNegotiation(SchProtocols.TlsServer | SchProtocols.Ssl3Server,
177                 this.serverToken.Certificate, this.ClientTokenAuthenticator != null);
178             }
179             else
180             {
181                 var protocol = (SchProtocols)System.Net.ServicePointManager.SecurityProtocol & SchProtocols.ServerMask;
182                 tlsNegotiation = new TlsSspiNegotiation(protocol, this.serverToken.Certificate, this.ClientTokenAuthenticator != null);
183             }
184             // Echo only for TrustFeb2005 and ValueType mismatch
185             if (this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrustFeb2005 &&
186                 this.NegotiationValueType.Value != incomingValueTypeUri)
187             {
188                 tlsNegotiation.IncomingValueTypeUri = incomingValueTypeUri;
189             }
190             return new SspiNegotiationTokenAuthenticatorState(tlsNegotiation);
191         }
192 
GetOutgoingBinaryNegotiation(ISspiNegotiation sspiNegotiation, byte[] outgoingBlob)193         protected override BinaryNegotiation GetOutgoingBinaryNegotiation(ISspiNegotiation sspiNegotiation, byte[] outgoingBlob)
194         {
195             TlsSspiNegotiation tlsNegotiation = sspiNegotiation as TlsSspiNegotiation;
196             // Echo only for TrustFeb2005 and ValueType mismatch
197             if (this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrustFeb2005 &&
198                 tlsNegotiation != null &&
199                 tlsNegotiation.IncomingValueTypeUri != null)
200             {
201                 return new BinaryNegotiation(tlsNegotiation.IncomingValueTypeUri, outgoingBlob);
202             }
203             else
204             {
205                 return base.GetOutgoingBinaryNegotiation(sspiNegotiation, outgoingBlob);
206             }
207         }
208 
ValidateSspiNegotiation(ISspiNegotiation sspiNegotiation)209         protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateSspiNegotiation(ISspiNegotiation sspiNegotiation)
210         {
211             TlsSspiNegotiation tlsNegotiation = (TlsSspiNegotiation)sspiNegotiation;
212             if (tlsNegotiation.IsValidContext == false)
213             {
214                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new SecurityNegotiationException(SR.GetString(SR.InvalidSspiNegotiation)));
215             }
216 
217             if (this.ClientTokenAuthenticator == null)
218             {
219                 return EmptyReadOnlyCollection<IAuthorizationPolicy>.Instance;
220             }
221 
222             X509Certificate2 clientCertificate = tlsNegotiation.RemoteCertificate;
223             if (clientCertificate == null)
224             {
225                 // isAnonymous is false. So, fail the negotiation
226                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new SecurityTokenValidationException(SR.GetString(SR.ClientCertificateNotProvided)));
227             }
228 
229             ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies;
230             if (this.ClientTokenAuthenticator != null)
231             {
232                 X509SecurityToken clientToken;
233                 WindowsIdentity preMappedIdentity;
234                 if (!this.MapCertificateToWindowsAccount || !tlsNegotiation.TryGetContextIdentity(out preMappedIdentity))
235                 {
236                     clientToken = new X509SecurityToken(clientCertificate);
237                 }
238                 else
239                 {
240                     clientToken = new X509WindowsSecurityToken(clientCertificate, preMappedIdentity, preMappedIdentity.AuthenticationType, true);
241                     preMappedIdentity.Dispose();
242                 }
243                 authorizationPolicies = this.ClientTokenAuthenticator.ValidateToken(clientToken);
244                 clientToken.Dispose();
245             }
246             else
247             {
248                 authorizationPolicies = EmptyReadOnlyCollection<IAuthorizationPolicy>.Instance;
249             }
250             return authorizationPolicies;
251         }
252     }
253 }
254