1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.ServiceModel.Channels
7 using System.Collections.ObjectModel;
8 using System.Diagnostics;
9 using System.IdentityModel.Policy;
10 using System.IdentityModel.Selectors;
11 using System.IdentityModel.Tokens;
13 using System.Net.Security;
15 using System.Runtime.Diagnostics;
16 using System.Security.Authentication;
17 using System.Security.Authentication.ExtendedProtection;
18 using System.Security.Cryptography.X509Certificates;
19 using System.ServiceModel;
20 using System.ServiceModel.Description;
21 using System.ServiceModel.Diagnostics;
22 using System.ServiceModel.Diagnostics.Application;
23 using System.ServiceModel.Security;
24 using System.ServiceModel.Security.Tokens;
26 class SslStreamSecurityUpgradeProvider : StreamSecurityUpgradeProvider, IStreamUpgradeChannelBindingProvider
28 SecurityTokenAuthenticator clientCertificateAuthenticator;
29 SecurityTokenManager clientSecurityTokenManager;
30 SecurityTokenProvider serverTokenProvider;
31 EndpointIdentity identity;
32 IdentityVerifier identityVerifier;
33 X509Certificate2 serverCertificate;
34 bool requireClientCertificate;
36 bool enableChannelBinding;
37 SslProtocols sslProtocols;
39 SslStreamSecurityUpgradeProvider(IDefaultCommunicationTimeouts timeouts, SecurityTokenManager clientSecurityTokenManager, bool requireClientCertificate, string scheme, IdentityVerifier identityVerifier, SslProtocols sslProtocols)
42 this.identityVerifier = identityVerifier;
44 this.clientSecurityTokenManager = clientSecurityTokenManager;
45 this.requireClientCertificate = requireClientCertificate;
46 this.sslProtocols = sslProtocols;
49 SslStreamSecurityUpgradeProvider(IDefaultCommunicationTimeouts timeouts, SecurityTokenProvider serverTokenProvider, bool requireClientCertificate, SecurityTokenAuthenticator clientCertificateAuthenticator, string scheme, IdentityVerifier identityVerifier, SslProtocols sslProtocols)
52 this.serverTokenProvider = serverTokenProvider;
53 this.requireClientCertificate = requireClientCertificate;
54 this.clientCertificateAuthenticator = clientCertificateAuthenticator;
55 this.identityVerifier = identityVerifier;
57 this.sslProtocols = sslProtocols;
60 public static SslStreamSecurityUpgradeProvider CreateClientProvider(
61 SslStreamSecurityBindingElement bindingElement, BindingContext context)
63 SecurityCredentialsManager credentialProvider = context.BindingParameters.Find<SecurityCredentialsManager>();
65 if (credentialProvider == null)
67 credentialProvider = ClientCredentials.CreateDefaultCredentials();
69 SecurityTokenManager tokenManager = credentialProvider.CreateSecurityTokenManager();
71 return new SslStreamSecurityUpgradeProvider(context.Binding, tokenManager, bindingElement.RequireClientCertificate, context.Binding.Scheme, bindingElement.IdentityVerifier, bindingElement.SslProtocols);
74 public static SslStreamSecurityUpgradeProvider CreateServerProvider(
75 SslStreamSecurityBindingElement bindingElement, BindingContext context)
77 SecurityCredentialsManager credentialProvider =
78 context.BindingParameters.Find<SecurityCredentialsManager>();
80 if (credentialProvider == null)
82 credentialProvider = ServiceCredentials.CreateDefaultCredentials();
85 Uri listenUri = TransportSecurityHelpers.GetListenUri(context.ListenUriBaseAddress, context.ListenUriRelativeAddress);
86 SecurityTokenManager tokenManager = credentialProvider.CreateSecurityTokenManager();
88 RecipientServiceModelSecurityTokenRequirement serverCertRequirement = new RecipientServiceModelSecurityTokenRequirement();
89 serverCertRequirement.TokenType = SecurityTokenTypes.X509Certificate;
90 serverCertRequirement.RequireCryptographicToken = true;
91 serverCertRequirement.KeyUsage = SecurityKeyUsage.Exchange;
92 serverCertRequirement.TransportScheme = context.Binding.Scheme;
93 serverCertRequirement.ListenUri = listenUri;
95 SecurityTokenProvider tokenProvider = tokenManager.CreateSecurityTokenProvider(serverCertRequirement);
96 if (tokenProvider == null)
98 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ClientCredentialsUnableToCreateLocalTokenProvider, serverCertRequirement)));
101 SecurityTokenAuthenticator certificateAuthenticator =
102 TransportSecurityHelpers.GetCertificateTokenAuthenticator(tokenManager, context.Binding.Scheme, listenUri);
104 return new SslStreamSecurityUpgradeProvider(context.Binding, tokenProvider, bindingElement.RequireClientCertificate,
105 certificateAuthenticator, context.Binding.Scheme, bindingElement.IdentityVerifier, bindingElement.SslProtocols);
108 public override EndpointIdentity Identity
112 if ((this.identity == null) && (this.serverCertificate != null))
114 this.identity = SecurityUtils.GetServiceCertificateIdentity(this.serverCertificate);
116 return this.identity;
120 public IdentityVerifier IdentityVerifier
124 return this.identityVerifier;
128 public bool RequireClientCertificate
132 return this.requireClientCertificate;
136 public X509Certificate2 ServerCertificate
140 return this.serverCertificate;
144 public SecurityTokenAuthenticator ClientCertificateAuthenticator
148 if (this.clientCertificateAuthenticator == null)
150 this.clientCertificateAuthenticator = new X509SecurityTokenAuthenticator(X509ClientCertificateAuthentication.DefaultCertificateValidator);
153 return this.clientCertificateAuthenticator;
157 public SecurityTokenManager ClientSecurityTokenManager
161 return this.clientSecurityTokenManager;
167 get { return this.scheme; }
170 public SslProtocols SslProtocols
172 get { return this.sslProtocols; }
175 public override T GetProperty<T>()
177 if (typeof(T) == typeof(IChannelBindingProvider) || typeof(T) == typeof(IStreamUpgradeChannelBindingProvider))
179 return (T)(object)this;
181 return base.GetProperty<T>();
184 ChannelBinding IStreamUpgradeChannelBindingProvider.GetChannelBinding(StreamUpgradeInitiator upgradeInitiator, ChannelBindingKind kind)
186 if (upgradeInitiator == null)
188 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("upgradeInitiator");
191 SslStreamSecurityUpgradeInitiator sslUpgradeInitiator = upgradeInitiator as SslStreamSecurityUpgradeInitiator;
193 if (sslUpgradeInitiator == null)
195 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("upgradeInitiator", SR.GetString(SR.UnsupportedUpgradeInitiator, upgradeInitiator.GetType()));
198 if (kind != ChannelBindingKind.Endpoint)
200 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("kind", SR.GetString(SR.StreamUpgradeUnsupportedChannelBindingKind, this.GetType(), kind));
203 return sslUpgradeInitiator.ChannelBinding;
206 ChannelBinding IStreamUpgradeChannelBindingProvider.GetChannelBinding(StreamUpgradeAcceptor upgradeAcceptor, ChannelBindingKind kind)
208 if (upgradeAcceptor == null)
210 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("upgradeAcceptor");
213 SslStreamSecurityUpgradeAcceptor sslupgradeAcceptor = upgradeAcceptor as SslStreamSecurityUpgradeAcceptor;
215 if (sslupgradeAcceptor == null)
217 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("upgradeAcceptor", SR.GetString(SR.UnsupportedUpgradeAcceptor, upgradeAcceptor.GetType()));
220 if (kind != ChannelBindingKind.Endpoint)
222 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("kind", SR.GetString(SR.StreamUpgradeUnsupportedChannelBindingKind, this.GetType(), kind));
225 return sslupgradeAcceptor.ChannelBinding;
228 void IChannelBindingProvider.EnableChannelBindingSupport()
230 this.enableChannelBinding = true;
234 bool IChannelBindingProvider.IsChannelBindingSupportEnabled
238 return this.enableChannelBinding;
242 public override StreamUpgradeAcceptor CreateUpgradeAcceptor()
244 ThrowIfDisposedOrNotOpen();
245 return new SslStreamSecurityUpgradeAcceptor(this);
248 public override StreamUpgradeInitiator CreateUpgradeInitiator(EndpointAddress remoteAddress, Uri via)
250 ThrowIfDisposedOrNotOpen();
251 return new SslStreamSecurityUpgradeInitiator(this, remoteAddress, via);
254 protected override void OnAbort()
256 if (this.clientCertificateAuthenticator != null)
258 SecurityUtils.AbortTokenAuthenticatorIfRequired(this.clientCertificateAuthenticator);
260 CleanupServerCertificate();
263 protected override void OnClose(TimeSpan timeout)
265 if (this.clientCertificateAuthenticator != null)
267 SecurityUtils.CloseTokenAuthenticatorIfRequired(this.clientCertificateAuthenticator, timeout);
269 CleanupServerCertificate();
272 protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
274 return SecurityUtils.BeginCloseTokenAuthenticatorIfRequired(this.clientCertificateAuthenticator, timeout, callback, state);
277 protected override void OnEndClose(IAsyncResult result)
279 SecurityUtils.EndCloseTokenAuthenticatorIfRequired(result);
280 CleanupServerCertificate();
283 void SetupServerCertificate(SecurityToken token)
285 X509SecurityToken x509Token = token as X509SecurityToken;
286 if (x509Token == null)
288 SecurityUtils.AbortTokenProviderIfRequired(this.serverTokenProvider);
289 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
290 SR.InvalidTokenProvided, this.serverTokenProvider.GetType(), typeof(X509SecurityToken))));
292 this.serverCertificate = new X509Certificate2(x509Token.Certificate);
295 void CleanupServerCertificate()
297 if (this.serverCertificate != null)
299 SecurityUtils.ResetCertificate(this.serverCertificate);
300 this.serverCertificate = null;
304 protected override void OnOpen(TimeSpan timeout)
306 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
307 SecurityUtils.OpenTokenAuthenticatorIfRequired(this.ClientCertificateAuthenticator, timeoutHelper.RemainingTime());
309 if (this.serverTokenProvider != null)
311 SecurityUtils.OpenTokenProviderIfRequired(this.serverTokenProvider, timeoutHelper.RemainingTime());
312 SecurityToken token = this.serverTokenProvider.GetToken(timeout);
313 SetupServerCertificate(token);
314 SecurityUtils.CloseTokenProviderIfRequired(this.serverTokenProvider, timeoutHelper.RemainingTime());
315 this.serverTokenProvider = null;
319 protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
321 return new OpenAsyncResult(this, timeout, callback, state);
324 protected override void OnEndOpen(IAsyncResult result)
326 OpenAsyncResult.End(result);
329 class OpenAsyncResult : AsyncResult
331 SslStreamSecurityUpgradeProvider parent;
332 TimeoutHelper timeoutHelper;
333 AsyncCallback onOpenTokenAuthenticator;
334 AsyncCallback onOpenTokenProvider;
335 AsyncCallback onGetToken;
336 AsyncCallback onCloseTokenProvider;
338 public OpenAsyncResult(SslStreamSecurityUpgradeProvider parent, TimeSpan timeout,
339 AsyncCallback callback, object state)
340 : base(callback, state)
342 this.parent = parent;
343 this.timeoutHelper = new TimeoutHelper(timeout);
347 // since we're at channel.Open and not per-message, minimize our statics overhead and leverage GC for our callbacks
348 this.onOpenTokenAuthenticator = Fx.ThunkCallback(new AsyncCallback(OnOpenTokenAuthenticator));
349 IAsyncResult result = SecurityUtils.BeginOpenTokenAuthenticatorIfRequired(parent.ClientCertificateAuthenticator,
350 timeoutHelper.RemainingTime(), onOpenTokenAuthenticator, this);
352 if (!result.CompletedSynchronously)
357 if (HandleOpenAuthenticatorComplete(result))
363 public static void End(IAsyncResult result)
365 AsyncResult.End<OpenAsyncResult>(result);
368 bool HandleOpenAuthenticatorComplete(IAsyncResult result)
370 SecurityUtils.EndOpenTokenAuthenticatorIfRequired(result);
372 if (parent.serverTokenProvider == null)
377 this.onOpenTokenProvider = Fx.ThunkCallback(new AsyncCallback(OnOpenTokenProvider));
378 IAsyncResult openTokenProviderResult = SecurityUtils.BeginOpenTokenProviderIfRequired(
379 parent.serverTokenProvider, timeoutHelper.RemainingTime(), onOpenTokenProvider, this);
381 if (!openTokenProviderResult.CompletedSynchronously)
386 return HandleOpenTokenProviderComplete(openTokenProviderResult);
389 bool HandleOpenTokenProviderComplete(IAsyncResult result)
391 SecurityUtils.EndOpenTokenProviderIfRequired(result);
392 this.onGetToken = Fx.ThunkCallback(new AsyncCallback(OnGetToken));
394 IAsyncResult getTokenResult = parent.serverTokenProvider.BeginGetToken(timeoutHelper.RemainingTime(),
397 if (!getTokenResult.CompletedSynchronously)
402 return HandleGetTokenComplete(getTokenResult);
405 bool HandleGetTokenComplete(IAsyncResult result)
407 SecurityToken token = parent.serverTokenProvider.EndGetToken(result);
408 parent.SetupServerCertificate(token);
409 this.onCloseTokenProvider = Fx.ThunkCallback(new AsyncCallback(OnCloseTokenProvider));
410 IAsyncResult closeTokenProviderResult =
411 SecurityUtils.BeginCloseTokenProviderIfRequired(parent.serverTokenProvider, timeoutHelper.RemainingTime(),
412 onCloseTokenProvider, this);
414 if (!closeTokenProviderResult.CompletedSynchronously)
419 return HandleCloseTokenProviderComplete(closeTokenProviderResult);
422 bool HandleCloseTokenProviderComplete(IAsyncResult result)
424 SecurityUtils.EndCloseTokenProviderIfRequired(result);
425 parent.serverTokenProvider = null;
429 void OnOpenTokenAuthenticator(IAsyncResult result)
431 if (result.CompletedSynchronously)
436 Exception completionException = null;
437 bool completeSelf = false;
440 completeSelf = this.HandleOpenAuthenticatorComplete(result);
442 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
451 completionException = e;
456 base.Complete(false, completionException);
460 void OnOpenTokenProvider(IAsyncResult result)
462 if (result.CompletedSynchronously)
467 Exception completionException = null;
468 bool completeSelf = false;
471 completeSelf = this.HandleOpenTokenProviderComplete(result);
473 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
482 completionException = e;
487 base.Complete(false, completionException);
491 void OnGetToken(IAsyncResult result)
493 if (result.CompletedSynchronously)
498 Exception completionException = null;
499 bool completeSelf = false;
502 completeSelf = this.HandleGetTokenComplete(result);
504 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
513 completionException = e;
518 base.Complete(false, completionException);
522 void OnCloseTokenProvider(IAsyncResult result)
524 if (result.CompletedSynchronously)
529 Exception completionException = null;
530 bool completeSelf = false;
533 completeSelf = this.HandleCloseTokenProviderComplete(result);
535 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
544 completionException = e;
549 base.Complete(false, completionException);
556 class SslStreamSecurityUpgradeAcceptor : StreamSecurityUpgradeAcceptorBase
558 SslStreamSecurityUpgradeProvider parent;
559 SecurityMessageProperty clientSecurity;
561 X509Certificate2 clientCertificate = null;
562 ChannelBinding channelBindingToken;
564 public SslStreamSecurityUpgradeAcceptor(SslStreamSecurityUpgradeProvider parent)
565 : base(FramingUpgradeString.SslOrTls)
567 this.parent = parent;
568 this.clientSecurity = new SecurityMessageProperty();
571 internal ChannelBinding ChannelBinding
575 Fx.Assert(this.IsChannelBindingSupportEnabled, "A request for the ChannelBinding is not permitted without enabling ChannelBinding first (through the IChannelBindingProvider interface)");
576 return this.channelBindingToken;
580 internal bool IsChannelBindingSupportEnabled
584 return ((IChannelBindingProvider)parent).IsChannelBindingSupportEnabled;
588 protected override Stream OnAcceptUpgrade(Stream stream, out SecurityMessageProperty remoteSecurity)
590 if (TD.SslOnAcceptUpgradeIsEnabled())
592 TD.SslOnAcceptUpgrade(this.EventTraceActivity);
595 SslStream sslStream = new SslStream(stream, false, this.ValidateRemoteCertificate);
599 sslStream.AuthenticateAsServer(this.parent.ServerCertificate, this.parent.RequireClientCertificate,
600 this.parent.SslProtocols, false);
602 catch (AuthenticationException exception)
604 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(exception.Message,
607 catch (IOException ioException)
609 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(
610 SR.GetString(SR.NegotiationFailedIO, ioException.Message), ioException));
612 if (SecurityUtils.ShouldValidateSslCipherStrength())
614 SecurityUtils.ValidateSslCipherStrength(sslStream.CipherStrength);
617 remoteSecurity = this.clientSecurity;
619 if (this.IsChannelBindingSupportEnabled)
621 this.channelBindingToken = ChannelBindingUtility.GetToken(sslStream);
627 protected override IAsyncResult OnBeginAcceptUpgrade(Stream stream, AsyncCallback callback, object state)
629 AcceptUpgradeAsyncResult result = new AcceptUpgradeAsyncResult(this, callback, state);
630 result.Begin(stream);
634 protected override Stream OnEndAcceptUpgrade(IAsyncResult result, out SecurityMessageProperty remoteSecurity)
636 return AcceptUpgradeAsyncResult.End(result, out remoteSecurity, out this.channelBindingToken);
639 // callback from schannel
640 bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain,
641 SslPolicyErrors sslPolicyErrors)
643 if (this.parent.RequireClientCertificate)
645 if (certificate == null)
647 if (DiagnosticUtility.ShouldTraceError)
649 TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.SslClientCertMissing,
650 SR.GetString(SR.TraceCodeSslClientCertMissing), this);
654 // Note: add ref to handle since the caller will reset the cert after the callback return.
655 X509Certificate2 certificate2 = new X509Certificate2(certificate);
656 this.clientCertificate = certificate2;
659 SecurityToken token = new X509SecurityToken(certificate2, false);
660 ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies = this.parent.ClientCertificateAuthenticator.ValidateToken(token);
661 this.clientSecurity = new SecurityMessageProperty();
662 this.clientSecurity.TransportToken = new SecurityTokenSpecification(token, authorizationPolicies);
663 this.clientSecurity.ServiceSecurityContext = new ServiceSecurityContext(authorizationPolicies);
665 catch (SecurityTokenException e)
667 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
674 public override SecurityMessageProperty GetRemoteSecurity()
676 if (this.clientSecurity.TransportToken != null)
678 return this.clientSecurity;
680 if (this.clientCertificate != null)
682 SecurityToken token = new X509SecurityToken(this.clientCertificate);
683 ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies = SecurityUtils.NonValidatingX509Authenticator.ValidateToken(token);
684 this.clientSecurity = new SecurityMessageProperty();
685 this.clientSecurity.TransportToken = new SecurityTokenSpecification(token, authorizationPolicies);
686 this.clientSecurity.ServiceSecurityContext = new ServiceSecurityContext(authorizationPolicies);
687 return this.clientSecurity;
689 return base.GetRemoteSecurity();
692 class AcceptUpgradeAsyncResult : StreamSecurityUpgradeAcceptorAsyncResult
694 SslStreamSecurityUpgradeAcceptor acceptor;
696 ChannelBinding channelBindingToken;
698 public AcceptUpgradeAsyncResult(SslStreamSecurityUpgradeAcceptor acceptor, AsyncCallback callback,
700 : base(callback, state)
702 this.acceptor = acceptor;
705 protected override IAsyncResult OnBegin(Stream stream, AsyncCallback callback)
707 if (TD.SslOnAcceptUpgradeIsEnabled())
709 TD.SslOnAcceptUpgrade(acceptor.EventTraceActivity);
712 this.sslStream = new SslStream(stream, false, this.acceptor.ValidateRemoteCertificate);
713 return this.sslStream.BeginAuthenticateAsServer(this.acceptor.parent.ServerCertificate,
714 this.acceptor.parent.RequireClientCertificate, this.acceptor.parent.SslProtocols, false, callback, this);
717 protected override Stream OnCompleteAuthenticateAsServer(IAsyncResult result)
719 this.sslStream.EndAuthenticateAsServer(result);
721 if (SecurityUtils.ShouldValidateSslCipherStrength())
723 SecurityUtils.ValidateSslCipherStrength(sslStream.CipherStrength);
726 if (this.acceptor.IsChannelBindingSupportEnabled)
728 this.channelBindingToken = ChannelBindingUtility.GetToken(this.sslStream);
731 return this.sslStream;
734 protected override SecurityMessageProperty ValidateCreateSecurity()
736 return this.acceptor.clientSecurity;
739 public static Stream End(IAsyncResult result, out SecurityMessageProperty remoteSecurity, out ChannelBinding channelBinding)
741 Stream stream = StreamSecurityUpgradeAcceptorAsyncResult.End(result, out remoteSecurity);
742 channelBinding = ((AcceptUpgradeAsyncResult)result).channelBindingToken;
748 class SslStreamSecurityUpgradeInitiator : StreamSecurityUpgradeInitiatorBase
750 SslStreamSecurityUpgradeProvider parent;
751 SecurityMessageProperty serverSecurity;
752 SecurityTokenProvider clientCertificateProvider;
753 X509SecurityToken clientToken;
754 SecurityTokenAuthenticator serverCertificateAuthenticator;
755 ChannelBinding channelBindingToken;
757 static LocalCertificateSelectionCallback clientCertificateSelectionCallback;
759 public SslStreamSecurityUpgradeInitiator(SslStreamSecurityUpgradeProvider parent,
760 EndpointAddress remoteAddress, Uri via)
761 : base(FramingUpgradeString.SslOrTls, remoteAddress, via)
763 this.parent = parent;
765 InitiatorServiceModelSecurityTokenRequirement serverCertRequirement = new InitiatorServiceModelSecurityTokenRequirement();
766 serverCertRequirement.TokenType = SecurityTokenTypes.X509Certificate;
767 serverCertRequirement.RequireCryptographicToken = true;
768 serverCertRequirement.KeyUsage = SecurityKeyUsage.Exchange;
769 serverCertRequirement.TargetAddress = remoteAddress;
770 serverCertRequirement.Via = via;
771 serverCertRequirement.TransportScheme = this.parent.Scheme;
772 serverCertRequirement.PreferSslCertificateAuthenticator = true;
774 SecurityTokenResolver dummy;
775 this.serverCertificateAuthenticator = (parent.ClientSecurityTokenManager.CreateSecurityTokenAuthenticator(serverCertRequirement, out dummy));
777 if (parent.RequireClientCertificate)
779 InitiatorServiceModelSecurityTokenRequirement clientCertRequirement = new InitiatorServiceModelSecurityTokenRequirement();
780 clientCertRequirement.TokenType = SecurityTokenTypes.X509Certificate;
781 clientCertRequirement.RequireCryptographicToken = true;
782 clientCertRequirement.KeyUsage = SecurityKeyUsage.Signature;
783 clientCertRequirement.TargetAddress = remoteAddress;
784 clientCertRequirement.Via = via;
785 clientCertRequirement.TransportScheme = this.parent.Scheme;
786 this.clientCertificateProvider = parent.ClientSecurityTokenManager.CreateSecurityTokenProvider(clientCertRequirement);
787 if (clientCertificateProvider == null)
789 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ClientCredentialsUnableToCreateLocalTokenProvider, clientCertRequirement)));
794 static LocalCertificateSelectionCallback ClientCertificateSelectionCallback
798 if (clientCertificateSelectionCallback == null)
800 clientCertificateSelectionCallback = new LocalCertificateSelectionCallback(SelectClientCertificate);
802 return clientCertificateSelectionCallback;
806 internal ChannelBinding ChannelBinding
810 Fx.Assert(this.IsChannelBindingSupportEnabled, "A request for the ChannelBinding is not permitted without enabling ChannelBinding first (through the IChannelBindingProvider interface)");
811 return this.channelBindingToken;
815 internal bool IsChannelBindingSupportEnabled
819 return ((IChannelBindingProvider)parent).IsChannelBindingSupportEnabled;
823 IAsyncResult BaseBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
825 return base.BeginOpen(timeout, callback, state);
828 void BaseEndOpen(IAsyncResult result)
830 base.EndOpen(result);
833 internal override IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
835 return new OpenAsyncResult(this, timeout, callback, state);
838 internal override void EndOpen(IAsyncResult result)
840 OpenAsyncResult.End(result);
843 internal override void Open(TimeSpan timeout)
845 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
846 base.Open(timeoutHelper.RemainingTime());
847 if (this.clientCertificateProvider != null)
849 SecurityUtils.OpenTokenProviderIfRequired(this.clientCertificateProvider, timeoutHelper.RemainingTime());
850 this.clientToken = (X509SecurityToken)this.clientCertificateProvider.GetToken(timeoutHelper.RemainingTime());
854 IAsyncResult BaseBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
856 return base.BeginClose(timeout, callback, state);
859 void BaseEndClose(IAsyncResult result)
861 base.EndClose(result);
864 internal override IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
866 return new CloseAsyncResult(this, timeout, callback, state);
869 internal override void EndClose(IAsyncResult result)
871 CloseAsyncResult.End(result);
874 internal override void Close(TimeSpan timeout)
876 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
877 base.Close(timeoutHelper.RemainingTime());
878 if (this.clientCertificateProvider != null)
880 SecurityUtils.CloseTokenProviderIfRequired(this.clientCertificateProvider, timeoutHelper.RemainingTime());
884 protected override IAsyncResult OnBeginInitiateUpgrade(Stream stream, AsyncCallback callback, object state)
886 if (TD.SslOnInitiateUpgradeIsEnabled())
888 TD.SslOnInitiateUpgrade();
891 InitiateUpgradeAsyncResult result = new InitiateUpgradeAsyncResult(this, callback, state);
892 result.Begin(stream);
896 protected override Stream OnEndInitiateUpgrade(IAsyncResult result,
897 out SecurityMessageProperty remoteSecurity)
899 return InitiateUpgradeAsyncResult.End(result, out remoteSecurity, out this.channelBindingToken);
902 protected override Stream OnInitiateUpgrade(Stream stream, out SecurityMessageProperty remoteSecurity)
904 if (TD.SslOnInitiateUpgradeIsEnabled())
906 TD.SslOnInitiateUpgrade();
909 X509CertificateCollection clientCertificates = null;
910 LocalCertificateSelectionCallback selectionCallback = null;
911 if (this.clientToken != null)
913 clientCertificates = new X509CertificateCollection();
914 clientCertificates.Add(clientToken.Certificate);
915 selectionCallback = ClientCertificateSelectionCallback;
918 SslStream sslStream = new SslStream(stream, false, this.ValidateRemoteCertificate, selectionCallback);
921 sslStream.AuthenticateAsClient(string.Empty, clientCertificates, this.parent.SslProtocols, false);
923 catch (SecurityTokenValidationException tokenValidationException)
925 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(tokenValidationException.Message,
926 tokenValidationException));
928 catch (AuthenticationException exception)
930 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(exception.Message,
933 catch (IOException ioException)
935 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(
936 SR.GetString(SR.NegotiationFailedIO, ioException.Message), ioException));
939 if (SecurityUtils.ShouldValidateSslCipherStrength())
941 SecurityUtils.ValidateSslCipherStrength(sslStream.CipherStrength);
944 remoteSecurity = this.serverSecurity;
946 if (this.IsChannelBindingSupportEnabled)
948 this.channelBindingToken = ChannelBindingUtility.GetToken(sslStream);
954 static X509Certificate SelectClientCertificate(object sender, string targetHost,
955 X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
957 return localCertificates[0];
960 bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain,
961 SslPolicyErrors sslPolicyErrors)
963 // Note: add ref to handle since the caller will reset the cert after the callback return.
964 X509Certificate2 certificate2 = new X509Certificate2(certificate);
965 SecurityToken token = new X509SecurityToken(certificate2, false);
966 ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies = this.serverCertificateAuthenticator.ValidateToken(token);
967 this.serverSecurity = new SecurityMessageProperty();
968 this.serverSecurity.TransportToken = new SecurityTokenSpecification(token, authorizationPolicies);
969 this.serverSecurity.ServiceSecurityContext = new ServiceSecurityContext(authorizationPolicies);
971 AuthorizationContext authzContext = this.serverSecurity.ServiceSecurityContext.AuthorizationContext;
972 this.parent.IdentityVerifier.EnsureOutgoingIdentity(this.RemoteAddress, this.Via, authzContext);
977 class InitiateUpgradeAsyncResult : StreamSecurityUpgradeInitiatorAsyncResult
979 X509CertificateCollection clientCertificates;
980 SslStreamSecurityUpgradeInitiator initiator;
981 LocalCertificateSelectionCallback selectionCallback;
983 ChannelBinding channelBindingToken;
985 public InitiateUpgradeAsyncResult(SslStreamSecurityUpgradeInitiator initiator, AsyncCallback callback,
987 : base(callback, state)
989 this.initiator = initiator;
990 if (initiator.clientToken != null)
992 this.clientCertificates = new X509CertificateCollection();
993 this.clientCertificates.Add(initiator.clientToken.Certificate);
994 this.selectionCallback = ClientCertificateSelectionCallback;
998 protected override IAsyncResult OnBeginAuthenticateAsClient(Stream stream, AsyncCallback callback)
1000 this.sslStream = new SslStream(stream, false, this.initiator.ValidateRemoteCertificate,
1001 this.selectionCallback);
1005 return this.sslStream.BeginAuthenticateAsClient(string.Empty, this.clientCertificates,
1006 this.initiator.parent.SslProtocols, false, callback, this);
1008 catch (SecurityTokenValidationException tokenValidationException)
1010 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(tokenValidationException.Message,
1011 tokenValidationException));
1015 protected override Stream OnCompleteAuthenticateAsClient(IAsyncResult result)
1019 this.sslStream.EndAuthenticateAsClient(result);
1021 catch (SecurityTokenValidationException tokenValidationException)
1023 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(tokenValidationException.Message,
1024 tokenValidationException));
1027 if (SecurityUtils.ShouldValidateSslCipherStrength())
1029 SecurityUtils.ValidateSslCipherStrength(sslStream.CipherStrength);
1032 if (this.initiator.IsChannelBindingSupportEnabled)
1034 this.channelBindingToken = ChannelBindingUtility.GetToken(this.sslStream);
1037 return this.sslStream;
1040 protected override SecurityMessageProperty ValidateCreateSecurity()
1042 return this.initiator.serverSecurity;
1045 public static Stream End(IAsyncResult result, out SecurityMessageProperty remoteSecurity, out ChannelBinding channelBinding)
1047 Stream stream = StreamSecurityUpgradeInitiatorAsyncResult.End(result, out remoteSecurity);
1048 channelBinding = ((InitiateUpgradeAsyncResult)result).channelBindingToken;
1053 class OpenAsyncResult : AsyncResult
1055 SslStreamSecurityUpgradeInitiator parent;
1056 TimeoutHelper timeoutHelper;
1057 AsyncCallback onBaseOpen;
1058 AsyncCallback onOpenTokenProvider;
1059 AsyncCallback onGetClientToken;
1061 public OpenAsyncResult(SslStreamSecurityUpgradeInitiator parent, TimeSpan timeout,
1062 AsyncCallback callback, object state)
1063 : base(callback, state)
1065 this.parent = parent;
1066 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1068 // since we're at channel.Open and not per-message, minimize our statics overhead and leverage GC for our callback
1069 this.onBaseOpen = Fx.ThunkCallback(new AsyncCallback(OnBaseOpen));
1070 if (parent.clientCertificateProvider != null)
1072 this.onOpenTokenProvider = Fx.ThunkCallback(new AsyncCallback(OnOpenTokenProvider));
1073 this.onGetClientToken = Fx.ThunkCallback(new AsyncCallback(OnGetClientToken));
1075 IAsyncResult result = parent.BaseBeginOpen(timeoutHelper.RemainingTime(), onBaseOpen, this);
1077 if (!result.CompletedSynchronously)
1082 if (HandleBaseOpenComplete(result))
1084 base.Complete(true);
1088 public static void End(IAsyncResult result)
1090 AsyncResult.End<OpenAsyncResult>(result);
1093 bool HandleBaseOpenComplete(IAsyncResult result)
1095 parent.BaseEndOpen(result);
1096 if (parent.clientCertificateProvider == null)
1101 IAsyncResult openTokenProviderResult = SecurityUtils.BeginOpenTokenProviderIfRequired(
1102 parent.clientCertificateProvider, timeoutHelper.RemainingTime(), onOpenTokenProvider, this);
1104 if (!openTokenProviderResult.CompletedSynchronously)
1109 return HandleOpenTokenProviderComplete(openTokenProviderResult);
1112 bool HandleOpenTokenProviderComplete(IAsyncResult result)
1114 SecurityUtils.EndOpenTokenProviderIfRequired(result);
1115 IAsyncResult getTokenResult = parent.clientCertificateProvider.BeginGetToken(timeoutHelper.RemainingTime(),
1116 onGetClientToken, this);
1118 if (!getTokenResult.CompletedSynchronously)
1123 return HandleGetTokenComplete(getTokenResult);
1126 bool HandleGetTokenComplete(IAsyncResult result)
1128 parent.clientToken = (X509SecurityToken)parent.clientCertificateProvider.EndGetToken(result);
1132 void OnBaseOpen(IAsyncResult result)
1134 if (result.CompletedSynchronously)
1139 Exception completionException = null;
1140 bool completeSelf = false;
1143 completeSelf = this.HandleBaseOpenComplete(result);
1145 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1153 completeSelf = true;
1154 completionException = e;
1159 base.Complete(false, completionException);
1163 void OnOpenTokenProvider(IAsyncResult result)
1165 if (result.CompletedSynchronously)
1170 Exception completionException = null;
1171 bool completeSelf = false;
1174 completeSelf = this.HandleOpenTokenProviderComplete(result);
1176 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1184 completeSelf = true;
1185 completionException = e;
1190 base.Complete(false, completionException);
1194 void OnGetClientToken(IAsyncResult result)
1196 if (result.CompletedSynchronously)
1201 Exception completionException = null;
1202 bool completeSelf = false;
1205 completeSelf = this.HandleGetTokenComplete(result);
1207 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1215 completeSelf = true;
1216 completionException = e;
1221 base.Complete(false, completionException);
1226 class CloseAsyncResult : AsyncResult
1228 SslStreamSecurityUpgradeInitiator parent;
1229 TimeoutHelper timeoutHelper;
1230 AsyncCallback onBaseClose;
1231 AsyncCallback onCloseTokenProvider;
1233 public CloseAsyncResult(SslStreamSecurityUpgradeInitiator parent, TimeSpan timeout,
1234 AsyncCallback callback, object state)
1235 : base(callback, state)
1237 this.parent = parent;
1238 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1240 // since we're at channel.Open and not per-message, minimize our statics overhead and leverage GC for our callback
1241 this.onBaseClose = Fx.ThunkCallback(new AsyncCallback(OnBaseClose));
1242 if (parent.clientCertificateProvider != null)
1244 this.onCloseTokenProvider = Fx.ThunkCallback(new AsyncCallback(OnCloseTokenProvider));
1246 IAsyncResult result = parent.BaseBeginClose(timeoutHelper.RemainingTime(), onBaseClose, this);
1248 if (!result.CompletedSynchronously)
1253 if (HandleBaseCloseComplete(result))
1255 base.Complete(true);
1259 public static void End(IAsyncResult result)
1261 AsyncResult.End<CloseAsyncResult>(result);
1264 bool HandleBaseCloseComplete(IAsyncResult result)
1266 parent.BaseEndClose(result);
1267 if (parent.clientCertificateProvider == null)
1272 IAsyncResult closeTokenProviderResult = SecurityUtils.BeginCloseTokenProviderIfRequired(
1273 parent.clientCertificateProvider, timeoutHelper.RemainingTime(), onCloseTokenProvider, this);
1275 if (!closeTokenProviderResult.CompletedSynchronously)
1280 SecurityUtils.EndCloseTokenProviderIfRequired(closeTokenProviderResult);
1284 void OnBaseClose(IAsyncResult result)
1286 if (result.CompletedSynchronously)
1291 Exception completionException = null;
1292 bool completeSelf = false;
1295 completeSelf = this.HandleBaseCloseComplete(result);
1297 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1305 completeSelf = true;
1306 completionException = e;
1311 base.Complete(false, completionException);
1315 void OnCloseTokenProvider(IAsyncResult result)
1317 if (result.CompletedSynchronously)
1322 Exception completionException = null;
1325 SecurityUtils.EndCloseTokenProviderIfRequired(result);
1327 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1335 completionException = e;
1338 base.Complete(false, completionException);