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