Ejemplo n.º 1
0
        private static unsafe int HandleEventNewStream(State state, ref QUIC_CONNECTION_EVENT connectionEvent)
        {
            var streamHandle = new SafeMsQuicStreamHandle(connectionEvent.PEER_STREAM_STARTED.Stream);

            if (!state.TryQueueNewStream(streamHandle, connectionEvent.PEER_STREAM_STARTED.Flags))
            {
                // This will call StreamCloseDelegate and free the stream.
                // We will return Success to the MsQuic to prevent double free.
                streamHandle.Dispose();
            }

            return(QUIC_STATUS_SUCCESS);
        }
Ejemplo n.º 2
0
        private static unsafe int HandleEventConnected(State state, ref QUIC_CONNECTION_EVENT connectionEvent)
        {
            if (state.Connected)
            {
                return(QUIC_STATUS_SUCCESS);
            }

            if (state.IsServer)
            {
                state.Connected = true;
                MsQuicListener.State?listenerState = state.ListenerState;
                state.ListenerState = null;

                if (listenerState != null)
                {
                    if (listenerState.PendingConnections.TryRemove(state.Handle.DangerousGetHandle(), out MsQuicConnection? connection))
                    {
                        // Move connection from pending to Accept queue and hand it out.
                        if (listenerState.AcceptConnectionQueue.Writer.TryWrite(connection))
                        {
                            return(QUIC_STATUS_SUCCESS);
                        }
                        // Listener is closed
                        connection.Dispose();
                    }
                }

                return(QUIC_STATUS_USER_CANCELED);
            }
            else
            {
                // Connected will already be true for connections accepted from a listener.
                Debug.Assert(!Monitor.IsEntered(state));


                Debug.Assert(state.Connection != null);
                state.Connection._localEndPoint = MsQuicParameterHelpers.GetIPEndPointParam(MsQuicApi.Api, state.Handle, QUIC_PARAM_CONN_LOCAL_ADDRESS);
                state.Connection.SetNegotiatedAlpn((IntPtr)connectionEvent.CONNECTED.NegotiatedAlpn, connectionEvent.CONNECTED.NegotiatedAlpnLength);
                state.Connection = null;

                state.Connected = true;
                state.ConnectTcs !.SetResult(QUIC_STATUS_SUCCESS);
                state.ConnectTcs = null;
            }

            return(QUIC_STATUS_SUCCESS);
        }
Ejemplo n.º 3
0
        private static int HandleEventShutdownInitiatedByTransport(State state, ref QUIC_CONNECTION_EVENT connectionEvent)
        {
            if (!state.Connected && state.ConnectTcs != null)
            {
                Debug.Assert(state.Connection != null);
                state.Connection = null;

                Exception ex = new MsQuicException(connectionEvent.SHUTDOWN_INITIATED_BY_TRANSPORT.Status, "Connection has been shutdown by transport");
                state.ConnectTcs !.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(ex));
                state.ConnectTcs = null;
            }

            // To throw QuicConnectionAbortedException (instead of QuicOperationAbortedException) out of AcceptStreamAsync() since
            // it wasn't our side who shutdown the connection.
            // We should rather keep the Status and propagate it either in a different exception or as a different field of QuicConnectionAbortedException.
            // See: https://github.com/dotnet/runtime/issues/60133
            state.AbortErrorCode = 0;
            state.AcceptQueue.Writer.TryComplete();
            return(QUIC_STATUS_SUCCESS);
        }
