Example #1
0
        public ClientHandshakeSession(SecurityParameters securityParameters)
            : base(securityParameters)
        {
            if (securityParameters.ServerCertificateValidationCallback != null)
            {
                _certificateValidationCallback = securityParameters.ServerCertificateValidationCallback;
            }
            else
            {
                _certificateValidationCallback = new ServerCertificateValidationCallback(DefaultCertificateValidationCallback);
            }
            if (securityParameters.ClientCertificateSelectionCallback != null)
            {
                _certificateSelectionCallback = securityParameters.ClientCertificateSelectionCallback;
            }
            else
            {
                _certificateSelectionCallback = new ClientCertificateSelectionCallback(DefaultCertificateSelectionCallback);
            }


            HandshakeClientHello clientHello = new HandshakeClientHello(_maxVersion);

            clientHello.CipherSuites.AddRange(_supportedCipherSuites);
            clientHello.CompressionMethods.AddRange(_supportedCompressions);
            clientHello.Extensions.Add(new HelloSignatureAlgorithmsExtension(_pluginManager.GetSupportedSignatureAndHashAlgorithms()));
            OutputMessage(clientHello);

            _connectionState.ClientRandom = clientHello.Random.GetBytes();
        }
        /// <summary>
        /// Call back to select client certificate used for mutual authentication
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="targetHost"></param>
        /// <param name="localCertificates"></param>
        /// <param name="remoteCertificate"></param>
        /// <param name="acceptableIssuers"></param>
        /// <returns></returns>
        internal X509Certificate SelectClientCertificate(
            object sender,
            string targetHost,
            X509CertificateCollection localCertificates,
            X509Certificate remoteCertificate,
            string[] acceptableIssuers)
        {
            X509Certificate clientCertificate = null;

            if (acceptableIssuers != null &&
                acceptableIssuers.Length > 0 &&
                localCertificates != null &&
                localCertificates.Count > 0)
            {
                // Use the first certificate that is from an acceptable issuer.
                foreach (X509Certificate certificate in localCertificates)
                {
                    string issuer = certificate.Issuer;
                    if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                    {
                        clientCertificate = certificate;
                    }
                }
            }

            if (localCertificates != null &&
                localCertificates.Count > 0)
            {
                clientCertificate = localCertificates[0];
            }

            //If user call back is registered
            if (ClientCertificateSelectionCallback != null)
            {
                var args = new CertificateSelectionEventArgs
                {
                    TargetHost        = targetHost,
                    LocalCertificates = localCertificates,
                    RemoteCertificate = remoteCertificate,
                    AcceptableIssuers = acceptableIssuers,
                    ClientCertificate = clientCertificate
                };


                Delegate[] invocationList = ClientCertificateSelectionCallback.GetInvocationList();
                Task[]     handlerTasks   = new Task[invocationList.Length];

                for (int i = 0; i < invocationList.Length; i++)
                {
                    handlerTasks[i] = ((Func <object, CertificateSelectionEventArgs, Task>)invocationList[i])(null, args);
                }

                Task.WhenAll(handlerTasks).Wait();

                return(args.ClientCertificate);
            }

            return(clientCertificate);
        }
        /// <summary>
        /// Call back to select client certificate used for mutual authentication
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="targetHost"></param>
        /// <param name="localCertificates"></param>
        /// <param name="remoteCertificate"></param>
        /// <param name="acceptableIssuers"></param>
        /// <returns></returns>
        internal X509Certificate SelectClientCertificate(
            object sender,
            string targetHost,
            X509CertificateCollection localCertificates,
            X509Certificate remoteCertificate,
            string[] acceptableIssuers)
        {
            X509Certificate clientCertificate = null;

            if (acceptableIssuers != null &&
                acceptableIssuers.Length > 0 &&
                localCertificates != null &&
                localCertificates.Count > 0)
            {
                // Use the first certificate that is from an acceptable issuer.
                foreach (X509Certificate certificate in localCertificates)
                {
                    string issuer = certificate.Issuer;
                    if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                    {
                        clientCertificate = certificate;
                    }
                }
            }

            if (localCertificates != null &&
                localCertificates.Count > 0)
            {
                clientCertificate = localCertificates[0];
            }

            //If user call back is registered
            if (ClientCertificateSelectionCallback != null)
            {
                var args = new CertificateSelectionEventArgs
                {
                    TargetHost        = targetHost,
                    LocalCertificates = localCertificates,
                    RemoteCertificate = remoteCertificate,
                    AcceptableIssuers = acceptableIssuers,
                    ClientCertificate = clientCertificate
                };

                //why is the sender null?
                ClientCertificateSelectionCallback.InvokeParallel(this, args);
                return(args.ClientCertificate);
            }

            return(clientCertificate);
        }
        /// <summary>
        ///     Call back to select client certificate used for mutual authentication
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="sessionArgs">The http session.</param>
        /// <param name="targetHost">The remote hostname.</param>
        /// <param name="localCertificates">Selected local certificates by SslStream.</param>
        /// <param name="remoteCertificate">The remote certificate of server.</param>
        /// <param name="acceptableIssuers">The acceptable issues for client certificate as listed by server.</param>
        /// <returns></returns>
        internal X509Certificate?SelectClientCertificate(object sender, SessionEventArgsBase sessionArgs, string targetHost,
                                                         X509CertificateCollection localCertificates,
                                                         X509Certificate remoteCertificate, string[] acceptableIssuers)
        {
            X509Certificate?clientCertificate = null;

            //fallback to the first client certificate from proxy machine certificate store
            if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null &&
                localCertificates.Count > 0)
            {
                foreach (var certificate in localCertificates)
                {
                    string issuer = certificate.Issuer;
                    if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                    {
                        clientCertificate = certificate;
                    }
                }
            }

            //fallback to the first client certificate from proxy machine certificate store
            if (clientCertificate == null &&
                localCertificates != null && localCertificates.Count > 0)
            {
                clientCertificate = localCertificates[0];
            }

            // If user call back is registered
            if (ClientCertificateSelectionCallback != null)
            {
                var args = new CertificateSelectionEventArgs(sessionArgs, targetHost, localCertificates, remoteCertificate, acceptableIssuers)
                {
                    ClientCertificate = clientCertificate
                };


                ClientCertificateSelectionCallback.InvokeAsync(this, args, ExceptionFunc).Wait();
                return(args.ClientCertificate);
            }

            return(clientCertificate);
        }
        public ClientHandshakeSession(SecurityParameters securityParameters)
            : base(securityParameters)
        {
            if (securityParameters.ServerCertificateValidationCallback != null) {
                _certificateValidationCallback = securityParameters.ServerCertificateValidationCallback;
            } else {
                _certificateValidationCallback = new ServerCertificateValidationCallback(DefaultCertificateValidationCallback);
            }
            if (securityParameters.ClientCertificateSelectionCallback != null) {
                _certificateSelectionCallback = securityParameters.ClientCertificateSelectionCallback;
            } else {
                _certificateSelectionCallback = new ClientCertificateSelectionCallback(DefaultCertificateSelectionCallback);
            }

            HandshakeClientHello clientHello = new HandshakeClientHello(_maxVersion);
            clientHello.CipherSuites.AddRange(_supportedCipherSuites);
            clientHello.CompressionMethods.AddRange(_supportedCompressions);
            clientHello.Extensions.Add(new HelloSignatureAlgorithmsExtension(_pluginManager.GetSupportedSignatureAndHashAlgorithms()));
            OutputMessage(clientHello);

            _connectionState.ClientRandom = clientHello.Random.GetBytes();
        }
        /// <summary>
        ///     Call back to select client certificate used for mutual authentication
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="sessionArgs">The http session.</param>
        /// <param name="targetHost">The remote hostname.</param>
        /// <param name="localCertificates">Selected local certificates by SslStream.</param>
        /// <param name="remoteCertificate">The remote certificate of server.</param>
        /// <param name="acceptableIssuers">The acceptable issues for client certificate as listed by server.</param>
        /// <returns></returns>
        internal X509Certificate?SelectClientCertificate(RequestStateBase state, object sender, string targetHost,
                                                         X509CertificateCollection localCertificates,
                                                         X509Certificate remoteCertificate, string[] acceptableIssuers)
        {
            X509Certificate?clientCertificate = null;

            if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null &&
                localCertificates.Count > 0)
            {
                foreach (var certificate in localCertificates)
                {
                    string issuer = certificate.Issuer;
                    if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                    {
                        clientCertificate = certificate;
                    }
                }
            }

            if (localCertificates != null && localCertificates.Count > 0)
            {
                clientCertificate = localCertificates[0];
            }

            // If user call back is registered
            if (ClientCertificateSelectionCallback != null)
            {
                var args = new CertificateSelectionEventArgs(state)
                {
                    ClientCertificate = clientCertificate
                };

                // why is the sender null?
                ClientCertificateSelectionCallback.InvokeAsync(this, args, ExceptionFunc).Wait();
                return(args.ClientCertificate);
            }

            return(clientCertificate);
        }
 /// <summary>
 /// Invocator for ClientCertifcateSelectionCallback event.
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 protected virtual void OnClientCertificateSelectionCallback(object sender, CertificateSelectionEventArgs e)
 {
     ClientCertificateSelectionCallback?.Invoke(sender, e);
 }
        private async Task InnerOnConnectionAsync(ConnectionContext context)
        {
            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);
            }
            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);
                }));
            }

            var sslStream = tlsDuplexPipe.Stream;

            using (var cancellationTokeSource = new CancellationTokenSource(_options.HandshakeTimeout))
                using (cancellationTokeSource.Token.UnsafeRegister(state => ((ConnectionContext)state).Abort(), context))
                {
                    try
                    {
                        ClientCertificateSelectionCallback selector = null;
                        if (_certificateSelector != null)
                        {
                            selector = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) =>
                            {
                                var cert = _certificateSelector(sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers);
                                if (cert != null)
                                {
                                    EnsureCertificateIsAllowedForClientAuth(cert);
                                }

                                return(cert);
                            };
                        }

                        var sslOptions = new TlsClientAuthenticationOptions
                        {
                            ClientCertificates = _certificate == null || _certificateSelector != null ? null : new X509CertificateCollection {
                                _certificate
                            },
                            LocalCertificateSelectionCallback = selector,
                            EnabledSslProtocols = _options.SslProtocols,
                        };

                        _options.OnAuthenticateAsClient?.Invoke(context, sslOptions);

                        await sslStream.AuthenticateAsClientAsync(sslOptions.Value, cancellationTokeSource.Token);
                    }
                    catch (OperationCanceledException ex)
                    {
                        _logger?.LogWarning(2, ex, "Authentication timed out");
                        await sslStream.DisposeAsync();

                        return;
                    }
                    catch (Exception ex)
                    {
                        _logger?.LogWarning(1, ex, "Authentication failed");
                        await sslStream.DisposeAsync();

                        return;
                    }
                }

            feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol;

            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
                await using (sslStream)
                    await using (tlsDuplexPipe)
                    {
                        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;
            }
        }
        public ClientHandshakeSession(SecurityParameters securityParameters, ILogger logger = null)
            : base(securityParameters, logger)
        {
            if (securityParameters.ServerCertificateValidationCallback != null)
            {
                _certificateValidationCallback = securityParameters.ServerCertificateValidationCallback;
            }
            else
            {
                _certificateValidationCallback = new ServerCertificateValidationCallback(DefaultCertificateValidationCallback);
            }
            if (securityParameters.ClientCertificateSelectionCallback != null)
            {
                _certificateSelectionCallback = securityParameters.ClientCertificateSelectionCallback;
            }
            else
            {
                _certificateSelectionCallback = new ClientCertificateSelectionCallback(DefaultCertificateSelectionCallback);
            }

            var clientHello = new HandshakeClientHello(_maxVersion);
            
            // add ciphersuites
            clientHello.CipherSuites.AddRange(_supportedCipherSuites.Select(cs => (CipherSuiteId)cs));
            
            // add compressions
            clientHello.CompressionMethods.AddRange(_supportedCompressions);

            // add signature and hash algorithms
            //var sigHashAlgorithms = _pluginManager.GetSupportedSignatureAndHashAlgorithms();
            //clientHello.Extensions.Add(new HelloSignatureAlgorithmsExtension(new[] { (ushort)0x0403 }));
            clientHello.Extensions.Add(new HelloSignatureAlgorithmsExtension(new[] { new SignatureAndHashAlgorithm()
                                        {
                                            HashAlgorithm = HashAlgorithmType.Sha256,
                                            SignatureAlgorithm = SignatureAlgorithmType.Ecdsa
                                        }  }));
            //if (sigHashAlgorithms.Any(s => BitConverter.GetBytes(s)[0] == 0x03))
            //{
            //    clientHello.Extensions.Add(new HelloEccExtension(0x0000));
            //}

            // get curve name from client certificate, only add the Curve Extension that corresponds to the client certificate
            // otherwise the meter may take the curve from the first transmitted extension (ignoring the curve of the certificate)
            var cert = securityParameters.AvailableCertificates.First()[0];
            var data = Asn1Object.FromByteArray(cert.GetKeyAlgorithmParameters());
            this.logger?.Debug($"Client certificate's key algorithm parameters {data}, here an OID is expepcted");
            var oid = new DerObjectIdentifier(data.ToString());
            var curveName = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetName(oid);

            if (curveName.ToUpperInvariant() == "SECP256R1")
            {
                clientHello.Extensions.Add(new HelloEccExtension(EccNamedCurve.Secp256R1));
            }
            else if (curveName.ToUpperInvariant() == "BRAINPOOLP256R1")
            {
                clientHello.Extensions.Add(new HelloEccExtension(EccNamedCurve.BrainpoolP256R1));
            }
            else
            {
                throw new NotSupportedException($"ECC Curve {curveName} is not supported");
            }


            this.logger?.Debug($"Creating ClientHello with max version {_maxVersion}, " +
                      $"supported cipher suites {string.Join(",", _supportedCipherSuites.Select(cs => $"{cs:X2}"))}, " +
                      $"compression methods {string.Join(",", _supportedCompressions.Select(c => $"{c:X2}"))}, " +
                      $"extension {string.Join(",", clientHello.Extensions.Select(ex => ex))} ");


            this.OutputMessage(clientHello);

            _connectionState.ClientRandom = clientHello.Random.GetBytes();
        }
        public ClientHandshakeSession(SecurityParameters securityParameters)
            : base(securityParameters)
        {
            if (securityParameters.ServerCertificateValidationCallback != null)
            {
                _certificateValidationCallback = securityParameters.ServerCertificateValidationCallback;
            }
            else
            {
                _certificateValidationCallback = new ServerCertificateValidationCallback(DefaultCertificateValidationCallback);
            }
            if (securityParameters.ClientCertificateSelectionCallback != null)
            {
                _certificateSelectionCallback = securityParameters.ClientCertificateSelectionCallback;
            }
            else
            {
                _certificateSelectionCallback = new ClientCertificateSelectionCallback(DefaultCertificateSelectionCallback);
            }

            var clientHello = new HandshakeClientHello(_maxVersion);

            // add ciphersuites
            clientHello.CipherSuites.AddRange(_supportedCipherSuites.Select(cs => (CipherSuiteId)cs));

            // add compressions
            clientHello.CompressionMethods.AddRange(_supportedCompressions);

            // add supported elliptic curves
            clientHello.Extensions.Add(
                new HelloEccExtension(
                    new[]
            {
                EccNamedCurve.Secp256R1,
                EccNamedCurve.Secp384R1,
                EccNamedCurve.BrainpoolP256R1,
                EccNamedCurve.BrainpoolP384R1,
                EccNamedCurve.BrainpoolP512R1
            }));

            // add elyptic curves point format
            clientHello.Extensions.Add(
                new HelloEccPointFormatsExtension(EccPointFormats.Uncompressed));

            // add signature and hash algorithms
            clientHello.Extensions.Add(
                new HelloSignatureAlgorithmsExtension(
                    new[]
            {
                new SignatureAndHashAlgorithm()
                {
                    HashAlgorithm = HashAlgorithmType.Sha256, SignatureAlgorithm = SignatureAlgorithmType.Ecdsa
                },
                new SignatureAndHashAlgorithm()
                {
                    HashAlgorithm = HashAlgorithmType.Sha384, SignatureAlgorithm = SignatureAlgorithmType.Ecdsa
                },
                new SignatureAndHashAlgorithm()
                {
                    HashAlgorithm = HashAlgorithmType.Sha512, SignatureAlgorithm = SignatureAlgorithmType.Ecdsa
                },
            }));

            this.logger?.Debug($"Creating ClientHello with max version {_maxVersion}, " +
                               $"supported cipher suites {string.Join(",", _supportedCipherSuites?.Select(cs => $"{cs}"))}, " +
                               $"compression methods {string.Join(",", _supportedCompressions?.Select(c => $"{c}"))}, " +
                               $"extension {string.Join(",", clientHello.Extensions?.Select(ex => ex))} ");


            this.OutputMessage(clientHello);

            _connectionState.ClientRandom = clientHello.Random.GetBytes();
        }