Пример #1
0
    private void FreeNativeMemory()
    {
        QUIC_BUFFER *buffers = _buffers;

        _buffers = null;
        NativeMemory.Free(buffers);
    }
Пример #2
0
 private void Reserve(int count)
 {
     if (count > _count)
     {
         FreeNativeMemory();
         _buffers = (QUIC_BUFFER *)NativeMemory.AllocZeroed((nuint)count, (nuint)sizeof(QUIC_BUFFER));
         _count   = count;
     }
 }
Пример #3
0
    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;
    }
Пример #4
0
    /// <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;
        }
    }
Пример #5
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;
            }
        }
Пример #6
0
 public MsQuicBuffers()
 {
     _buffers = null;
     _count   = 0;
 }
Пример #7
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();
                }
            }
        }
Пример #8
0
 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();
                }
            }
        }