public IntPtr ConnectionOpen(QuicClientConnectionOptions options) { if (!_opened) { OpenSession(options.ClientAuthenticationOptions.ApplicationProtocols[0].Protocol.ToArray(), (ushort)options.MaxBidirectionalStreams, (ushort)options.MaxUnidirectionalStreams); } MsQuicStatusException.ThrowIfFailed(MsQuicApi.Api.ConnectionOpenDelegate( _nativeObjPtr, MsQuicConnection.NativeCallbackHandler, IntPtr.Zero, out IntPtr connectionPtr)); return(connectionPtr); }
public async Task UnidirectionalAndBidirectionalChangeValues() { QuicClientConnectionOptions listenerOptions = new QuicClientConnectionOptions() { MaxBidirectionalStreams = 10, MaxUnidirectionalStreams = 20, ClientAuthenticationOptions = GetSslClientAuthenticationOptions() }; (QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(listenerOptions); Assert.Equal(100, clientConnection.GetRemoteAvailableBidirectionalStreamCount()); Assert.Equal(100, clientConnection.GetRemoteAvailableUnidirectionalStreamCount()); Assert.Equal(10, serverConnection.GetRemoteAvailableBidirectionalStreamCount()); Assert.Equal(20, serverConnection.GetRemoteAvailableUnidirectionalStreamCount()); serverConnection.Dispose(); clientConnection.Dispose(); }
public IntPtr ConnectionOpen(QuicClientConnectionOptions options) { if (!_opened) { OpenSession(options.ClientAuthenticationOptions !.ApplicationProtocols !, (ushort)options.MaxBidirectionalStreams, (ushort)options.MaxUnidirectionalStreams); } QuicExceptionHelpers.ThrowIfFailed(MsQuicApi.Api.ConnectionOpenDelegate( _nativeObjPtr, MsQuicConnection.s_connectionDelegate, IntPtr.Zero, out IntPtr connectionPtr), "Could not open the connection."); return(connectionPtr); }
public async Task CertificateCallbackThrowPropagates() { using CancellationTokenSource cts = new CancellationTokenSource(PassingTestTimeout); X509Certificate?receivedCertificate = null; bool validationResult = false; var listenerOptions = new QuicListenerOptions(); listenerOptions.ListenEndPoint = new IPEndPoint(Socket.OSSupportsIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0); listenerOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, listenerOptions); QuicClientConnectionOptions clientOptions = CreateQuicClientOptions(); clientOptions.RemoteEndPoint = listener.ListenEndPoint; clientOptions.ClientAuthenticationOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => { receivedCertificate = cert; if (validationResult) { return(validationResult); } throw new ArithmeticException("foobar"); }; clientOptions.ClientAuthenticationOptions.TargetHost = "foobar1"; QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, clientOptions); await Assert.ThrowsAsync <ArithmeticException>(() => clientConnection.ConnectAsync(cts.Token).AsTask()); Assert.Equal(listenerOptions.ServerAuthenticationOptions.ServerCertificate, receivedCertificate); clientConnection.Dispose(); // Make sure the listner is still usable and there is no lingering bad conenction validationResult = true; (clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(listener); await PingPong(clientConnection, serverConnection); clientConnection.Dispose(); serverConnection.Dispose(); }
public async Task UntrustedClientCertificateFails() { var listenerOptions = new QuicListenerOptions(); listenerOptions.ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0); listenerOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); listenerOptions.ServerAuthenticationOptions.ClientCertificateRequired = true; listenerOptions.ServerAuthenticationOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => { return(false); }; using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, listenerOptions); QuicClientConnectionOptions clientOptions = CreateQuicClientOptions(); clientOptions.RemoteEndPoint = listener.ListenEndPoint; clientOptions.ClientAuthenticationOptions.ClientCertificates = new X509CertificateCollection() { ClientCertificate }; QuicConnection clientConnection = CreateQuicConnection(clientOptions); using CancellationTokenSource cts = new CancellationTokenSource(); cts.CancelAfter(500); //Some delay to see if we would get failed connection. Task <QuicConnection> serverTask = listener.AcceptConnectionAsync(cts.Token).AsTask(); ValueTask t = clientConnection.ConnectAsync(cts.Token); t.AsTask().Wait(PassingTestTimeout); await Assert.ThrowsAsync <OperationCanceledException>(() => serverTask); // The task will likely succed but we don't really care. // It may fail if the server aborts quickly. try { await t; } catch (Exception ex) { _output.WriteLine($"Ignored exception:{Environment.NewLine}{ex}"); } }
// constructor for outbound connections public MsQuicConnection(QuicClientConnectionOptions options) { if (options.RemoteEndPoint == null) { throw new ArgumentNullException(nameof(options.RemoteEndPoint)); } _remoteEndPoint = options.RemoteEndPoint; _configuration = SafeMsQuicConfigurationHandle.Create(options); _state.RemoteCertificateRequired = true; if (options.ClientAuthenticationOptions != null) { _state.RevocationMode = options.ClientAuthenticationOptions.CertificateRevocationCheckMode; _state.RemoteCertificateValidationCallback = options.ClientAuthenticationOptions.RemoteCertificateValidationCallback; _state.TargetHost = options.ClientAuthenticationOptions.TargetHost; } _state.StateGCHandle = GCHandle.Alloc(_state); try { Debug.Assert(!Monitor.IsEntered(_state)); uint status = MsQuicApi.Api.ConnectionOpenDelegate( MsQuicApi.Api.Registration, s_connectionDelegate, GCHandle.ToIntPtr(_state.StateGCHandle), out _state.Handle); QuicExceptionHelpers.ThrowIfFailed(status, "Could not open the connection."); } catch { _state.StateGCHandle.Free(); throw; } _state.TraceId = MsQuicTraceHelper.GetTraceId(_state.Handle); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(_state, $"{TraceId()} Outbound connection created"); } }
public MsQuicConnection(QuicClientConnectionOptions options) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this); } // TODO need to figure out if/how we want to expose sessions // Creating a session per connection isn't ideal. _session = new MsQuicSession(); _ptr = _session.ConnectionOpen(options); _remoteEndPoint = options.RemoteEndPoint !; SetCallbackHandler(); SetIdleTimeout(options.IdleTimeout); if (NetEventSource.IsEnabled) { NetEventSource.Exit(this); } }
public async Task ConnectWithClientCertificate() { bool clientCertificateOK = false; var listenerOptions = new QuicListenerOptions(); listenerOptions.ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0); listenerOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); listenerOptions.ServerAuthenticationOptions.ClientCertificateRequired = true; listenerOptions.ServerAuthenticationOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => { _output.WriteLine("client certificate {0}", cert); Assert.NotNull(cert); Assert.Equal(ClientCertificate.Thumbprint, ((X509Certificate2)cert).Thumbprint); clientCertificateOK = true; return(true); }; using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, listenerOptions); QuicClientConnectionOptions clientOptions = CreateQuicClientOptions(); clientOptions.ClientAuthenticationOptions.ClientCertificates = new X509CertificateCollection() { ClientCertificate }; (QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(clientOptions, listener); // Verify functionality of the connections. await PingPong(clientConnection, serverConnection); // check we completed the client certificate verification. Assert.True(clientCertificateOK); Assert.Equal(ClientCertificate, serverConnection.RemoteCertificate); await serverConnection.CloseAsync(0); clientConnection.Dispose(); serverConnection.Dispose(); }
public async Task ConnectWithCertificateChain() { (X509Certificate2 certificate, X509Certificate2Collection chain) = System.Net.Security.Tests.TestHelper.GenerateCertificates("localhost", longChain: true); X509Certificate2 rootCA = chain[chain.Count - 1]; var quicOptions = new QuicListenerOptions(); quicOptions.ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0); quicOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); quicOptions.ServerAuthenticationOptions.ServerCertificateContext = SslStreamCertificateContext.Create(certificate, chain); quicOptions.ServerAuthenticationOptions.ServerCertificate = 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) => { Assert.Equal(certificate.Subject, cert.Subject); Assert.Equal(certificate.Issuer, cert.Issuer); // We should get full chain without root CA. // With trusted root, we should be able to build chain. chain.ChainPolicy.CustomTrustStore.Add(rootCA); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; Assert.True(chain.Build(certificate)); return(true); }; using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options); ValueTask clientTask = clientConnection.ConnectAsync(); using QuicConnection serverConnection = await listener.AcceptConnectionAsync(); await clientTask; }
private async ValueTask FinishConnectAsync(QuicClientConnectionOptions options, CancellationToken cancellationToken = default) { ObjectDisposedException.ThrowIf(_disposed == 1, this); if (_connectedTcs.TryInitialize(out ValueTask valueTask, this, cancellationToken)) { _canAccept = options.MaxInboundBidirectionalStreams > 0 || options.MaxInboundUnidirectionalStreams > 0; _defaultStreamErrorCode = options.DefaultStreamErrorCode; _defaultCloseErrorCode = options.DefaultCloseErrorCode; if (!options.RemoteEndPoint.TryParse(out string?host, out IPAddress? address, out int port)) { throw new ArgumentException(SR.Format(SR.net_quic_unsupported_endpoint_type, options.RemoteEndPoint.GetType()), nameof(options)); } int addressFamily = QUIC_ADDRESS_FAMILY_UNSPEC; // RemoteEndPoint is either IPEndPoint or DnsEndPoint containing IPAddress string. // --> Set the IP directly, no name resolution needed. if (address is not null) { QuicAddr quicAddress = new IPEndPoint(address, port).ToQuicAddr(); MsQuicHelpers.SetMsQuicParameter(_handle, QUIC_PARAM_CONN_REMOTE_ADDRESS, quicAddress); } // RemoteEndPoint is DnsEndPoint containing hostname that is different from requested SNI. // --> Resolve the hostname and set the IP directly, use requested SNI in ConnectionStart. else if (host is not null && !host.Equals(options.ClientAuthenticationOptions.TargetHost, StringComparison.InvariantCultureIgnoreCase)) { IPAddress[] addresses = await Dns.GetHostAddressesAsync(host !, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); if (addresses.Length == 0) { throw new SocketException((int)SocketError.HostNotFound); } QuicAddr quicAddress = new IPEndPoint(addresses[0], port).ToQuicAddr(); MsQuicHelpers.SetMsQuicParameter(_handle, QUIC_PARAM_CONN_REMOTE_ADDRESS, quicAddress); }
public async Task UnidirectionalAndBidirectionalChangeValues() { using QuicListener listener = CreateQuicListener(); QuicClientConnectionOptions options = new QuicClientConnectionOptions() { MaxBidirectionalStreams = 10, MaxUnidirectionalStreams = 20, RemoteEndPoint = listener.ListenEndPoint, ClientAuthenticationOptions = GetSslClientAuthenticationOptions() }; using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options); ValueTask clientTask = clientConnection.ConnectAsync(); using QuicConnection serverConnection = await listener.AcceptConnectionAsync(); await clientTask; Assert.Equal(20, clientConnection.GetRemoteAvailableUnidirectionalStreamCount()); Assert.Equal(10, clientConnection.GetRemoteAvailableBidirectionalStreamCount()); Assert.Equal(100, serverConnection.GetRemoteAvailableBidirectionalStreamCount()); Assert.Equal(100, serverConnection.GetRemoteAvailableUnidirectionalStreamCount()); }
public async Task CertificateCallbackThrowPropagates() { using CancellationTokenSource cts = new CancellationTokenSource(PassingTestTimeout); X509Certificate?receivedCertificate = null; var quicOptions = new QuicListenerOptions(); quicOptions.ListenEndPoint = new IPEndPoint(Socket.OSSupportsIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0); quicOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); 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; throw new ArithmeticException("foobar"); }; options.ClientAuthenticationOptions.TargetHost = "foobar1"; QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options); Task <QuicConnection> serverTask = listener.AcceptConnectionAsync(cts.Token).AsTask(); await Assert.ThrowsAsync <ArithmeticException>(() => clientConnection.ConnectAsync(cts.Token).AsTask()); QuicConnection serverConnection = await serverTask; Assert.Equal(quicOptions.ServerAuthenticationOptions.ServerCertificate, receivedCertificate); clientConnection.Dispose(); serverConnection.Dispose(); }
public async Task Connect_PeerCertificateDisposed(bool useGetter) { await using QuicListener listener = await CreateQuicListener(); QuicClientConnectionOptions clientOptions = CreateQuicClientOptions(listener.LocalEndPoint); X509Certificate? peerCertificate = null; clientOptions.ClientAuthenticationOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { peerCertificate = certificate; return(true); }; ValueTask <QuicConnection> connectTask = CreateQuicConnection(clientOptions); ValueTask <QuicConnection> acceptTask = listener.AcceptConnectionAsync(); await new Task[] { connectTask.AsTask(), acceptTask.AsTask() }.WhenAllOrAnyFailed(PassingTestTimeoutMilliseconds); await using QuicConnection serverConnection = acceptTask.Result; QuicConnection clientConnection = connectTask.Result; Assert.NotNull(peerCertificate); if (useGetter) { Assert.Equal(peerCertificate, clientConnection.RemoteCertificate); } // Dispose connection, if we touched RemoteCertificate (useGetter), the cert should not be disposed; otherwise, it should be disposed. await clientConnection.DisposeAsync(); if (useGetter) { Assert.NotEqual(IntPtr.Zero, peerCertificate.Handle); } else { Assert.Equal(IntPtr.Zero, peerCertificate.Handle); } peerCertificate.Dispose(); }
// constructor for outbound connections public MsQuicConnection(QuicClientConnectionOptions options) { _remoteEndPoint = options.RemoteEndPoint !; _configuration = SafeMsQuicConfigurationHandle.Create(options); _isServer = false; _remoteCertificateRequired = true; if (options.ClientAuthenticationOptions != null) { _revocationMode = options.ClientAuthenticationOptions.CertificateRevocationCheckMode; _remoteCertificateValidationCallback = options.ClientAuthenticationOptions.RemoteCertificateValidationCallback; } _state.StateGCHandle = GCHandle.Alloc(_state); try { // this handle is ref counted by MsQuic, so safe to dispose here. using SafeMsQuicConfigurationHandle config = SafeMsQuicConfigurationHandle.Create(options); uint status = MsQuicApi.Api.ConnectionOpenDelegate( MsQuicApi.Api.Registration, s_connectionDelegate, GCHandle.ToIntPtr(_state.StateGCHandle), out _state.Handle); QuicExceptionHelpers.ThrowIfFailed(status, "Could not open the connection."); } catch { _state.StateGCHandle.Free(); throw; } _state.TraceId = MsQuicTraceHelper.GetTraceId(_state.Handle); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(_state, $"{TraceId()} Outbound connection created"); } }
// TODO: consider moving the static code from here to keep all the handle classes small and simple. public static SafeMsQuicConfigurationHandle Create(QuicClientConnectionOptions options) { X509Certificate?certificate = null; if (options.ClientAuthenticationOptions != null) { #pragma warning disable SYSLIB0040 // NoEncryption and AllowNoEncryption are obsolete if (options.ClientAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.NoEncryption) { throw new PlatformNotSupportedException(SR.Format(SR.net_quic_ssl_option, nameof(options.ClientAuthenticationOptions.EncryptionPolicy))); } #pragma warning restore SYSLIB0040 if (options.ClientAuthenticationOptions.ClientCertificates != null) { foreach (var cert in options.ClientAuthenticationOptions.ClientCertificates) { try { if (((X509Certificate2)cert).HasPrivateKey) { // Pick first certificate with private key. certificate = cert; break; } } catch { } } } } QUIC_CREDENTIAL_FLAGS flags = QUIC_CREDENTIAL_FLAGS.CLIENT; if (OperatingSystem.IsWindows()) { flags |= QUIC_CREDENTIAL_FLAGS.USE_SUPPLIED_CREDENTIALS; } return(Create(options, flags, certificate: certificate, certificateContext: null, options.ClientAuthenticationOptions?.ApplicationProtocols, options.ClientAuthenticationOptions?.CipherSuitesPolicy)); }
// TODO: consider moving the static code from here to keep all the handle classes small and simple. public static unsafe SafeMsQuicConfigurationHandle Create(QuicClientConnectionOptions options) { X509Certificate?certificate = null; if (options.ClientAuthenticationOptions?.ClientCertificates != null) { foreach (var cert in options.ClientAuthenticationOptions.ClientCertificates) { try { if (((X509Certificate2)cert).HasPrivateKey) { // Pick first certificate with private key. certificate = cert; break; } } catch { } } } return(Create(options, QUIC_CREDENTIAL_FLAGS.CLIENT, certificate: certificate, certificateContext: null, options.ClientAuthenticationOptions?.ApplicationProtocols)); }
public async Task UnidirectionalAndBidirectionalChangeValues() { using QuicListener listener = CreateQuicListener(); QuicClientConnectionOptions options = new QuicClientConnectionOptions() { MaxBidirectionalStreams = 10, MaxUnidirectionalStreams = 20, RemoteEndPoint = listener.ListenEndPoint, ClientAuthenticationOptions = GetSslClientAuthenticationOptions() }; using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options); Task <QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask(); await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds); using QuicConnection serverConnection = serverTask.Result; Assert.Equal(100, clientConnection.GetRemoteAvailableBidirectionalStreamCount()); Assert.Equal(100, clientConnection.GetRemoteAvailableUnidirectionalStreamCount()); Assert.Equal(10, serverConnection.GetRemoteAvailableBidirectionalStreamCount()); Assert.Equal(20, serverConnection.GetRemoteAvailableUnidirectionalStreamCount()); }
public async Task SetListenerTimeoutWorksWithSmallTimeout() { var quicOptions = new QuicListenerOptions(); quicOptions.IdleTimeout = TimeSpan.FromSeconds(10); quicOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); quicOptions.ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0); using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, quicOptions); listener.Start(); QuicClientConnectionOptions options = new QuicClientConnectionOptions() { RemoteEndPoint = listener.ListenEndPoint, ClientAuthenticationOptions = GetSslClientAuthenticationOptions(), }; using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options); ValueTask clientTask = clientConnection.ConnectAsync(); using QuicConnection serverConnection = await listener.AcceptConnectionAsync(); await clientTask; await Assert.ThrowsAsync<QuicOperationAbortedException>(async () => await serverConnection.AcceptStreamAsync().AsTask().WaitAsync(TimeSpan.FromSeconds(100))); }
// constructor for outbound connections public unsafe MsQuicConnection(QuicClientConnectionOptions options) { ArgumentNullException.ThrowIfNull(options.RemoteEndPoint, nameof(options.RemoteEndPoint)); _remoteEndPoint = options.RemoteEndPoint; _configuration = SafeMsQuicConfigurationHandle.Create(options); _state.RemoteCertificateRequired = true; if (options.ClientAuthenticationOptions != null) { _state.RevocationMode = options.ClientAuthenticationOptions.CertificateRevocationCheckMode; _state.RemoteCertificateValidationCallback = options.ClientAuthenticationOptions.RemoteCertificateValidationCallback; _state.TargetHost = options.ClientAuthenticationOptions.TargetHost; } _state.StateGCHandle = GCHandle.Alloc(_state); try { QUIC_HANDLE *handle; Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)"); ThrowIfFailure(MsQuicApi.Api.ApiTable->ConnectionOpen( MsQuicApi.Api.Registration.QuicHandle, &NativeCallback, (void *)GCHandle.ToIntPtr(_state.StateGCHandle), &handle), "Could not open the connection"); _state.Handle = new SafeMsQuicConnectionHandle(handle); } catch { _state.StateGCHandle.Free(); throw; } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(_state, $"{_state.Handle} Outbound connection created"); } }
/// <summary> /// Creates a new <see cref="QuicConnection"/> and connects it to the peer. /// </summary> /// <param name="options">Options for the connection.</param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param> /// <returns>An asynchronous task that completes with the connected connection.</returns> public static async ValueTask <QuicConnection> ConnectAsync(QuicClientConnectionOptions options, CancellationToken cancellationToken = default) { if (!IsSupported) { throw new PlatformNotSupportedException(SR.SystemNetQuic_PlatformNotSupported); } // Validate and fill in defaults for the options. options.Validate(nameof(options)); QuicConnection connection = new QuicConnection(); try { await connection.FinishConnectAsync(options, cancellationToken).ConfigureAwait(false); } catch { await connection.DisposeAsync().ConfigureAwait(false); throw; } return(connection); }
public async Task ConnectWithCertificateForLoopbackIP_IndicatesExpectedError(string ipString, bool expectsError) { var ipAddress = IPAddress.Parse(ipString); (X509Certificate2 certificate, _) = System.Net.Security.Tests.TestHelper.GenerateCertificates(expectsError ? "badhost" : "localhost"); var listenerOptions = new QuicListenerOptions(); listenerOptions.ListenEndPoint = new IPEndPoint(ipAddress, 0); listenerOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); listenerOptions.ServerAuthenticationOptions.ServerCertificate = certificate; QuicClientConnectionOptions clientOptions = CreateQuicClientOptions(); clientOptions.ClientAuthenticationOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => { Assert.Equal(certificate.Subject, cert.Subject); Assert.Equal(certificate.Issuer, cert.Issuer); Assert.Equal(expectsError ? SslPolicyErrors.RemoteCertificateNameMismatch : SslPolicyErrors.None, errors & SslPolicyErrors.RemoteCertificateNameMismatch); return(true); }; (QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(clientOptions, listenerOptions); }
public async Task SetListenerTimeoutWorksWithSmallTimeout() { var quicOptions = new QuicListenerOptions(); quicOptions.IdleTimeout = TimeSpan.FromSeconds(1); quicOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); quicOptions.ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0); using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, quicOptions); QuicClientConnectionOptions options = new QuicClientConnectionOptions() { RemoteEndPoint = listener.ListenEndPoint, ClientAuthenticationOptions = GetSslClientAuthenticationOptions(), }; using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options); Task <QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask(); await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds); using QuicConnection serverConnection = serverTask.Result; await Assert.ThrowsAsync <QuicOperationAbortedException>(async() => await serverConnection.AcceptStreamAsync().AsTask().WaitAsync(TimeSpan.FromSeconds(100))); }
// TODO: consider moving the static code from here to keep all the handle classes small and simple. public static SafeMsQuicConfigurationHandle Create(QuicClientConnectionOptions options) { X509Certificate?certificate = null; if (options.ClientAuthenticationOptions != null) { if (options.ClientAuthenticationOptions.CipherSuitesPolicy != null) { throw new PlatformNotSupportedException(SR.Format(SR.net_quic_ssl_option, nameof(options.ClientAuthenticationOptions.CipherSuitesPolicy))); } if (options.ClientAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.NoEncryption) { throw new PlatformNotSupportedException(SR.Format(SR.net_quic_ssl_option, nameof(options.ClientAuthenticationOptions.EncryptionPolicy))); } if (options.ClientAuthenticationOptions.ClientCertificates != null) { foreach (var cert in options.ClientAuthenticationOptions.ClientCertificates) { try { if (((X509Certificate2)cert).HasPrivateKey) { // Pick first certificate with private key. certificate = cert; break; } } catch { } } } } return(Create(options, QUIC_CREDENTIAL_FLAGS.CLIENT, certificate: certificate, certificateContext: null, options.ClientAuthenticationOptions?.ApplicationProtocols)); }
public IntPtr ConnectionOpen(QuicClientConnectionOptions options) { if (!_opened) { OpenSession(options.ClientAuthenticationOptions !.ApplicationProtocols ![0].Protocol.ToArray(),
internal override QuicConnectionProvider CreateConnection(QuicClientConnectionOptions options) { return(new MockConnection(options.RemoteEndPoint, options.ClientAuthenticationOptions, options.LocalEndPoint)); }
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 listenerOptions = new QuicListenerOptions(); listenerOptions.ListenEndPoint = new IPEndPoint(Socket.OSSupportsIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0); listenerOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions(); listenerOptions.ServerAuthenticationOptions.ServerCertificate = null; listenerOptions.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, listenerOptions); QuicClientConnectionOptions clientOptions = CreateQuicClientOptions(); clientOptions.ClientAuthenticationOptions.TargetHost = "foobar1"; clientOptions.ClientAuthenticationOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => { receivedCertificate = cert; return(true); }; (QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(clientOptions, listener); Assert.Equal(clientOptions.ClientAuthenticationOptions.TargetHost, receivedHostName); Assert.Equal(c1, receivedCertificate); clientConnection.Dispose(); serverConnection.Dispose(); // This should fail when callback return null. clientOptions.ClientAuthenticationOptions.TargetHost = "foobar3"; clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, clientOptions); Task clientTask = clientConnection.ConnectAsync(cts.Token).AsTask(); await Assert.ThrowsAsync <QuicException>(() => clientTask); Assert.Equal(clientOptions.ClientAuthenticationOptions.TargetHost, receivedHostName); clientConnection.Dispose(); // Do this last to make sure Listener is still functional. clientOptions.ClientAuthenticationOptions.TargetHost = "foobar2"; expectedCertificate = c2; (clientConnection, serverConnection) = await CreateConnectedQuicConnection(clientOptions, listener); Assert.Equal(clientOptions.ClientAuthenticationOptions.TargetHost, receivedHostName); Assert.Equal(c2, receivedCertificate); clientConnection.Dispose(); serverConnection.Dispose(); }
internal QuicConnection CreateQuicConnection(QuicClientConnectionOptions clientOptions) { return(new QuicConnection(ImplementationProvider, clientOptions)); }
// TODO: consider moving the static code from here to keep all the handle classes small and simple. public static unsafe SafeMsQuicConfigurationHandle Create(QuicClientConnectionOptions options) { // TODO: lots of ClientAuthenticationOptions are not yet supported by MsQuic. return(Create(options, QUIC_CREDENTIAL_FLAGS.CLIENT, certificate: null, options.ClientAuthenticationOptions?.ApplicationProtocols)); }
internal override QuicConnectionProvider CreateConnection(QuicClientConnectionOptions options) { return(new MsQuicConnection(options)); }
internal abstract QuicConnectionProvider CreateConnection(QuicClientConnectionOptions options);