private static QUIC_ALLOWED_CIPHER_SUITE_FLAGS CipherSuitePolicyToFlags(CipherSuitesPolicy cipherSuitesPolicy)
        {
            QUIC_ALLOWED_CIPHER_SUITE_FLAGS flags = QUIC_ALLOWED_CIPHER_SUITE_FLAGS.NONE;

            foreach (TlsCipherSuite cipher in cipherSuitesPolicy.AllowedCipherSuites)
            {
                switch (cipher)
                {
                case TlsCipherSuite.TLS_AES_128_GCM_SHA256:
                    flags |= QUIC_ALLOWED_CIPHER_SUITE_FLAGS.AES_128_GCM_SHA256;
                    break;

                case TlsCipherSuite.TLS_AES_256_GCM_SHA384:
                    flags |= QUIC_ALLOWED_CIPHER_SUITE_FLAGS.AES_256_GCM_SHA384;
                    break;

                case TlsCipherSuite.TLS_CHACHA20_POLY1305_SHA256:
                    flags |= QUIC_ALLOWED_CIPHER_SUITE_FLAGS.CHACHA20_POLY1305_SHA256;
                    break;

                case TlsCipherSuite.TLS_AES_128_CCM_SHA256:     // not supported by MsQuic (yet?), but QUIC RFC allows it so we ignore it.
                default:
                    // ignore
                    break;
                }
            }

            if (flags == QUIC_ALLOWED_CIPHER_SUITE_FLAGS.NONE)
            {
                throw new ArgumentException(SR.net_quic_empty_cipher_suite, nameof(SslClientAuthenticationOptions.CipherSuitesPolicy));
            }

            return(flags);
        }
Beispiel #2
0
        public void NoSupportedCiphers_ThrowsArgumentException(TlsCipherSuite[] ciphers)
        {
            CipherSuitesPolicy policy = new CipherSuitesPolicy(ciphers);
            var listenerOptions       = new QuicListenerOptions()
            {
                ListenEndPoint       = new IPEndPoint(IPAddress.Loopback, 0),
                ApplicationProtocols = new List <SslApplicationProtocol>()
                {
                    ApplicationProtocol
                },
                ConnectionOptionsCallback = (_, _, _) =>
                {
                    var serverOptions = CreateQuicServerOptions();
                    serverOptions.ServerAuthenticationOptions.CipherSuitesPolicy = policy;
                    return(ValueTask.FromResult(serverOptions));
                }
            };

            Assert.ThrowsAsync <ArgumentException>(async() => await CreateQuicListener(listenerOptions));

            var clientOptions = CreateQuicClientOptions(new IPEndPoint(IPAddress.Loopback, 5000));

            clientOptions.ClientAuthenticationOptions.CipherSuitesPolicy = policy;
            Assert.ThrowsAsync <ArgumentException>(async() => await CreateQuicConnection(clientOptions));
        }
Beispiel #3
0
        private async Task TestConnection(CipherSuitesPolicy serverPolicy, CipherSuitesPolicy clientPolicy)
        {
            var listenerOptions = new QuicListenerOptions()
            {
                ListenEndPoint       = new IPEndPoint(IPAddress.Loopback, 0),
                ApplicationProtocols = new List <SslApplicationProtocol>()
                {
                    ApplicationProtocol
                },
                ConnectionOptionsCallback = (_, _, _) =>
                {
                    var serverOptions = CreateQuicServerOptions();
                    serverOptions.ServerAuthenticationOptions.CipherSuitesPolicy = serverPolicy;
                    return(ValueTask.FromResult(serverOptions));
                }
            };

            await using QuicListener listener = await CreateQuicListener(listenerOptions);

            var clientOptions = CreateQuicClientOptions(listener.LocalEndPoint);

            clientOptions.ClientAuthenticationOptions.CipherSuitesPolicy = clientPolicy;
            await using QuicConnection clientConnection = await CreateQuicConnection(clientOptions);

            await clientConnection.CloseAsync(0);
        }
Beispiel #4
0
        public void NoSupportedCiphers_ThrowsArgumentException(TlsCipherSuite[] ciphers)
        {
            CipherSuitesPolicy policy = new CipherSuitesPolicy(ciphers);
            var listenerOptions       = CreateQuicListenerOptions();

            listenerOptions.ServerAuthenticationOptions.CipherSuitesPolicy = policy;
            Assert.ThrowsAsync <ArgumentException>(async() => await CreateQuicListener(listenerOptions));

            var clientOptions = CreateQuicClientOptions();

            clientOptions.ClientAuthenticationOptions.CipherSuitesPolicy = policy;
            clientOptions.RemoteEndPoint = new IPEndPoint(IPAddress.Loopback, 5000);
            Assert.ThrowsAsync <ArgumentException>(async() => await CreateQuicConnection(clientOptions));
        }
        public void CipherSuitesPolicy_NothingAllowed_Fails()
        {
            CipherSuitesPolicy csp = BuildPolicy();

            var sp = new ConnectionParams();

            sp.CipherSuitesPolicy = csp;

            var cp = new ConnectionParams();

            cp.CipherSuitesPolicy = csp;

            NegotiatedParams ret = ConnectAndGetNegotiatedParams(sp, cp);

            ret.Failed();
        }
