public async Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
            {
                await Task.Yield();

                return(new AdaptedConnection(new RewritingStream(context.ConnectionStream)));
            }
        public Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
        {
            var adapted = new AdaptedConnection(new PassThroughStream(context.ConnectionStream));

            return(Task.FromResult <IAdaptedConnection>(adapted));
        }
 public Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
 {
     _rewritingStream = new RewritingStream(context.ConnectionStream);
     return(Task.FromResult <IAdaptedConnection>(new AdaptedConnection(_rewritingStream)));
 }
 public Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context) =>
 Task.Run(() => this.InnerOnConnectionAsync(context));
        async Task <IAdaptedConnection> InnerOnConnectionAsync(ConnectionAdapterContext context)
        {
            SslStream sslStream;
            bool      certificateRequired;

            IList <X509Certificate2> chainElements = new List <X509Certificate2>();

            if (this.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(this.options.ClientCertificateMode != ClientCertificateMode.RequireCertificate);
                    }

                    if (this.options.ClientCertificateValidation == null)
                    {
                        if (sslPolicyErrors != SslPolicyErrors.None)
                        {
                            return(false);
                        }
                    }
                    else if (!this.options.ClientCertificateValidation(new X509Certificate2(certificate), chain, sslPolicyErrors))
                    {
                        return(false);
                    }

                    foreach (X509ChainElement element in chain.ChainElements)
                    {
                        chainElements.Add(element.Certificate);
                    }

                    return(true);
                });

                certificateRequired = true;
            }

            try
            {
                if (AppContext.TryGetSwitch(DisableHandshakeTimeoutSwitch, out bool handshakeDisabled) && handshakeDisabled)
                {
                    await sslStream.AuthenticateAsServerAsync(
                        this.serverCertificate,
                        certificateRequired,
                        this.options.SslProtocols,
                        this.options.CheckCertificateRevocation);
                }
                else
                {
                    try
                    {
                        Task handshakeTask = sslStream.AuthenticateAsServerAsync(
                            this.serverCertificate,
                            certificateRequired,
                            this.options.SslProtocols,
                            this.options.CheckCertificateRevocation);
                        Task handshakeTimeoutTask = Task.Delay(HandshakeTimeout);

                        Task firstTask = await Task.WhenAny(handshakeTask, handshakeTimeoutTask);

                        if (firstTask == handshakeTimeoutTask)
                        {
                            Events.AuthenticationTimedOut();

                            // Observe any exception that might be raised from AuthenticateAsServerAsync after the timeout.
                            ObserveTaskException(handshakeTask);

                            // This will cause the request processing loop to exit immediately and close the underlying connection.
                            sslStream.Dispose();
                            return(ClosedAdaptedConnectionInstance);
                        }

                        // Observe potential handshake failures.
                        await handshakeTask;
                    }
                    catch (OperationCanceledException)
                    {
                        Events.AuthenticationTimedOut();
                        sslStream.Dispose();
                        return(ClosedAdaptedConnectionInstance);
                    }
                }
            }
            catch (Exception)
            {
                Events.AuthenticationFailed();
                sslStream.Dispose();
                return(ClosedAdaptedConnectionInstance);
            }

            Events.AuthenticationSuccess();

            // Always set the feature even though the cert might be null
            X509Certificate2 cert = sslStream.RemoteCertificate != null ? new X509Certificate2(sslStream.RemoteCertificate) : null;

            context.Features.Set <ITlsConnectionFeature>(
                new TlsConnectionFeature
            {
                ClientCertificate = cert
            });

            context.Features.Set <ITlsConnectionFeatureExtended>(
                new TlsConnectionFeatureExtended
            {
                ChainElements = chainElements
            });

            return(new HttpsAdaptedConnection(sslStream));
        }
            public async Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
            {
                await _waitingTcs.Task;

                return(new AdaptedConnection(context.ConnectionStream));
            }
 public Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
 {
     throw new Exception();
 }
 public Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
 {
     // Don't trust SslStream not to block.
     return(Task.Run(() => InnerOnConnectionAsync(context)));
 }
        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);
                    // 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);
#elif NETSTANDARD2_0 // No ALPN support
                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);
#else
#error TFMs need to be updated
#endif
            }
            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();
            }

#if NETCOREAPP2_1
            feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol;
            context.Features.Set <ITlsApplicationProtocolFeature>(feature);
#elif NETSTANDARD2_0 // No ALPN support
#else
#error TFMs need to be updated
#endif
            feature.ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate);

            return(new HttpsAdaptedConnection(sslStream));
        }
