private void FreeNativeMemory() { QUIC_BUFFER *buffers = _buffers; _buffers = null; NativeMemory.Free(buffers); }
private void Reserve(int count) { if (count > _count) { FreeNativeMemory(); _buffers = (QUIC_BUFFER *)NativeMemory.AllocZeroed((nuint)count, (nuint)sizeof(QUIC_BUFFER)); _count = count; } }
private void Reserve(int count) { if (_handles.Length < count) { _handles = new MemoryHandle[count]; FreeNativeMemory(); _buffers = (QUIC_BUFFER *)NativeMemory.Alloc((nuint)count, (nuint)sizeof(QUIC_BUFFER)); } _count = count; }
/// <summary> /// The method initializes QUIC_BUFFER* with data from inputs, converted via toBuffer. /// Note that the struct either needs to be freshly created via new or previously cleaned up with Reset. /// </summary> /// <param name="inputs">Inputs to get their byte array, pin them and pepare them to be passed to MsQuic as QUIC_BUFFER*.</param> /// <param name="toBuffer">Method extracting byte array from the inputs, e.g. applicationProtocol.Protocol.</param> /// <typeparam name="T">The type of the inputs.</typeparam> public void Initialize <T>(IList <T> inputs, Func <T, ReadOnlyMemory <byte> > toBuffer) { if (_handles.Length < inputs.Count) { _handles = new MemoryHandle[inputs.Count]; } if (_count < inputs.Count) { FreeNativeMemory(); _buffers = (QUIC_BUFFER *)NativeMemory.Alloc((nuint)sizeof(QUIC_BUFFER), (nuint)inputs.Count); } _count = inputs.Count; for (int i = 0; i < inputs.Count; ++i) { ReadOnlyMemory <byte> buffer = toBuffer(inputs[i]); MemoryHandle handle = buffer.Pin(); _handles[i] = handle; _buffers[i].Buffer = (byte *)handle.Pointer; _buffers[i].Length = (uint)buffer.Length; } }
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; } }
public MsQuicBuffers() { _buffers = null; _count = 0; }
public unsafe int ValidateCertificate(QUIC_BUFFER *certificatePtr, QUIC_BUFFER *chainPtr, out X509Certificate2?certificate) { SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; IntPtr certificateBuffer = 0; int certificateLength = 0; X509Chain? chain = null; X509Certificate2?result = null; try { if (certificatePtr is not null) { chain = new X509Chain(); chain.ChainPolicy.RevocationMode = _revocationMode; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; chain.ChainPolicy.ApplicationPolicy.Add(_isClient ? s_serverAuthOid : s_clientAuthOid); if (OperatingSystem.IsWindows()) { result = new X509Certificate2((IntPtr)certificatePtr); } else { if (certificatePtr->Length > 0) { certificateBuffer = (IntPtr)certificatePtr->Buffer; certificateLength = (int)certificatePtr->Length; result = new X509Certificate2(certificatePtr->Span); } if (chainPtr->Length > 0) { X509Certificate2Collection additionalCertificates = new X509Certificate2Collection(); additionalCertificates.Import(chainPtr->Span); chain.ChainPolicy.ExtraStore.AddRange(additionalCertificates); } } } if (result is not null) { sslPolicyErrors |= CertificateValidation.BuildChainAndVerifyProperties(chain !, result, checkCertName: true, !_isClient, _targetHost, certificateBuffer, certificateLength); } else if (_certificateRequired) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable; } int status = QUIC_STATUS_SUCCESS; if (_validationCallback is not null) { if (!_validationCallback(_connection, result, chain, sslPolicyErrors)) { if (_isClient) { throw new AuthenticationException(SR.net_quic_cert_custom_validation); } status = QUIC_STATUS_USER_CANCELED; } } else if (sslPolicyErrors != SslPolicyErrors.None) { if (_isClient) { throw new AuthenticationException(SR.Format(SR.net_quic_cert_chain_validation, sslPolicyErrors)); } status = QUIC_STATUS_HANDSHAKE_FAILURE; } certificate = result; return(status); } catch { result?.Dispose(); throw; } finally { if (chain is not null) { X509ChainElementCollection elements = chain.ChainElements; for (int i = 0; i < elements.Count; i++) { elements[i].Certificate.Dispose(); } chain.Dispose(); } } }
public MsQuicBuffers() { _handles = Array.Empty <MemoryHandle>(); _buffers = null; _count = 0; }
public unsafe int ValidateCertificate(QUIC_BUFFER *certificatePtr, QUIC_BUFFER *chainPtr, out X509Certificate2?certificate) { SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; IntPtr certificateBuffer = 0; int certificateLength = 0; X509Chain? chain = null; X509Certificate2?result = null; try { if (certificatePtr is not null) { chain = new X509Chain(); if (_certificateChainPolicy != null) { chain.ChainPolicy = _certificateChainPolicy; } else { chain.ChainPolicy.RevocationMode = _revocationMode; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; // TODO: configure chain.ChainPolicy.CustomTrustStore to mirror behavior of SslStream.VerifyRemoteCertificate (https://github.com/dotnet/runtime/issues/73053) } // set ApplicationPolicy unless already provided. if (chain.ChainPolicy.ApplicationPolicy.Count == 0) { // Authenticate the remote party: (e.g. when operating in server mode, authenticate the client). chain.ChainPolicy.ApplicationPolicy.Add(_isClient ? s_serverAuthOid : s_clientAuthOid); } if (MsQuicApi.UsesSChannelBackend) { result = new X509Certificate2((IntPtr)certificatePtr); } else { if (certificatePtr->Length > 0) { certificateBuffer = (IntPtr)certificatePtr->Buffer; certificateLength = (int)certificatePtr->Length; result = new X509Certificate2(certificatePtr->Span); } if (chainPtr->Length > 0) { X509Certificate2Collection additionalCertificates = new X509Certificate2Collection(); additionalCertificates.Import(chainPtr->Span); chain.ChainPolicy.ExtraStore.AddRange(additionalCertificates); } } } if (result is not null) { bool checkCertName = !chain !.ChainPolicy !.VerificationFlags.HasFlag(X509VerificationFlags.IgnoreInvalidName); sslPolicyErrors |= CertificateValidation.BuildChainAndVerifyProperties(chain !, result, checkCertName, !_isClient, _targetHost, certificateBuffer, certificateLength); } else if (_certificateRequired) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable; } int status = QUIC_STATUS_SUCCESS; if (_validationCallback is not null) { if (!_validationCallback(_connection, result, chain, sslPolicyErrors)) { if (_isClient) { throw new AuthenticationException(SR.net_quic_cert_custom_validation); } status = QUIC_STATUS_USER_CANCELED; } } else if (sslPolicyErrors != SslPolicyErrors.None) { if (_isClient) { throw new AuthenticationException(SR.Format(SR.net_quic_cert_chain_validation, sslPolicyErrors)); } status = QUIC_STATUS_HANDSHAKE_FAILURE; } certificate = result; return(status); } catch { result?.Dispose(); throw; } finally { if (chain is not null) { X509ChainElementCollection elements = chain.ChainElements; for (int i = 0; i < elements.Count; i++) { elements[i].Certificate.Dispose(); } chain.Dispose(); } } }