Beispiel #6
0
        private async Task TestConnection(CipherSuitesPolicy serverPolicy, CipherSuitesPolicy clientPolicy)
        {
            var listenerOptions = CreateQuicListenerOptions();

            listenerOptions.ServerAuthenticationOptions.CipherSuitesPolicy = serverPolicy;
            using QuicListener listener = await CreateQuicListener(listenerOptions);

            var clientOptions = CreateQuicClientOptions();

            clientOptions.ClientAuthenticationOptions.CipherSuitesPolicy = clientPolicy;
            clientOptions.RemoteEndPoint          = listener.ListenEndPoint;
            using QuicConnection clientConnection = await CreateQuicConnection(clientOptions);

            await clientConnection.ConnectAsync();

            await clientConnection.CloseAsync(0);
        }
        public void CipherSuitesPolicy_AllowedCipherSuitesIncludesSubsetOfInput_Success()
        {
            TlsCipherSuite[] allCipherSuites = (TlsCipherSuite[])Enum.GetValues(typeof(TlsCipherSuite));
            var r = new Random(123);

            int[] numOfCipherSuites = new int[] { 0, 1, 2, 5, 10, 15, 30 };

            foreach (int n in numOfCipherSuites)
            {
                HashSet <TlsCipherSuite> cipherSuites = PickRandomValues(allCipherSuites, n, r);
                var csp = new CipherSuitesPolicy(cipherSuites);
                Assert.NotNull(csp.AllowedCipherSuites);
                Assert.InRange(csp.AllowedCipherSuites.Count(), 0, n);

                foreach (var cs in csp.AllowedCipherSuites)
                {
                    Assert.True(cipherSuites.Contains(cs));
                }
            }
        }
        private static void AllowOneOnOneSide(IEnumerable <TlsCipherSuite> cipherSuites,
                                              Predicate <TlsCipherSuite> mustSucceed,
                                              Action <TlsCipherSuite> cipherSuitePicked = null)
        {
            foreach (TlsCipherSuite cs in cipherSuites)
            {
                CipherSuitesPolicy csp = BuildPolicy(cs);

                var paramsA = new ConnectionParams()
                {
                    CipherSuitesPolicy = csp,
                };

                var paramsB = new ConnectionParams();
                int score   = 0; // 1 for success 0 for fail. Sum should be even

                for (int i = 0; i < 2; i++)
                {
                    NegotiatedParams ret = i == 0 ?
                                           ConnectAndGetNegotiatedParams(paramsA, paramsB) :
                                           ConnectAndGetNegotiatedParams(paramsB, paramsA);

                    score += ret.HasSucceeded ? 1 : 0;
                    if (mustSucceed(cs) || ret.HasSucceeded)
                    {
                        // we do not always guarantee success but if it succeeds it
                        // must use the picked cipher suite
                        ret.Succeeded();
                        ret.CheckCipherSuite(cs);

                        if (cipherSuitePicked != null && i == 0)
                        {
                            cipherSuitePicked(cs);
                        }
                    }
                }

                // we should either get 2 successes or 2 failures
                Assert.True(score % 2 == 0);
            }
        }
Beispiel #9
0
        public HttpsConnectionMiddleware(RavenServer server, KestrelServerOptions options)
        {
            _server            = server;
            CipherSuitesPolicy = server.Configuration.Security.TlsCipherSuites != null && server.Configuration.Security.TlsCipherSuites.Length > 0
                ? new CipherSuitesPolicy(server.Configuration.Security.TlsCipherSuites)
                : null;

            options.ConfigureHttpsDefaults(o =>
            {
                o.SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12;
                o.CheckCertificateRevocation  = false;
                o.ClientCertificateMode       = ClientCertificateMode.AllowCertificate;
                o.ClientCertificateValidation = (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);
                };
                o.ServerCertificateSelector = (_, __) => _serverCertificate;

                if (CipherSuitesPolicy != null)
                {
                    o.OnAuthenticate = (_, sslServerAuthenticationOptions) => sslServerAuthenticationOptions.CipherSuitesPolicy = CipherSuitesPolicy;
                }
            });
        }
