Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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();
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
0
        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();
        }
Exemplo n.º 5
0
        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}");
            }
        }
Exemplo n.º 6
0
        // 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);
            }
        }
Exemplo n.º 8
0
        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();
        }
Exemplo n.º 9
0
        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;
        }
Exemplo n.º 10
0
    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);
            }
Exemplo n.º 11
0
        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());
        }
Exemplo n.º 12
0
        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();
        }
Exemplo n.º 13
0
        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();
        }
Exemplo n.º 14
0
        // 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");
            }
        }
Exemplo n.º 15
0
        // 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));
        }
Exemplo n.º 16
0
        // 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));
        }
Exemplo n.º 17
0
        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());
        }
Exemplo n.º 18
0
        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)));
        }
Exemplo n.º 19
0
        // 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");
            }
        }
Exemplo n.º 20
0
    /// <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);
    }
Exemplo n.º 21
0
        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);
        }
Exemplo n.º 22
0
        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)));
        }
Exemplo n.º 23
0
        // 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));
 }
Exemplo n.º 26
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 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();
        }
Exemplo n.º 27
0
 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);