Ejemplo n.º 4
0
        private static unsafe int HandleEventPeerCertificateReceived(State state, ref QUIC_CONNECTION_EVENT connectionEvent)
        {
            SslPolicyErrors            sslPolicyErrors        = SslPolicyErrors.None;
            X509Chain?                 chain                  = null;
            X509Certificate2?          certificate            = null;
            X509Certificate2Collection?additionalCertificates = null;
            IntPtr certificateBuffer = IntPtr.Zero;
            int    certificateLength = 0;

            try
            {
                IntPtr certificateHandle = (IntPtr)connectionEvent.PEER_CERTIFICATE_RECEIVED.Certificate;
                if (certificateHandle != IntPtr.Zero)
                {
                    if (OperatingSystem.IsWindows())
                    {
                        certificate = new X509Certificate2(certificateHandle);
                    }
                    else
                    {
                        unsafe
                        {
                            QUIC_BUFFER *certBuffer = (QUIC_BUFFER *)certificateHandle;
                            certificate       = new X509Certificate2(new ReadOnlySpan <byte>(certBuffer->Buffer, (int)certBuffer->Length));
                            certificateBuffer = (IntPtr)certBuffer->Buffer;
                            certificateLength = (int)certBuffer->Length;

                            IntPtr chainHandle = (IntPtr)connectionEvent.PEER_CERTIFICATE_RECEIVED.Chain;
                            if (chainHandle != IntPtr.Zero)
                            {
                                QUIC_BUFFER *chainBuffer = (QUIC_BUFFER *)chainHandle;
                                if (chainBuffer->Length != 0 && chainBuffer->Buffer != null)
                                {
                                    additionalCertificates = new X509Certificate2Collection();
                                    additionalCertificates.Import(new ReadOnlySpan <byte>(chainBuffer->Buffer, (int)chainBuffer->Length));
                                }
                            }
                        }
                    }
                }

                if (certificate == null)
                {
                    if (NetEventSource.Log.IsEnabled() && state.RemoteCertificateRequired)
                    {
                        NetEventSource.Error(state, $"{state.Handle} Remote certificate required, but no remote certificate received");
                    }
                    sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable;
                }
                else
                {
                    chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode = state.RevocationMode;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
                    chain.ChainPolicy.ApplicationPolicy.Add(state.IsServer ? s_clientAuthOid : s_serverAuthOid);

                    if (additionalCertificates != null && additionalCertificates.Count > 1)
                    {
                        chain.ChainPolicy.ExtraStore.AddRange(additionalCertificates);
                    }

                    sslPolicyErrors |= CertificateValidation.BuildChainAndVerifyProperties(chain, certificate, true, state.IsServer, state.TargetHost, certificateBuffer, certificateLength);
                }

                if (!state.RemoteCertificateRequired)
                {
                    sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNotAvailable;
                }

                state.RemoteCertificate = certificate;

                if (state.RemoteCertificateValidationCallback != null)
                {
                    bool success = state.RemoteCertificateValidationCallback(state, certificate, chain, sslPolicyErrors);
                    // Unset the callback to prevent multiple invocations of the callback per a single connection.
                    // Return the same value as the custom callback just did.
                    state.RemoteCertificateValidationCallback = (_, _, _, _) => success;

                    if (!success && NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(state, $"{state.Handle} Remote certificate rejected by verification callback");
                    }

                    if (!success)
                    {
                        if (state.IsServer)
                        {
                            return(QUIC_STATUS_USER_CANCELED);
                        }

                        throw new AuthenticationException(SR.net_quic_cert_custom_validation);
                    }

                    return(QUIC_STATUS_SUCCESS);
                }

                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Info(state, $"{state.Handle} Certificate validation for '${certificate?.Subject}' finished with ${sslPolicyErrors}");
                }


                if (sslPolicyErrors != SslPolicyErrors.None)
                {
                    if (state.IsServer)
                    {
                        return(QUIC_STATUS_HANDSHAKE_FAILURE);
                    }

                    throw new AuthenticationException(SR.Format(SR.net_quic_cert_chain_validation, sslPolicyErrors));
                }

                return(QUIC_STATUS_SUCCESS);
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(state, $"{state.Handle} Certificate validation failed ${ex.Message}");
                }
                throw;
            }
        }
Ejemplo n.º 5
0
 private static int HandleEventStreamsAvailable(State state, ref QUIC_CONNECTION_EVENT connectionEvent)
 {
     return(QUIC_STATUS_SUCCESS);
 }
Ejemplo n.º 6
0
 private static int HandleEventShutdownInitiatedByPeer(State state, ref QUIC_CONNECTION_EVENT connectionEvent)
 {
     state.AbortErrorCode = (long)connectionEvent.SHUTDOWN_INITIATED_BY_PEER.ErrorCode;
     state.AcceptQueue.Writer.TryComplete();
     return(QUIC_STATUS_SUCCESS);
 }