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); }
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); }
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); }
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; } }
private static int HandleEventStreamsAvailable(State state, ref QUIC_CONNECTION_EVENT connectionEvent) { return(QUIC_STATUS_SUCCESS); }
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); }