Beispiel #10
0
        public Task SupportedCipher_Success()
        {
            CipherSuitesPolicy policy = new CipherSuitesPolicy(new[] { TlsCipherSuite.TLS_AES_128_GCM_SHA256 });

            return(TestConnection(policy, policy));
        }
    public void CloneSslOptionsClonesAllProperties()
    {
        var propertyNames = typeof(SslServerAuthenticationOptions).GetProperties().Select(property => property.Name).ToList();

        CipherSuitesPolicy cipherSuitesPolicy = null;

        if (!OperatingSystem.IsWindows())
        {
            try
            {
                // The CipherSuitesPolicy ctor throws a PlatformNotSupportedException on Windows.
                cipherSuitesPolicy = new CipherSuitesPolicy(new[] { TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 });
            }
            catch (PlatformNotSupportedException)
            {
                // The CipherSuitesPolicy ctor throws a PlatformNotSupportedException on Ubuntu 16.04.
                // I don't know exactly which other distros/versions throw PNEs, but it isn't super relevant to this test,
                // so let's just swallow this exception.
            }
        }

        // Set options properties to non-default values to verify they're copied.
        var options = new SslServerAuthenticationOptions
        {
            // Defaults to true
            AllowRenegotiation = false,
            // Defaults to null
            ApplicationProtocols = new List <SslApplicationProtocol> {
                SslApplicationProtocol.Http2
            },
            // Defaults to X509RevocationMode.NoCheck
            CertificateRevocationCheckMode = X509RevocationMode.Offline,
            // Defaults to null
            CipherSuitesPolicy = cipherSuitesPolicy,
            // Defaults to false
            ClientCertificateRequired = true,
            // Defaults to SslProtocols.None
#pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete
            EnabledSslProtocols = SslProtocols.Tls13 | SslProtocols.Tls11,
#pragma warning restore SYSLIB0039
#pragma warning disable SYSLIB0040 // EncryptionPolicy.NoEncryption is obsolete
            // Defaults to EncryptionPolicy.RequireEncryption
            EncryptionPolicy = EncryptionPolicy.NoEncryption,
#pragma warning restore SYSLIB0040
            // Defaults to null
            RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true,
            // Defaults to null
            ServerCertificate = new X509Certificate2(Array.Empty <byte>()),
            // Defaults to null
            ServerCertificateContext = SslStreamCertificateContext.Create(_x509Certificate2, additionalCertificates: null, offline: true),
            // Defaults to null
            ServerCertificateSelectionCallback = (sender, serverName) => null,
            // Defaults to null
            CertificateChainPolicy = new X509ChainPolicy(),
        };

        var clonedOptions = SniOptionsSelector.CloneSslOptions(options);

        Assert.NotSame(options, clonedOptions);

        Assert.Equal(options.AllowRenegotiation, clonedOptions.AllowRenegotiation);
        Assert.True(propertyNames.Remove(nameof(options.AllowRenegotiation)));

        // Ensure the List<SslApplicationProtocol> is also cloned since it could be modified by a user callback.
        Assert.NotSame(options.ApplicationProtocols, clonedOptions.ApplicationProtocols);
        Assert.Equal(Assert.Single(options.ApplicationProtocols), Assert.Single(clonedOptions.ApplicationProtocols));
        Assert.True(propertyNames.Remove(nameof(options.ApplicationProtocols)));

        Assert.Equal(options.CertificateRevocationCheckMode, clonedOptions.CertificateRevocationCheckMode);
        Assert.True(propertyNames.Remove(nameof(options.CertificateRevocationCheckMode)));

        Assert.Same(options.CipherSuitesPolicy, clonedOptions.CipherSuitesPolicy);
        Assert.True(propertyNames.Remove(nameof(options.CipherSuitesPolicy)));

        Assert.Equal(options.ClientCertificateRequired, clonedOptions.ClientCertificateRequired);
        Assert.True(propertyNames.Remove(nameof(options.ClientCertificateRequired)));

        Assert.Equal(options.EnabledSslProtocols, clonedOptions.EnabledSslProtocols);
        Assert.True(propertyNames.Remove(nameof(options.EnabledSslProtocols)));

        Assert.Equal(options.EncryptionPolicy, clonedOptions.EncryptionPolicy);
        Assert.True(propertyNames.Remove(nameof(options.EncryptionPolicy)));

        Assert.Same(options.RemoteCertificateValidationCallback, clonedOptions.RemoteCertificateValidationCallback);
        Assert.True(propertyNames.Remove(nameof(options.RemoteCertificateValidationCallback)));

        // Technically the ServerCertificate could be reset/reimported, but I'm hoping this is uncommon. Trying to clone the certificate and/or context seems risky.
        Assert.Same(options.ServerCertificate, clonedOptions.ServerCertificate);
        Assert.True(propertyNames.Remove(nameof(options.ServerCertificate)));

        Assert.Same(options.ServerCertificateContext, clonedOptions.ServerCertificateContext);
        Assert.True(propertyNames.Remove(nameof(options.ServerCertificateContext)));

        Assert.Same(options.ServerCertificateSelectionCallback, clonedOptions.ServerCertificateSelectionCallback);
        Assert.True(propertyNames.Remove(nameof(options.ServerCertificateSelectionCallback)));

        Assert.Same(options.CertificateChainPolicy, clonedOptions.CertificateChainPolicy);
        Assert.True(propertyNames.Remove(nameof(options.CertificateChainPolicy)));

        // Ensure we've checked every property. When new properties get added, we'll have to update this test along with the CloneSslOptions implementation.
        Assert.Empty(propertyNames);
    }