Ejemplo n.º 1
0
        public async Task ConnectWithCertificateCallback()
        {
            X509Certificate2 c1 = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate();
            X509Certificate2 c2 = System.Net.Test.Common.Configuration.Certificates.GetClientCertificate(); // This 'wrong' certificate but should be sufficient
            X509Certificate2 expectedCertificate = c1;

            using CancellationTokenSource cts = new CancellationTokenSource();
            cts.CancelAfter(PassingTestTimeout);
            string?         receivedHostName    = null;
            X509Certificate?receivedCertificate = null;

            var quicOptions = new QuicListenerOptions();

            quicOptions.ListenEndPoint = new IPEndPoint(Socket.OSSupportsIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0);
            quicOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions();
            quicOptions.ServerAuthenticationOptions.ServerCertificate = null;
            quicOptions.ServerAuthenticationOptions.ServerCertificateSelectionCallback = (sender, hostName) =>
            {
                receivedHostName = hostName;
                if (hostName == "foobar1")
                {
                    return(c1);
                }
                else if (hostName == "foobar2")
                {
                    return(c2);
                }

                return(null);
            };

            using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, quicOptions);

            QuicClientConnectionOptions options = new QuicClientConnectionOptions()
            {
                RemoteEndPoint = listener.ListenEndPoint,
                ClientAuthenticationOptions = GetSslClientAuthenticationOptions(),
            };

            options.ClientAuthenticationOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) =>
            {
                receivedCertificate = cert;
                return(true);
            };

            options.ClientAuthenticationOptions.TargetHost = "foobar1";

            QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);

            Task <QuicConnection> serverTask = listener.AcceptConnectionAsync(cts.Token).AsTask();

            await new Task[] { clientConnection.ConnectAsync().AsTask(), serverTask }.WhenAllOrAnyFailed(PassingTestTimeoutMilliseconds);
            QuicConnection serverConnection = serverTask.Result;

            Assert.Equal(options.ClientAuthenticationOptions.TargetHost, receivedHostName);
            Assert.Equal(c1, receivedCertificate);
            clientConnection.Dispose();
            serverConnection.Dispose();

            // This should fail when callback return null.
            options.ClientAuthenticationOptions.TargetHost = "foobar3";
            clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
            Task clientTask = clientConnection.ConnectAsync(cts.Token).AsTask();

            await Assert.ThrowsAsync <QuicException>(() => clientTask);

            Assert.Equal(options.ClientAuthenticationOptions.TargetHost, receivedHostName);
            clientConnection.Dispose();

            // Do this last to make sure Listener is still functional.
            options.ClientAuthenticationOptions.TargetHost = "foobar2";
            expectedCertificate = c2;

            clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
            serverTask       = listener.AcceptConnectionAsync(cts.Token).AsTask();
            await new Task[] { clientConnection.ConnectAsync().AsTask(), serverTask }.WhenAllOrAnyFailed(PassingTestTimeoutMilliseconds);
            serverConnection = serverTask.Result;

            Assert.Equal(options.ClientAuthenticationOptions.TargetHost, receivedHostName);
            Assert.Equal(c2, receivedCertificate);
            clientConnection.Dispose();
            serverConnection.Dispose();
        }
Ejemplo n.º 2
0
 private QuicListener CreateQuicListener(QuicListenerOptions options) => new QuicListener(ImplementationProvider, options);