Beispiel #10
0
        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
                var sslOptions = new SslServerAuthenticationOptions()
                {
                    ServerCertificate              = _serverCertificate,
                    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
                await sslStream.AuthenticateAsServerAsync(_serverCertificate, certificateRequired,
                                                          _options.SslProtocols, _options.CheckCertificateRevocation);
#endif
            }
            catch (OperationCanceledException)
            {
                _logger?.LogInformation(2, CoreStrings.AuthenticationTimedOut);
                sslStream.Dispose();
                return(_closedAdaptedConnection);
            }
            catch (IOException ex)
            {
                _logger?.LogInformation(1, ex, CoreStrings.AuthenticationFailed);
                sslStream.Dispose();
                return(_closedAdaptedConnection);
            }
            finally
            {
                timeoutFeature.CancelTimeout();
            }

#if NETCOREAPP2_1
            // Don't allocate in the common case, see https://github.com/dotnet/corefx/issues/25432
            if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http11)
            {
                feature.ApplicationProtocol = "http/1.1";
            }
            else if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2)
            {
                feature.ApplicationProtocol = "h2";
            }
            else
            {
                feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.ToString();
            }

            context.Features.Set <ITlsApplicationProtocolFeature>(feature);
#endif
            feature.ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate);

            return(new HttpsAdaptedConnection(sslStream));
        }
        public async Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
        {
            if (context.ConnectionStream is RawStream rs)
            {
                // here we do protocol sniffing to see if user is trying to access us via
                // http while we are expecting HTTPS.

                var input = GetInput(rs); // uses a delegate to get the private RawStream._input out
                // here we take advantage of the fact that Kestrel allow to get the data from the buffer
                // without actually consuming it
                var result = await input.ReadAsync();

                try
                {
                    if (result.Buffer.First.TryGetArray(out var bytes) && bytes.Count > 0)
                    {
                        var b = bytes.Array[bytes.Offset];
                        if (b >= 'A' && b <= 'Z')
                        {
                            // this is a good indication that we have been connected using HTTP, instead of HTTPS
                            // because the first characeter is a valid ASCII value. However, in SSL2, the first bit
                            // is always on, and in SSL 3 / TLS 1.0 - 1.2 the first byte is 22.
                            // https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
                            context.Features.Set <IHttpAuthenticationFeature>(new RavenServer.AuthenticateConnection
                            {
                                WrongProtocolMessage = "Attempted to access an HTTPS server using HTTP, did you forget to change 'http://' to 'https://' ?"
                            });
                            return(new SameConnectionStream(rs));
                        }
                    }
                }
                finally
                {
                    input.Advance(result.Buffer.Start, result.Buffer.Start);
                }
            }

            var connection = await _httpsConnectionAdapter.OnConnectionAsync(context);

            if (connection is HttpsConnectionAdapter.HttpsAdaptedConnection c)
            {
                if (c.SslProtocol != SslProtocols.Tls12)
                {
                    context.Features.Set <IHttpAuthenticationFeature>(new RavenServer.AuthenticateConnection
                    {
                        WrongProtocolMessage = "RavenDB requires clients to connect using TLS 1.2, but the client used: '" + c.SslProtocol + "'."
                    });

                    return(c);
                }
            }

            var tls                  = context.Features.Get <ITlsConnectionFeature>();
            var certificate          = tls?.ClientCertificate;
            var authenticationStatus = _server.AuthenticateConnectionCertificate(certificate);

            if (Logger.IsOperationsEnabled)
            {
                Logger.Operations($"Received TLS connection request with client certificate: {certificate?.SubjectName?.Name}. Authentication status: {authenticationStatus.Status}.");
            }

            // build the token
            context.Features.Set <IHttpAuthenticationFeature>(authenticationStatus);

            return(connection);
        }
        public Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
        {
            var adapted = new AdaptedConnection(new LoggingStream(context.ConnectionStream, new TestApplicationErrorLogger()));

            return(Task.FromResult <IAdaptedConnection>(adapted));
        }
        private async Task <IAdaptedConnection> InnerOnConnectionAsync(ConnectionAdapterContext context)
        {
            var sslStream = new SslStream(context.ConnectionStream,
                                          leaveInnerStreamOpen: false,
                                          userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) =>
            {
                if (certificate == null)
                {
                    return(true);    // we handle the error from not having certificate higher in the stack
                }

                var certificate2 = ConvertToX509Certificate2(certificate);
                if (certificate2 == null)
                {
                    return(false);    // we require to be able to convert it in all cases
                }
                // Here we are explicitly ignoring trust chain issues for client certificates
                // this is because we don't actually require trust, we just use the certificate
                // as a way to authenticate. The admin is going to tell us which specific certs
                // we can trust anyway, so we can ignore such errors.

                return(sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors ||
                       sslPolicyErrors == SslPolicyErrors.None);
            });

            var timeoutFeature = context.Features.Get <Microsoft.AspNetCore.Server.Kestrel.Core.Features.IConnectionTimeoutFeature>();

            timeoutFeature.SetTimeout(_options.HandshakeTimeout);

            try
            {
                await sslStream.AuthenticateAsServerAsync(
                    _serverCertificate,
                    clientCertificateRequired : true,
                    enabledSslProtocols : SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
                    checkCertificateRevocation : true);
            }
            catch (OperationCanceledException)
            {
                sslStream.Dispose();
                return(_closedAdaptedConnection);
            }
            catch (IOException ex)
            {
                if (_logger.IsInfoEnabled)
                {
                    _logger.Info("Failed to authenticate client", ex);
                }
                sslStream.Dispose();
                return(_closedAdaptedConnection);
            }
            finally
            {
                timeoutFeature.CancelTimeout();
            }

            // Always set the feature even though the cert might be null
            context.Features.Set <ITlsConnectionFeature>(new TlsConnectionFeature
            {
                ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate)
            });

            return(new HttpsAdaptedConnection(sslStream));
        }
        private async Task <IAdaptedConnection> InnerOnConnectionAsync(ConnectionAdapterContext context)
        {
            // We start off by handing the connection stream off to a library that can do a peek read
            // (which is really just doing buffering tricks, not an actual peek read).
            var yourClientStream = new CustomBufferedStream(context.ConnectionStream, 4096);

            // We then use the same lib to parse the "peeked" data and extract the SNI hostname.
            var clientSslHelloInfo = await SslTools.PeekClientHello(yourClientStream);

            switch (clientSslHelloInfo != null)
            {
            case true:
            {
                string sniHost = clientSslHelloInfo.Extensions?.FirstOrDefault(x => x.Name == "server_name")?.Data;

                if (string.IsNullOrEmpty(sniHost) || string.IsNullOrWhiteSpace(sniHost))
                {
                    LoggerProxy.Default.Error("Failed to extract SNI hostname.");
                    return(s_closedConnection);
                }

                try
                {
                    var sslStream = new SslStream(yourClientStream, true,
                                                  (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
                        {
                            // TODO - Handle client certificates. They should be pushed to the
                            // upstream connection eventually.
                            if (certificate != null)
                            {
                                LoggerProxy.Default.Info("CLIENT CERTIFICATE AVAILABLE!!!!!!!!!!!!!");
                            }

                            return(true);
                        }
                                                  );

                    // Spoof a cert for the extracted SNI hostname.
                    var spoofedCert = m_certStore.GetSpoofedCertificateForHost(sniHost);

                    try
                    {
                        // Try to handshake.
                        await sslStream.AuthenticateAsServerAsync(spoofedCert, false, s_allowedTlsProtocols, false);
                    }
                    catch (OperationCanceledException oe)
                    {
                        LoggerProxy.Default.Error("Failed to complete client TLS handshake because the operation was cancelled.");

                        LoggerProxy.Default.Error(oe);

                        sslStream.Dispose();
                        return(s_closedConnection);
                    }
                    catch (IOException ex)
                    {
                        LoggerProxy.Default.Error("Failed to complete client TLS handshake because of IO exception.");

                        LoggerProxy.Default.Error(ex);

                        sslStream.Dispose();
                        return(s_closedConnection);
                    }

                    // Always set the feature even though the cert might be null
                    context.Features.Set <ITlsConnectionFeature>(new TlsConnectionFeature
                        {
                            ClientCertificate = sslStream.RemoteCertificate != null ? sslStream.RemoteCertificate.ToV2Certificate() : null
                        });

                    return(new HttpsAdaptedConnection(sslStream));
                }
                catch (Exception err)
                {
                    LoggerProxy.Default.Error("Failed to complete client TLS handshake because of unknown exception.");

                    LoggerProxy.Default.Error(err);
                }

                return(s_closedConnection);
            }

            default:
            {
                return(s_closedConnection);
            }
            }
        }
 public Task <IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
 {
     return(Task.Run(() => InnerOnConnectionAsync(context)));
 }
        private async Task <IAdaptedConnection> InnerOnConnectionAsync(ConnectionAdapterContext context)
        {
            SslStream sslStream;
            bool      certificateRequired;

            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;
            }

            //TODO: removed this because this is not on Kestrel 2.0
            //var timeoutFeature = context.Features.Get<IConnectionTimeoutFeature>();
            //timeoutFeature.SetTimeout(_options.HandshakeTimeout);

            try
            {
                await sslStream.AuthenticateAsServerAsync(_fetcher.Certificate, certificateRequired,
                                                          _options.SslProtocols, _options.CheckCertificateRevocation);
            }
            catch (OperationCanceledException)
            {
                _logger?.LogInformation(2, HttpsStrings.AuthenticationTimedOut);
                sslStream.Dispose();
                return(_closedAdaptedConnection);
            }
            catch (IOException ex)
            {
                _logger?.LogInformation(1, ex, HttpsStrings.AuthenticationFailed);
                sslStream.Dispose();
                return(_closedAdaptedConnection);
            }
            finally
            {
                // TODO: restore this
                //timeoutFeature.CancelTimeout();
            }

            // Always set the feature even though the cert might be null
            context.Features.Set <ITlsConnectionFeature>(new TlsConnectionFeature
            {
                ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate)
            });

            return(new HttpsAdaptedConnection(sslStream));
        }