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(); }
private QuicListener CreateQuicListener(QuicListenerOptions options) => new QuicListener(ImplementationProvider, options);
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[]
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);
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)); }
public QuicListener(Implementations.QuicImplementationProvider implementationProvider, QuicListenerOptions options) { throw null; }
internal override QuicListenerProvider CreateListener(QuicListenerOptions options) { return(new MockListener(options)); }
public QuicListener(QuicListenerOptions options) { throw null; }