Ejemplo n.º 3
0
        internal async Task RunClientServer(Func <QuicConnection, Task> clientFunction, Func <QuicConnection, Task> serverFunction, int iterations = 1, int millisecondsTimeout = PassingTestTimeoutMilliseconds, QuicListenerOptions listenerOptions = null)
        {
            const long ClientCloseErrorCode = 11111;
            const long ServerCloseErrorCode = 22222;

            using QuicListener listener = CreateQuicListener(listenerOptions ?? CreateQuicListenerOptions());

            using var serverFinished = new SemaphoreSlim(0);
            using var clientFinished = new SemaphoreSlim(0);

            for (int i = 0; i < iterations; ++i)
            {
                await new[]
Ejemplo n.º 4
0
    public QuicConnectionListener(
        QuicTransportOptions options,
        ILogger log,
        EndPoint endpoint,
        TlsConnectionCallbackOptions tlsConnectionCallbackOptions)
    {
        if (!QuicListener.IsSupported)
        {
            throw new NotSupportedException("QUIC is not supported or enabled on this platform. See https://aka.ms/aspnet/kestrel/http3reqs for details.");
        }

        if (endpoint is not IPEndPoint listenEndPoint)
        {
            throw new InvalidOperationException($"QUIC doesn't support listening on the configured endpoint type. Expected {nameof(IPEndPoint)} but got {endpoint.GetType().Name}.");
        }

        if (tlsConnectionCallbackOptions.ApplicationProtocols.Count == 0)
        {
            throw new InvalidOperationException("No application protocols specified.");
        }

        _pendingConnections = new ConditionalWeakTable <QuicConnection, QuicConnectionContext>();
        _log = log;
        _tlsConnectionCallbackOptions = tlsConnectionCallbackOptions;
        _context             = new QuicTransportContext(_log, options);
        _quicListenerOptions = new QuicListenerOptions
        {
            ApplicationProtocols      = _tlsConnectionCallbackOptions.ApplicationProtocols,
            ListenEndPoint            = listenEndPoint,
            ListenBacklog             = options.Backlog,
            ConnectionOptionsCallback = async(connection, helloInfo, cancellationToken) =>
            {
                // Create the connection context inside the callback because it's passed
                // to the connection callback. The field is then read once AcceptConnectionAsync
                // finishes awaiting.
                var currentAcceptingConnection = new QuicConnectionContext(connection, _context);
                _pendingConnections.Add(connection, currentAcceptingConnection);

                var context = new TlsConnectionCallbackContext
                {
                    ClientHelloInfo = helloInfo,
                    State           = _tlsConnectionCallbackOptions.OnConnectionState,
                    Connection      = currentAcceptingConnection,
                };
                var serverAuthenticationOptions = await _tlsConnectionCallbackOptions.OnConnection(context, cancellationToken);

                // If the callback didn't set protocols then use the listener's list of protocols.
                if (serverAuthenticationOptions.ApplicationProtocols == null)
                {
                    serverAuthenticationOptions.ApplicationProtocols = _tlsConnectionCallbackOptions.ApplicationProtocols;
                }

                // If the SslServerAuthenticationOptions doesn't have a cert or protocols then the
                // QUIC connection will fail and the client receives an unhelpful message.
                // Validate the options on the server and log issues to improve debugging.
                ValidateServerAuthenticationOptions(serverAuthenticationOptions);

                var connectionOptions = new QuicServerConnectionOptions
                {
                    ServerAuthenticationOptions = serverAuthenticationOptions,
                    IdleTimeout = Timeout.InfiniteTimeSpan, // Kestrel manages connection lifetimes itself so it can send GoAway's.
                    MaxInboundBidirectionalStreams  = options.MaxBidirectionalStreamCount,
                    MaxInboundUnidirectionalStreams = options.MaxUnidirectionalStreamCount,
                    DefaultCloseErrorCode           = options.DefaultCloseErrorCode,
                    DefaultStreamErrorCode          = options.DefaultStreamErrorCode,
                };
                return(connectionOptions);
            }
        };

        // Setting to listenEndPoint to prevent the property from being null.
        // This will be initialized when CreateListenerAsync() is invoked.
        EndPoint = listenEndPoint;
    }
 internal abstract QuicListenerProvider CreateListener(QuicListenerOptions options);
Ejemplo n.º 6
0
 internal override QuicListenerProvider CreateListener(QuicListenerOptions options)
 {
     return(new MockListener(options.ListenEndPoint !, options.ServerAuthenticationOptions));
 }
 public static unsafe SafeMsQuicConfigurationHandle Create(QuicListenerOptions options)
 {
     // TODO: lots of ServerAuthenticationOptions are not yet supported by MsQuic.
     return(Create(options, QUIC_CREDENTIAL_FLAGS.NONE, options.ServerAuthenticationOptions?.ServerCertificate, options.ServerAuthenticationOptions?.ApplicationProtocols));
 }
Ejemplo n.º 8
0
 public QuicListener(Implementations.QuicImplementationProvider implementationProvider, QuicListenerOptions options)
 {
     throw null;
 }
Ejemplo n.º 9
0
 internal override QuicListenerProvider CreateListener(QuicListenerOptions options)
 {
     return(new MockListener(options));
 }
Ejemplo n.º 10
0
 public QuicListener(QuicListenerOptions options)
 {
     throw null;
 }