public ServerHandshakeSession(SecurityParameters securityParameters) : base(securityParameters) { if (securityParameters.ServerCertificateSelectionCallback != null) { _certificateSelectionCallback = securityParameters.ServerCertificateSelectionCallback; } else { _certificateSelectionCallback = new ServerCertificateSelectionCallback(DefaultCertificateSelectionCallback); } _availableCertificates = new List <X509CertificateCollection>(); _availableCertificates.AddRange(securityParameters.AvailableCertificates); _availablePrivateKeys = new List <CertificatePrivateKey>(); _availablePrivateKeys.AddRange(securityParameters.AvailablePrivateKeys); if (securityParameters.ClientCertificateTypes.Count > 0) { _certificateRequest = new HandshakeCertificateRequest(_version); _certificateRequest.CertificateTypes.AddRange(securityParameters.ClientCertificateTypes); _certificateRequest.SignatureAndHashAlgorithms.AddRange(_pluginManager.GetSupportedSignatureAndHashAlgorithms()); _certificateRequest.CertificateAuthorities.AddRange(securityParameters.ClientCertificateAuthorities); } }
private void BeginHandshake(IChannelHandlerContext ctx) { if (_isServer) { #if NETCOREAPP_2_0_GREATER || NETSTANDARD_2_0_GREATER // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_serverCertificateSelector is object) { X509Certificate LocalServerCertificateSelection(object sender, string name) { ctx.GetAttribute(SslStreamAttrKey).Set(_sslStream); return(_serverCertificateSelector(ctx, name)); } selector = new ServerCertificateSelectionCallback(LocalServerCertificateSelection); } var sslOptions = new SslServerAuthenticationOptions() { ServerCertificate = _serverCertificate, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = _serverSettings.NegotiateClientCertificate, EnabledSslProtocols = _serverSettings.EnabledProtocols, CertificateRevocationCheckMode = _serverSettings.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, ApplicationProtocols = _serverSettings.ApplicationProtocols // ?? new List<SslApplicationProtocol>() }; _serverSettings.OnAuthenticate?.Invoke(ctx, _serverSettings, sslOptions); var cts = new CancellationTokenSource(_serverSettings.HandshakeTimeout); _sslStream.AuthenticateAsServerAsync(sslOptions, cts.Token) .ContinueWith(
internal static MSI.MonoServerCertificateSelectionCallback PublicToMono(ServerCertificateSelectionCallback callback) { if (callback == null) { return(null); } return((s, h) => callback(s, h)); }
private static CipherSuite SelectCipherSuite(CipherSuitePluginManager pluginManager, ProtocolVersion clientVersion, ProtocolVersion minVersion, ProtocolVersion maxVersion, List<CipherSuiteId> clientSuites, List<CipherSuiteId> serverSuites, ServerCertificateSelectionCallback certificateSelectionCallback, List<X509CertificateCollection> availableCertificates) { if (clientVersion < minVersion) { throw new AlertException(AlertDescription.ProtocolVersion, "Offered client version " + clientVersion + " lower than minimum supported version " + minVersion); } // Initialize our return value as null CipherSuite selectedCipherSuite = null; // Run as long as we either select a cipher suite or run out of versions ProtocolVersion selectedVersion = clientVersion < maxVersion ? clientVersion : maxVersion; while (selectedCipherSuite == null) { foreach (CipherSuiteId id in clientSuites) { if (!serverSuites.Contains(id)) continue; // Try initializing the cipher suite based on ID selectedCipherSuite = pluginManager.GetCipherSuite(selectedVersion, (ushort)id); if (selectedCipherSuite == null) continue; // Try selecting a suitable certificate for this cipher suite int certificateIndex = certificateSelectionCallback(selectedCipherSuite, availableCertificates.ToArray()); if (certificateIndex >= 0 && certificateIndex < availableCertificates.Count) { // We finally found the valid suite, break out from the loop break; } // No certificate was found for the suite, ignore selectedCipherSuite = null; } if (selectedCipherSuite != null) break; if (selectedVersion == minVersion) break; selectedVersion = selectedVersion.PreviousProtocolVersion; } if (selectedCipherSuite == null) { throw new AlertException(AlertDescription.HandshakeFailure, "None of the cipher suites offered by client is accepted"); } return selectedCipherSuite; }
private SslAuthenticationOptions CreateAuthenticationOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions) { if (sslServerAuthenticationOptions.ServerCertificate == null && sslServerAuthenticationOptions.ServerCertificateSelectionCallback == null) { throw new ArgumentNullException(nameof(sslServerAuthenticationOptions.ServerCertificate)); } if (sslServerAuthenticationOptions.ServerCertificate != null && sslServerAuthenticationOptions.ServerCertificateSelectionCallback != null) { throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(ServerCertificateSelectionCallback))); } var authOptions = new SslAuthenticationOptions(sslServerAuthenticationOptions); _userServerCertificateSelectionCallback = sslServerAuthenticationOptions.ServerCertificateSelectionCallback; authOptions.ServerCertSelectionDelegate = _userServerCertificateSelectionCallback == null ? null : new ServerCertSelectionCallback(ServerCertSelectionCallbackWrapper); authOptions.CertValidationDelegate = _certValidationDelegate; return(authOptions); }
public ServerHandshakeSession(SecurityParameters securityParameters) : base(securityParameters) { if (securityParameters.ServerCertificateSelectionCallback != null) { _certificateSelectionCallback = securityParameters.ServerCertificateSelectionCallback; } else { _certificateSelectionCallback = new ServerCertificateSelectionCallback(DefaultCertificateSelectionCallback); } _availableCertificates = new List<X509CertificateCollection>(); _availableCertificates.AddRange(securityParameters.AvailableCertificates); _availablePrivateKeys = new List<CertificatePrivateKey>(); _availablePrivateKeys.AddRange(securityParameters.AvailablePrivateKeys); if (securityParameters.ClientCertificateTypes.Count > 0) { _certificateRequest = new HandshakeCertificateRequest(_version); _certificateRequest.CertificateTypes.AddRange(securityParameters.ClientCertificateTypes); _certificateRequest.SignatureAndHashAlgorithms.AddRange(_pluginManager.GetSupportedSignatureAndHashAlgorithms()); _certificateRequest.CertificateAuthorities.AddRange(securityParameters.ClientCertificateAuthorities); } }
private Task DoOptionsBasedHandshakeAsync(ConnectionContext context, SslStream sslStream, Core.Internal.TlsConnectionFeature feature, CancellationToken cancellationToken) { // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_serverCertificateSelector != null) { selector = (sender, name) => { feature.HostName = name; context.Features.Set(sslStream); var cert = _serverCertificateSelector(context, name); if (cert != null) { EnsureCertificateIsAllowedForServerAuth(cert); } return(cert); }; } var sslOptions = new SslServerAuthenticationOptions { ServerCertificate = _serverCertificate, ServerCertificateContext = _serverCertificateContext, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = _options.ClientCertificateMode != ClientCertificateMode.NoCertificate, EnabledSslProtocols = _options.SslProtocols, CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, }; ConfigureAlpn(sslOptions, _options.HttpProtocols); _options.OnAuthenticate?.Invoke(context, sslOptions); KestrelEventSource.Log.TlsHandshakeStart(context, sslOptions); return(sslStream.AuthenticateAsServerAsync(sslOptions, cancellationToken)); }
private async Task InnerOnConnectionAsync(ConnectionContext context) { bool certificateRequired; var feature = new Core.Internal.TlsConnectionFeature(); context.Features.Set <ITlsConnectionFeature>(feature); context.Features.Set <ITlsHandshakeFeature>(feature); var memoryPool = context.Features.Get <IMemoryPoolFeature>()?.MemoryPool; var inputPipeOptions = new StreamPipeReaderOptions ( pool: memoryPool, bufferSize: memoryPool.GetMinimumSegmentSize(), minimumReadSize: memoryPool.GetMinimumAllocSize(), leaveOpen: true ); var outputPipeOptions = new StreamPipeWriterOptions ( pool: memoryPool, leaveOpen: true ); SslDuplexPipe sslDuplexPipe = null; if (_options.ClientCertificateMode == ClientCertificateMode.NoCertificate) { sslDuplexPipe = new SslDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions); certificateRequired = false; } else { sslDuplexPipe = new SslDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions, s => new SslStream(s, leaveInnerStreamOpen: false, userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) => { if (certificate == null) { return(_options.ClientCertificateMode != ClientCertificateMode.RequireCertificate); } if (_options.ClientCertificateValidation == null) { if (sslPolicyErrors != SslPolicyErrors.None) { return(false); } } var certificate2 = ConvertToX509Certificate2(certificate); if (certificate2 == null) { return(false); } if (_options.ClientCertificateValidation != null) { if (!_options.ClientCertificateValidation(certificate2, chain, sslPolicyErrors)) { return(false); } } return(true); })); certificateRequired = true; } var sslStream = sslDuplexPipe.Stream; using (var cancellationTokeSource = new CancellationTokenSource(_options.HandshakeTimeout)) using (cancellationTokeSource.Token.UnsafeRegister(state => ((ConnectionContext)state).Abort(), context)) { try { // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_serverCertificateSelector != null) { selector = (sender, name) => { context.Features.Set(sslStream); var cert = _serverCertificateSelector(context, name); if (cert != null) { EnsureCertificateIsAllowedForServerAuth(cert); } return(cert); }; } var sslOptions = new SslServerAuthenticationOptions { ServerCertificate = _serverCertificate, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = certificateRequired, EnabledSslProtocols = _options.SslProtocols, CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, ApplicationProtocols = new List <SslApplicationProtocol>() }; // This is order sensitive if ((_options.HttpProtocols & HttpProtocols.Http2) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http2); // https://tools.ietf.org/html/rfc7540#section-9.2.1 sslOptions.AllowRenegotiation = false; } if ((_options.HttpProtocols & HttpProtocols.Http1) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http11); } _options.OnAuthenticate?.Invoke(context, sslOptions); await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None); } catch (OperationCanceledException) { _logger?.LogDebug(2, CoreStrings.AuthenticationTimedOut); await sslStream.DisposeAsync(); return; } catch (Exception ex) when(ex is IOException || ex is AuthenticationException) { _logger?.LogDebug(1, ex, CoreStrings.AuthenticationFailed); await sslStream.DisposeAsync(); return; } } feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol; context.Features.Set <ITlsApplicationProtocolFeature>(feature); feature.ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate); feature.CipherAlgorithm = sslStream.CipherAlgorithm; feature.CipherStrength = sslStream.CipherStrength; feature.HashAlgorithm = sslStream.HashAlgorithm; feature.HashStrength = sslStream.HashStrength; feature.KeyExchangeAlgorithm = sslStream.KeyExchangeAlgorithm; feature.KeyExchangeStrength = sslStream.KeyExchangeStrength; feature.Protocol = sslStream.SslProtocol; var originalTransport = context.Transport; try { context.Transport = sslDuplexPipe; // Disposing the stream will dispose the sslDuplexPipe await using (sslStream) await using (sslDuplexPipe) { await _next(context); // Dispose the inner stream (SslDuplexPipe) before disposing the SslStream // as the duplex pipe can hit an ODE as it still may be writing. } } finally { // Restore the original so that it gets closed appropriately context.Transport = originalTransport; } }
private async Task <IAdaptedConnection> InnerOnConnectionAsync(ConnectionAdapterContext context) { SslStream sslStream; bool certificateRequired; var feature = new TlsConnectionFeature(); context.Features.Set <ITlsConnectionFeature>(feature); if (_options.ClientCertificateMode == ClientCertificateMode.NoCertificate) { sslStream = new SslStream(context.ConnectionStream); certificateRequired = false; } else { sslStream = new SslStream(context.ConnectionStream, leaveInnerStreamOpen: false, userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) => { if (certificate == null) { return(_options.ClientCertificateMode != ClientCertificateMode.RequireCertificate); } if (_options.ClientCertificateValidation == null) { if (sslPolicyErrors != SslPolicyErrors.None) { return(false); } } var certificate2 = ConvertToX509Certificate2(certificate); if (certificate2 == null) { return(false); } if (_options.ClientCertificateValidation != null) { if (!_options.ClientCertificateValidation(certificate2, chain, sslPolicyErrors)) { return(false); } } return(true); }); certificateRequired = true; } var timeoutFeature = context.Features.Get <IConnectionTimeoutFeature>(); timeoutFeature.SetTimeout(_options.HandshakeTimeout); try { #if NETCOREAPP2_1 // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_serverCertificateSelector != null) { selector = (sender, name) => { context.Features.Set(sslStream); var cert = _serverCertificateSelector(context.ConnectionContext, name); if (cert != null) { EnsureCertificateIsAllowedForServerAuth(cert); } return(cert); }; } var sslOptions = new SslServerAuthenticationOptions() { ServerCertificate = _serverCertificate, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = certificateRequired, EnabledSslProtocols = _options.SslProtocols, CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, ApplicationProtocols = new List <SslApplicationProtocol>() }; // This is order sensitive if ((_options.HttpProtocols & HttpProtocols.Http2) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http2); } if ((_options.HttpProtocols & HttpProtocols.Http1) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http11); } await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None); #else var serverCert = _serverCertificate; if (_serverCertificateSelector != null) { context.Features.Set(sslStream); serverCert = _serverCertificateSelector(context.ConnectionContext, null); if (serverCert != null) { EnsureCertificateIsAllowedForServerAuth(serverCert); } } await sslStream.AuthenticateAsServerAsync(serverCert, certificateRequired, _options.SslProtocols, _options.CheckCertificateRevocation); #endif } catch (OperationCanceledException) { _logger?.LogDebug(2, CoreStrings.AuthenticationTimedOut); sslStream.Dispose(); return(_closedAdaptedConnection); } catch (IOException ex) { _logger?.LogDebug(1, ex, CoreStrings.AuthenticationFailed); sslStream.Dispose(); return(_closedAdaptedConnection); } finally { timeoutFeature.CancelTimeout(); } #if NETCOREAPP2_1 feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol; context.Features.Set <ITlsApplicationProtocolFeature>(feature); #endif feature.ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate); return(new HttpsAdaptedConnection(sslStream)); }
private async Task <IAdaptedConnection> InnerOnConnectionAsync(ConnectionAdapterContext context) { SslStream sslStream; bool certificateRequired; var feature = new Core.Internal.TlsConnectionFeature(); context.Features.Set <ITlsConnectionFeature>(feature); context.Features.Set <ITlsHandshakeFeature>(feature); if (_options.ClientCertificateMode == ClientCertificateMode.NoCertificate) { sslStream = new SslStream(context.ConnectionStream); certificateRequired = false; } else { sslStream = new SslStream(context.ConnectionStream, leaveInnerStreamOpen: false, userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) => { if (certificate == null) { return(_options.ClientCertificateMode != ClientCertificateMode.RequireCertificate); } if (_options.ClientCertificateValidation == null) { if (sslPolicyErrors != SslPolicyErrors.None) { return(false); } } var certificate2 = ConvertToX509Certificate2(certificate); if (certificate2 == null) { return(false); } if (_options.ClientCertificateValidation != null) { if (!_options.ClientCertificateValidation(certificate2, chain, sslPolicyErrors)) { return(false); } } return(true); }); certificateRequired = true; } var timeoutFeature = context.Features.Get <IConnectionTimeoutFeature>(); timeoutFeature.SetTimeout(_options.HandshakeTimeout); _options.OnHandshakeStarted?.Invoke(); try { // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_serverCertificateSelector != null) { selector = (sender, name) => { context.Features.Set(sslStream); var cert = _serverCertificateSelector(context.ConnectionContext, name); if (cert != null) { EnsureCertificateIsAllowedForServerAuth(cert); } return(cert); }; } var sslOptions = new SslServerAuthenticationOptions { ServerCertificate = _serverCertificate, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = certificateRequired, EnabledSslProtocols = _options.SslProtocols, CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, ApplicationProtocols = new List <SslApplicationProtocol>() }; // This is order sensitive if ((_options.HttpProtocols & HttpProtocols.Http2) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http2); // https://tools.ietf.org/html/rfc7540#section-9.2.1 sslOptions.AllowRenegotiation = false; } if ((_options.HttpProtocols & HttpProtocols.Http1) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http11); } await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None); } catch (OperationCanceledException) { _logger?.LogDebug(2, CoreStrings.AuthenticationTimedOut); sslStream.Dispose(); return(_closedAdaptedConnection); } catch (Exception ex) when(ex is IOException || ex is AuthenticationException) { _logger?.LogDebug(1, ex, CoreStrings.AuthenticationFailed); sslStream.Dispose(); return(_closedAdaptedConnection); } finally { timeoutFeature.CancelTimeout(); } feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol; context.Features.Set <ITlsApplicationProtocolFeature>(feature); feature.ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate); feature.CipherAlgorithm = sslStream.CipherAlgorithm; feature.CipherStrength = sslStream.CipherStrength; feature.HashAlgorithm = sslStream.HashAlgorithm; feature.HashStrength = sslStream.HashStrength; feature.KeyExchangeAlgorithm = sslStream.KeyExchangeAlgorithm; feature.KeyExchangeStrength = sslStream.KeyExchangeStrength; feature.Protocol = sslStream.SslProtocol; return(new HttpsAdaptedConnection(sslStream)); }
private bool EnsureAuthenticated(IChannelHandlerContext ctx) { var oldState = State; if (!oldState.HasAny(TlsHandlerState.AuthenticationStarted)) { State = oldState | TlsHandlerState.Authenticating; if (_isServer) { #if NETCOREAPP_2_0_GREATER || NETSTANDARD_2_0_GREATER // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_serverCertificateSelector is object) { X509Certificate LocalServerCertificateSelection(object sender, string name) { ctx.GetAttribute(SslStreamAttrKey).Set(_sslStream); var cert = _serverCertificateSelector(ctx, name); if (cert is object) { EnsureCertificateIsAllowedForServerAuth(cert); } return(cert); } selector = new ServerCertificateSelectionCallback(LocalServerCertificateSelection); } var sslOptions = new SslServerAuthenticationOptions() { ServerCertificate = _serverCertificate, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = _serverSettings.NegotiateClientCertificate, EnabledSslProtocols = _serverSettings.EnabledProtocols, CertificateRevocationCheckMode = _serverSettings.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, ApplicationProtocols = _serverSettings.ApplicationProtocols // ?? new List<SslApplicationProtocol>() }; if (_hasHttp2Protocol) { // https://tools.ietf.org/html/rfc7540#section-9.2.1 sslOptions.AllowRenegotiation = false; } _sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None) .ContinueWith(s_handshakeCompletionCallback, this, TaskContinuationOptions.ExecuteSynchronously); #else var serverCert = _serverCertificate; if (_serverCertificateSelector is object) { ctx.GetAttribute(SslStreamAttrKey).Set(_sslStream); var serverCert2 = _serverCertificateSelector(ctx, null); if (serverCert2 is object) { EnsureCertificateIsAllowedForServerAuth(serverCert2); serverCert = serverCert2; } } _sslStream.AuthenticateAsServerAsync(serverCert, _serverSettings.NegotiateClientCertificate, _serverSettings.EnabledProtocols, _serverSettings.CheckCertificateRevocation) .ContinueWith(s_handshakeCompletionCallback, this, TaskContinuationOptions.ExecuteSynchronously); #endif } else { #if NETCOREAPP_2_0_GREATER || NETSTANDARD_2_0_GREATER LocalCertificateSelectionCallback selector = null; if (_userCertSelector is object) { X509Certificate LocalCertificateSelection(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) { ctx.GetAttribute(SslStreamAttrKey).Set(_sslStream); return(_userCertSelector(ctx, targetHost, localCertificates, remoteCertificate, acceptableIssuers)); } selector = new LocalCertificateSelectionCallback(LocalCertificateSelection); } var sslOptions = new SslClientAuthenticationOptions() { TargetHost = _clientSettings.TargetHost, ClientCertificates = _clientSettings.X509CertificateCollection, EnabledSslProtocols = _clientSettings.EnabledProtocols, CertificateRevocationCheckMode = _clientSettings.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, LocalCertificateSelectionCallback = selector, ApplicationProtocols = _clientSettings.ApplicationProtocols }; if (_hasHttp2Protocol) { // https://tools.ietf.org/html/rfc7540#section-9.2.1 sslOptions.AllowRenegotiation = false; } _sslStream.AuthenticateAsClientAsync(sslOptions, CancellationToken.None) .ContinueWith(s_handshakeCompletionCallback, this, TaskContinuationOptions.ExecuteSynchronously); #else _sslStream.AuthenticateAsClientAsync(_clientSettings.TargetHost, _clientSettings.X509CertificateCollection, _clientSettings.EnabledProtocols, _clientSettings.CheckCertificateRevocation) .ContinueWith(s_handshakeCompletionCallback, this, TaskContinuationOptions.ExecuteSynchronously); #endif } return(false); } return(oldState.Has(TlsHandlerState.Authenticated)); }
private static CipherSuite SelectCipherSuite(CipherSuitePluginManager pluginManager, ProtocolVersion clientVersion, ProtocolVersion minVersion, ProtocolVersion maxVersion, List <UInt16> clientSuites, List <UInt16> serverSuites, ServerCertificateSelectionCallback certificateSelectionCallback, List <X509CertificateCollection> availableCertificates) { if (clientVersion < minVersion) { throw new AlertException(AlertDescription.ProtocolVersion, "Offered client version " + clientVersion + " lower than minimum supported version " + minVersion); } // Initialize our return value as null CipherSuite selectedCipherSuite = null; // Run as long as we either select a cipher suite or run out of versions ProtocolVersion selectedVersion = clientVersion < maxVersion ? clientVersion : maxVersion; while (selectedCipherSuite == null) { foreach (UInt16 id in clientSuites) { if (!serverSuites.Contains(id)) { continue; } // Try initializing the cipher suite based on ID selectedCipherSuite = pluginManager.GetCipherSuite(selectedVersion, id); if (selectedCipherSuite == null) { continue; } // Try selecting a suitable certificate for this cipher suite int certificateIndex = certificateSelectionCallback(selectedCipherSuite, availableCertificates.ToArray()); if (certificateIndex >= 0 && certificateIndex < availableCertificates.Count) { // We finally found the valid suite, break out from the loop break; } // No certificate was found for the suite, ignore selectedCipherSuite = null; } if (selectedCipherSuite != null) { break; } if (selectedVersion == minVersion) { break; } selectedVersion = selectedVersion.PreviousProtocolVersion; } if (selectedCipherSuite == null) { throw new AlertException(AlertDescription.HandshakeFailure, "None of the cipher suites offered by client is accepted"); } return(selectedCipherSuite); }
public SslListenerBuilder WithServerCertificateSelectionCallback(ServerCertificateSelectionCallback callback) { _options.ServerCertificateSelectionCallback = callback; return(this); }
private async Task InnerOnConnectionAsync(ConnectionContext context) { bool certificateRequired; var feature = new TlsConnectionFeature(); context.Features.Set <ITlsConnectionFeature>(feature); context.Features.Set <ITlsHandshakeFeature>(feature); var memoryPool = context.Features.Get <IMemoryPoolFeature>()?.MemoryPool; var inputPipeOptions = new StreamPipeReaderOptions ( pool: memoryPool, bufferSize: memoryPool.GetMinimumSegmentSize(), minimumReadSize: memoryPool.GetMinimumAllocSize(), leaveOpen: true ); var outputPipeOptions = new StreamPipeWriterOptions ( pool: memoryPool, leaveOpen: true ); TlsDuplexPipe tlsDuplexPipe = null; if (_options.RemoteCertificateMode == RemoteCertificateMode.NoCertificate) { tlsDuplexPipe = new TlsDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions); certificateRequired = false; } else { tlsDuplexPipe = new TlsDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions, s => new SslStream( s, leaveInnerStreamOpen: false, userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) => { if (certificate == null) { return(_options.RemoteCertificateMode != RemoteCertificateMode.RequireCertificate); } if (_options.RemoteCertificateValidation == null) { if (sslPolicyErrors != SslPolicyErrors.None) { return(false); } } var certificate2 = ConvertToX509Certificate2(certificate); if (certificate2 == null) { return(false); } if (_options.RemoteCertificateValidation != null) { if (!_options.RemoteCertificateValidation(certificate2, chain, sslPolicyErrors)) { return(false); } } return(true); })); certificateRequired = true; } var sslStream = tlsDuplexPipe.Stream; using (var cancellationTokeSource = new CancellationTokenSource(_options.HandshakeTimeout)) using (cancellationTokeSource.Token.UnsafeRegisterCancellation(state => ((ConnectionContext)state).Abort(), context)) { try { // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_certificateSelector != null) { selector = (sender, name) => { context.Features.Set(sslStream); var cert = _certificateSelector(context, name); if (cert != null) { EnsureCertificateIsAllowedForServerAuth(cert); } return(cert); }; } var sslOptions = new TlsServerAuthenticationOptions { ServerCertificate = _certificate, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = certificateRequired, EnabledSslProtocols = _options.SslProtocols, CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, }; _options.OnAuthenticateAsServer?.Invoke(context, sslOptions); #if NETCOREAPP await sslStream.AuthenticateAsServerAsync(sslOptions.Value, cancellationTokeSource.Token); #else await sslStream.AuthenticateAsServerAsync( sslOptions.ServerCertificate, sslOptions.ClientCertificateRequired, sslOptions.EnabledSslProtocols, sslOptions.CertificateRevocationCheckMode == X509RevocationMode.Online); #endif } catch (OperationCanceledException ex) { _logger?.LogWarning(2, ex, "Authentication timed out"); #if NETCOREAPP await sslStream.DisposeAsync(); #else sslStream.Dispose(); #endif return; } catch (Exception ex) { _logger?.LogWarning(1, ex, "Authentication failed"); #if NETCOREAPP await sslStream.DisposeAsync(); #else sslStream.Dispose(); #endif return; } } #if NETCOREAPP feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol; #endif context.Features.Set <ITlsApplicationProtocolFeature>(feature); feature.LocalCertificate = ConvertToX509Certificate2(sslStream.LocalCertificate); feature.RemoteCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate); feature.CipherAlgorithm = sslStream.CipherAlgorithm; feature.CipherStrength = sslStream.CipherStrength; feature.HashAlgorithm = sslStream.HashAlgorithm; feature.HashStrength = sslStream.HashStrength; feature.KeyExchangeAlgorithm = sslStream.KeyExchangeAlgorithm; feature.KeyExchangeStrength = sslStream.KeyExchangeStrength; feature.Protocol = sslStream.SslProtocol; var originalTransport = context.Transport; try { context.Transport = tlsDuplexPipe; // Disposing the stream will dispose the TlsDuplexPipe #if NETCOREAPP await using (sslStream) await using (tlsDuplexPipe) #else using (sslStream) using (tlsDuplexPipe) #endif { await _next(context); // Dispose the inner stream (TlsDuplexPipe) before disposing the SslStream // as the duplex pipe can hit an ODE as it still may be writing. } } finally { // Restore the original so that it gets closed appropriately context.Transport = originalTransport; } }
private async Task InnerOnConnectionAsync(ConnectionContext context) { SslStream sslStream; bool certificateRequired; var feature = new Core.Internal.TlsConnectionFeature(); context.Features.Set <ITlsConnectionFeature>(feature); context.Features.Set <ITlsHandshakeFeature>(feature); // TODO: Handle the cases where this can be null var memoryPoolFeature = context.Features.Get <IMemoryPoolFeature>(); var inputPipeOptions = new PipeOptions ( pool: memoryPoolFeature.MemoryPool, readerScheduler: _options.Scheduler, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: _options.MaxInputBufferSize ?? 0, resumeWriterThreshold: _options.MaxInputBufferSize / 2 ?? 0, useSynchronizationContext: false, minimumSegmentSize: memoryPoolFeature.MemoryPool.GetMinimumSegmentSize() ); var outputPipeOptions = new PipeOptions ( pool: memoryPoolFeature.MemoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: _options.MaxOutputBufferSize ?? 0, resumeWriterThreshold: _options.MaxOutputBufferSize / 2 ?? 0, useSynchronizationContext: false, minimumSegmentSize: memoryPoolFeature.MemoryPool.GetMinimumSegmentSize() ); // TODO: eventually make SslDuplexStream : Stream, IDuplexPipe to avoid RawStream allocation and pipe allocations var adaptedPipeline = new AdaptedPipeline(context.Transport, new Pipe(inputPipeOptions), new Pipe(outputPipeOptions), _logger, memoryPoolFeature.MemoryPool.GetMinimumAllocSize()); var transportStream = adaptedPipeline.TransportStream; if (_options.ClientCertificateMode == ClientCertificateMode.NoCertificate) { sslStream = new SslStream(transportStream); certificateRequired = false; } else { sslStream = new SslStream(transportStream, leaveInnerStreamOpen: false, userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) => { if (certificate == null) { return(_options.ClientCertificateMode != ClientCertificateMode.RequireCertificate); } if (_options.ClientCertificateValidation == null) { if (sslPolicyErrors != SslPolicyErrors.None) { return(false); } } var certificate2 = ConvertToX509Certificate2(certificate); if (certificate2 == null) { return(false); } if (_options.ClientCertificateValidation != null) { if (!_options.ClientCertificateValidation(certificate2, chain, sslPolicyErrors)) { return(false); } } return(true); }); certificateRequired = true; } using (var cancellationTokeSource = new CancellationTokenSource(_options.HandshakeTimeout)) using (cancellationTokeSource.Token.UnsafeRegister(state => ((ConnectionContext)state).Abort(), context)) { try { // Adapt to the SslStream signature ServerCertificateSelectionCallback selector = null; if (_serverCertificateSelector != null) { selector = (sender, name) => { context.Features.Set(sslStream); var cert = _serverCertificateSelector(context, name); if (cert != null) { EnsureCertificateIsAllowedForServerAuth(cert); } return(cert); }; } var sslOptions = new SslServerAuthenticationOptions { ServerCertificate = _serverCertificate, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = certificateRequired, EnabledSslProtocols = _options.SslProtocols, CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, ApplicationProtocols = new List <SslApplicationProtocol>() }; // This is order sensitive if ((_options.HttpProtocols & HttpProtocols.Http2) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http2); // https://tools.ietf.org/html/rfc7540#section-9.2.1 sslOptions.AllowRenegotiation = false; } if ((_options.HttpProtocols & HttpProtocols.Http1) != 0) { sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http11); } _options.OnAuthenticate?.Invoke(context, sslOptions); await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None); } catch (OperationCanceledException) { _logger?.LogDebug(2, CoreStrings.AuthenticationTimedOut); sslStream.Dispose(); return; } catch (Exception ex) when(ex is IOException || ex is AuthenticationException) { _logger?.LogDebug(1, ex, CoreStrings.AuthenticationFailed); sslStream.Dispose(); return; } } feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol; context.Features.Set <ITlsApplicationProtocolFeature>(feature); feature.ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate); feature.CipherAlgorithm = sslStream.CipherAlgorithm; feature.CipherStrength = sslStream.CipherStrength; feature.HashAlgorithm = sslStream.HashAlgorithm; feature.HashStrength = sslStream.HashStrength; feature.KeyExchangeAlgorithm = sslStream.KeyExchangeAlgorithm; feature.KeyExchangeStrength = sslStream.KeyExchangeStrength; feature.Protocol = sslStream.SslProtocol; var original = context.Transport; try { context.Transport = adaptedPipeline; using (sslStream) { try { adaptedPipeline.RunAsync(sslStream); await _next(context); } finally { await adaptedPipeline.CompleteAsync(); } } } finally { // Restore the original so that it gets closed appropriately context.Transport = original; } }