Exemplo n.º 1
0
        public virtual void ValidateHttpEndpoint(Models.Endpoint endpoint, X509Chain?chain, SslPolicyErrors sslPolicyErrors)
        {
            if (endpoint.GetHttpIgnoreTlsCerts())
            {
                return; // Everything is OK
            }

            chain ??= new X509Chain();
            var customCertPem = endpoint.GetHttpCustomTlsCert();

            if (!string.IsNullOrWhiteSpace(customCertPem))
            {
                if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable))
                {
                    // Unacceptable errors are present; throw
                    throw GetAppropriateException(false, chain, sslPolicyErrors, false);
                }
                foreach (var el in chain.ChainElements)
                {
                    if (el.ChainElementStatus != null && el.ChainElementStatus.Length > 0)
                    {
                        foreach (var status in el.ChainElementStatus)
                        {
                            if (status.Status == X509ChainStatusFlags.NoError)
                            {
                                continue;
                            }
                            if (status.Status.HasFlag(X509ChainStatusFlags.Cyclic) || status.Status.HasFlag(X509ChainStatusFlags.ExplicitDistrust) || status.Status.HasFlag(X509ChainStatusFlags.NotSignatureValid) || status.Status.HasFlag(X509ChainStatusFlags.Revoked))
                            {
                                // Unacceptable errors are present; throw
                                throw GetAppropriateException(false, chain, sslPolicyErrors, false);
                            }
                        }
                    }
                }

                // Everything looks good so far; load the custom cert
                var cert = LoadCert(false, customCertPem);

                foreach (var el in chain.ChainElements)
                {
                    if (el.Certificate.Thumbprint.Equals(cert.Thumbprint))
                    {
                        // Got a matching cert; everything is okay
                        return;
                    }
                }

                throw GetAppropriateException(false, chain, sslPolicyErrors, true);
            }
            else
            {
                // Use existing status information
                if (sslPolicyErrors == SslPolicyErrors.None)
                {
                    return; // OK
                }
                throw GetAppropriateException(false, chain, sslPolicyErrors, false);
            }
        }
Exemplo n.º 2
0
            static bool CertificateValidationCallback(
                object sender,
                X509Certificate?certificate,
                X509Chain?chain,
                SslPolicyErrors sslPolicyErrors)
            {
                Assert.NotNull(certificate);

                using (SafeCertContextHandle ctx = new SafeCertContextHandle(certificate.Handle, ownsHandle: false))
                {
                    bool hasStapledOcsp =
                        ctx.CertHasProperty(Interop.Crypt32.CertContextPropId.CERT_OCSP_RESPONSE_PROP_ID);

                    if (((SslStream)sender).CheckCertRevocationStatus)
                    {
                        Assert.True(hasStapledOcsp, "Cert has stapled OCSP data");
                    }
                    else
                    {
                        Assert.False(hasStapledOcsp, "Cert has stapled OCSP data");
                    }
                }

                return(true);
            }
Exemplo n.º 3
0
        internal static bool TryFindClientCertificate(this X509Certificate2Collection certificates,
                                                      ISet <string> allowedIssuers,
                                                      out X509Certificate2?clientCertificate,
                                                      out X509Chain?clientCertChain)
        {
            clientCertificate = null;
            clientCertChain   = null;
            if (certificates == null)
            {
                return(false);
            }

            DateTime now = DateTime.Now;

            foreach (X509Certificate2 cert in certificates)
            {
                if (cert.HasPrivateKey && now >= cert.NotBefore && now <= cert.NotAfter)
                {
                    if (IsClientCertificate(cert))
                    {
                        if (allowedIssuers.Count == 0)
                        {
                            clientCertificate = cert;
                            clientCertChain   = null;
                            return(true);
                        }

                        X509Chain?chain = BuildNewChain(cert, includeClientApplicationPolicy: true);
                        if (chain == null)
                        {
                            continue;
                        }

                        bool isComplete = true;
                        foreach (X509ChainStatus chainStatus in chain.ChainStatus)
                        {
                            if ((chainStatus.Status & X509ChainStatusFlags.PartialChain) == X509ChainStatusFlags.PartialChain)
                            {
                                isComplete = false;
                                break;
                            }
                        }

                        if (chain.ChainElements.Count > 0 && isComplete)
                        {
                            X509Certificate2 trustAnchor = chain.ChainElements[chain.ChainElements.Count - 1].Certificate !;
                            if (allowedIssuers.Contains(trustAnchor.SubjectName.Name))
                            {
                                clientCertificate = cert;
                                clientCertChain   = chain;
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Exemplo n.º 4
0
 private static bool DangerousCertificationValidation(
     object sender,
     X509Certificate?certificate,
     X509Chain?chain,
     SslPolicyErrors sslPolicyErrors)
 {
     return(true);
 }
Exemplo n.º 5
0
        private static X509Certificate2?GetRemoteCertificate(
            SafeDeleteContext?securityContext,
            bool retrieveChainCertificates,
            ref X509Chain?chain,
            X509ChainPolicy?chainPolicy)
        {
            if (securityContext == null)
            {
                return(null);
            }

            SafeSslHandle sslContext = ((SafeDeleteSslContext)securityContext).SslContext;

            if (sslContext == null)
            {
                return(null);
            }

            X509Certificate2?result = null;

            using (SafeX509ChainHandle chainHandle = Interop.AppleCrypto.SslCopyCertChain(sslContext))
            {
                long chainSize = Interop.AppleCrypto.X509ChainGetChainSize(chainHandle);

                if (retrieveChainCertificates && chainSize > 1)
                {
                    chain ??= new X509Chain();
                    if (chainPolicy != null)
                    {
                        chain.ChainPolicy = chainPolicy;
                    }

                    // First certificate is peer's certificate.
                    // Any any additional intermediate CAs to ExtraStore.
                    for (int i = 1; i < chainSize; i++)
                    {
                        IntPtr certHandle = Interop.AppleCrypto.X509ChainGetCertificateAtIndex(chainHandle, i);
                        chain.ChainPolicy.ExtraStore.Add(new X509Certificate2(certHandle));
                    }
                }

                // This will be a distinct object than remoteCertificateStore[0] (if applicable),
                // to match what the Windows and Unix PALs do.
                if (chainSize > 0)
                {
                    IntPtr certHandle = Interop.AppleCrypto.X509ChainGetCertificateAtIndex(chainHandle, 0);
                    result = new X509Certificate2(certHandle);
                }
            }

            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Log.RemoteCertificate(result);
            }

            return(result);
        }
        //
        // Extracts a remote certificate upon request.
        //

        private static X509Certificate2?GetRemoteCertificate(
            SafeDeleteContext?securityContext, bool retrieveChainCertificates, ref X509Chain?chain)
        {
            if (securityContext == null)
            {
                return(null);
            }

            X509Certificate2?   result        = null;
            SafeFreeCertContext?remoteContext = null;

            try
            {
                // SECPKG_ATTR_REMOTE_CERT_CONTEXT will not succeed before TLS handshake completes. Inside the handshake,
                // we need to use (more expensive) SECPKG_ATTR_REMOTE_CERT_CHAIN. That one may be unsupported on older
                // versions of windows. In that case, we have no option than to return null.
                //
                // We can use retrieveCollection to distinguish between in-handshake and after-handshake calls, because
                // the collection is retrieved for cert validation purposes after the handshake completes.
                if (retrieveChainCertificates) // handshake completed
                {
                    SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);
                }
                else // in handshake
                {
                    SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CHAIN(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);
                }

                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }
            }
            finally
            {
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    if (retrieveChainCertificates)
                    {
                        chain ??= new X509Chain();

                        UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext, chain.ChainPolicy.ExtraStore);
                    }

                    remoteContext.Dispose();
                }
            }

            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Log.RemoteCertificate(result);
            }
            return(result);
        }
Exemplo n.º 7
0
        //
        // Extracts a remote certificate upon request.
        //

        private static X509Certificate2?GetRemoteCertificate(
            SafeDeleteContext?securityContext,
            bool retrieveChainCertificates,
            ref X509Chain?chain,
            X509ChainPolicy?chainPolicy)
        {
            SafeSslHandle?sslContext = ((SafeDeleteSslContext?)securityContext)?.SslContext;

            if (sslContext == null)
            {
                return(null);
            }

            X509Certificate2?cert = null;

            if (!retrieveChainCertificates)
            {
                // Constructing a new X509Certificate2 adds a global reference to the pointer, so we dispose this handle
                using (SafeX509Handle handle = Interop.AndroidCrypto.SSLStreamGetPeerCertificate(sslContext))
                {
                    if (!handle.IsInvalid)
                    {
                        cert = new X509Certificate2(handle.DangerousGetHandle());
                    }
                }
            }
            else
            {
                chain ??= new X509Chain();
                if (chainPolicy != null)
                {
                    chain.ChainPolicy = chainPolicy;
                }
                IntPtr[]? ptrs = Interop.AndroidCrypto.SSLStreamGetPeerCertificates(sslContext);
                if (ptrs != null && ptrs.Length > 0)
                {
                    // This is intentionally a different object from the cert added to the remote certificate store
                    // to match the behaviour on other platforms.
                    cert = new X509Certificate2(ptrs[0]);
                    foreach (IntPtr ptr in ptrs)
                    {
                        // Constructing a new X509Certificate2 adds a global reference to the pointer, so we dispose this handle
                        using (var handle = new SafeX509Handle(ptr))
                        {
                            chain.ChainPolicy.ExtraStore.Add(new X509Certificate2(handle.DangerousGetHandle()));
                        }
                    }
                }
            }

            return(cert);
        }
Exemplo n.º 8
0
            static bool CertificateValidationCallback(
                object sender,
                X509Certificate?certificate,
                X509Chain?chain,
                SslPolicyErrors sslPolicyErrors)
            {
                Assert.NotNull(certificate);
                Assert.NotNull(chain);

                sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateChainErrors;

                chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
                chain.ChainPolicy.CustomTrustStore.Add(chain.ChainElements[^ 1].Certificate);
Exemplo n.º 9
0
        public async Task <bool> ValidateAsync(X509Certificate2 certificate, X509Chain?chain, SslPolicyErrors sslPolicyErrors, CancellationToken token)
        {
            if (certificate is null)
            {
                throw new ArgumentNullException(nameof(certificate));
            }
            if (chain is null)
            {
                throw new ArgumentNullException(nameof(chain));
            }

            var commonName   = certificate.GetNameInfo(X509NameType.SimpleName, false);
            var regex        = Regex.Match(commonName, "([a-fA-F0-9]{2}[-:]?){8}");
            var parseSuccess = StationEui.TryParse(regex.Value, out var stationEui);

            if (!parseSuccess)
            {
                this.logger.LogError("Could not find a possible StationEui in '{CommonName}'.", commonName);
                return(false);
            }

            using var scope = this.logger.BeginEuiScope(stationEui);

            // Logging any chain related issue that is causing verification to fail
            if (chain.ChainStatus.Any(s => s.Status != X509ChainStatusFlags.NoError))
            {
                foreach (var status in chain.ChainStatus)
                {
                    this.logger.LogError("{Status} {StatusInformation}", status.Status, status.StatusInformation);
                }
                this.logger.LogError("Some errors were found in the chain.");
                return(false);
            }

            // Additional validation is done on certificate thumprint
            try
            {
                var thumbprints = await this.stationConfigurationService.GetAllowedClientThumbprintsAsync(stationEui, token);

                var thumbprintFound = thumbprints.Any(t => t.Equals(certificate.Thumbprint, StringComparison.OrdinalIgnoreCase));
                if (!thumbprintFound)
                {
                    this.logger.LogDebug($"'{certificate.Thumbprint}' was not found as allowed thumbprint for {stationEui}");
                }
                return(thumbprintFound);
            }
            catch (Exception ex) when(ExceptionFilterUtility.False(() => this.logger.LogError(ex, "An exception occurred while processing requests: {Exception}.", ex)))
            {
                return(false);
            }
        }
Exemplo n.º 10
0
    private static bool ServerCertificateCustomValidation(
        HttpRequestMessage requestMessage,
        X509Certificate2?certificate,
        X509Chain?chain,
        SslPolicyErrors sslErrors)
    {
        if (certificate is not null)
        {
            requestMessage.Properties[HttpPropertyKeyCertificateDaysToExpiry] =
                (int)Math.Floor((certificate.NotAfter - DateTime.Now).TotalDays);
        }

        return(sslErrors == SslPolicyErrors.None);
    }
Exemplo n.º 11
0
    public bool CheckValidationCallback(object sender, X509Certificate?certificate, X509Chain?chain, SslPolicyErrors sslPolicyErrors)
    {
        try
        {
            this.CheckCertificate(certificate);
        }
        catch (Exception ex)
        {
            ex._Error();

            return(false);
        }

        return(true);
    }
Exemplo n.º 12
0
        internal static bool RemoteCertificateValidationCallback(
            ClientCertificateMode clientCertificateMode,
            Func <X509Certificate2, X509Chain?, SslPolicyErrors, bool>?clientCertificateValidation,
            X509Certificate?certificate,
            X509Chain?chain,
            SslPolicyErrors sslPolicyErrors)
        {
            if (certificate == null)
            {
                return(clientCertificateMode != ClientCertificateMode.RequireCertificate);
            }

            if (clientCertificateValidation == null)
            {
                if (sslPolicyErrors != SslPolicyErrors.None)
                {
                    return(false);
                }
            }

            var certificate2 = ConvertToX509Certificate2(certificate);

            if (certificate2 == null)
            {
                return(false);
            }

            if (clientCertificateValidation != null)
            {
                if (!clientCertificateValidation(certificate2, chain, sslPolicyErrors))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemplo n.º 13
0
 public bool RemoteCertificateValidationCallback(object sender, X509Certificate?certificate, X509Chain?chain, SslPolicyErrors sslPolicyErrors)
 {
     Assert.Equal(ServerCertificate.GetCertHash(), certificate?.GetCertHash());
     return(true);
 }
Exemplo n.º 14
0
        private static bool ValidateServerCertificate(ClickHouseConnectionSettings connectionSettings, X509Certificate?cert, X509Chain?chain, SslPolicyErrors errors)
        {
            if (errors == SslPolicyErrors.None)
            {
                return(true);
            }

            if (cert == null)
            {
                return(false);
            }

            if (!connectionSettings.ServerCertificateHash.IsEmpty)
            {
                var certHash = cert.GetCertHash();
                if (connectionSettings.ServerCertificateHash.Span.SequenceEqual(certHash))
                {
                    return(true);
                }
            }

            if (chain != null && connectionSettings.RootCertificate != null)
            {
                if ((errors & ~SslPolicyErrors.RemoteCertificateChainErrors) != SslPolicyErrors.None)
                {
                    return(false);
                }

                var collection = CertificateHelper.LoadFromFile(connectionSettings.RootCertificate);
#if NET5_0_OR_GREATER
                chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
                chain.ChainPolicy.CustomTrustStore.AddRange(collection);
                var isValid = chain.Build(cert as X509Certificate2 ?? new X509Certificate2(cert));
                return(isValid);
#else
                foreach (var chainElement in chain.ChainElements)
                {
                    if (chainElement.ChainElementStatus.Length != 0)
                    {
                        bool ignoreError = true;
                        foreach (var status in chainElement.ChainElementStatus)
                        {
                            if (status.Status == X509ChainStatusFlags.UntrustedRoot)
                            {
                                continue;
                            }

                            ignoreError = false;
                            break;
                        }

                        if (!ignoreError)
                        {
                            break;
                        }
                    }

                    if (collection.Contains(chainElement.Certificate))
                    {
                        return(true);
                    }
                }
#endif
            }

            return(false);
        }
Exemplo n.º 15
0
 internal static bool AllowCertificate(object sender, X509Certificate?certificate, X509Chain?chain, SslPolicyErrors sslPolicyErrors) => true;
Exemplo n.º 16
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;
            }
        }
Exemplo n.º 17
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 bool Validate(object sender, X509Certificate?certificate, X509Chain?chain, SslPolicyErrors sslpolicyerrors)
        {
            ArgumentNullException.ThrowIfNull(certificate);

            return(IsValidChain(_certificateAuthority, certificate));
        }
Exemplo n.º 19
0
        private static void OnRequestSendingRequest(WinHttpRequestState state)
        {
            Debug.Assert(state != null, "OnRequestSendingRequest: state is null");
            Debug.Assert(state.RequestHandle != null, "OnRequestSendingRequest: state.RequestHandle is null");
            Debug.Assert(state.RequestMessage != null, "OnRequestSendingRequest: state.RequestMessage is null");
            Debug.Assert(state.RequestMessage.RequestUri != null, "OnRequestSendingRequest: state.RequestMessage.RequestUri is null");

            if (state.RequestMessage.RequestUri.Scheme != UriScheme.Https)
            {
                // Not SSL/TLS.
                return;
            }

            // Grab the channel binding token (CBT) information from the request handle and put it into
            // the TransportContext object.
            state.TransportContext.SetChannelBinding(state.RequestHandle);

            if (state.ServerCertificateValidationCallback != null)
            {
                IntPtr certHandle     = IntPtr.Zero;
                uint   certHandleSize = (uint)IntPtr.Size;

                if (!Interop.WinHttp.WinHttpQueryOption(
                        state.RequestHandle,
                        Interop.WinHttp.WINHTTP_OPTION_SERVER_CERT_CONTEXT,
                        ref certHandle,
                        ref certHandleSize))
                {
                    int lastError = Marshal.GetLastWin32Error();
                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(state, $"Error getting WINHTTP_OPTION_SERVER_CERT_CONTEXT, {lastError}");
                    }

                    if (lastError == Interop.WinHttp.ERROR_WINHTTP_INCORRECT_HANDLE_STATE)
                    {
                        // Not yet an SSL/TLS connection. This occurs while connecting thru a proxy where the
                        // CONNECT verb hasn't yet been processed due to the proxy requiring authentication.
                        // We need to ignore this notification. Another notification will be sent once the final
                        // connection thru the proxy is completed.
                        return;
                    }

                    throw WinHttpException.CreateExceptionUsingError(lastError, "WINHTTP_CALLBACK_STATUS_SENDING_REQUEST/WinHttpQueryOption");
                }

                // Get any additional certificates sent from the remote server during the TLS/SSL handshake.
                X509Certificate2Collection remoteCertificateStore = new X509Certificate2Collection();
                UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(certHandle, remoteCertificateStore);

                // Create a managed wrapper around the certificate handle. Since this results in duplicating
                // the handle, we will close the original handle after creating the wrapper.
                var serverCertificate = new X509Certificate2(certHandle);
                Interop.Crypt32.CertFreeCertificateContext(certHandle);

                X509Chain?      chain = null;
                SslPolicyErrors sslPolicyErrors;
                bool            result = false;

                try
                {
                    WinHttpCertificateHelper.BuildChain(
                        serverCertificate,
                        remoteCertificateStore,
                        state.RequestMessage.RequestUri.Host,
                        state.CheckCertificateRevocationList,
                        out chain,
                        out sslPolicyErrors);

                    result = state.ServerCertificateValidationCallback(
                        state.RequestMessage,
                        serverCertificate,
                        chain,
                        sslPolicyErrors);
                }
                catch (Exception ex)
                {
                    throw WinHttpException.CreateExceptionUsingError(
                              (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, "X509Chain.Build", ex);
                }
                finally
                {
                    if (chain != null)
                    {
                        chain.Dispose();
                    }

                    serverCertificate.Dispose();
                }

                if (!result)
                {
                    throw WinHttpException.CreateExceptionUsingError(
                              (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, "ServerCertificateValidationCallback");
                }
            }
        }
Exemplo n.º 20
0
        private bool RemoteCertificateValidationCallback(
            object sender,
            X509Certificate?certificate,
            X509Chain?chain,
            SslPolicyErrors errors)
        {
            var message = new StringBuilder();

            if ((errors & SslPolicyErrors.RemoteCertificateNotAvailable) > 0)
            {
                // For an outgoing connection the peer must always provide a certificate, for an incoming connection
                // the certificate is only required if the RequireClientCertificate option was set.
                if (!_incoming || _engine.TlsServerOptions.RequireClientCertificate)
                {
                    if (_engine.SecurityTraceLevel >= 1)
                    {
                        _communicator.Logger.Trace(
                            SslEngine.SecurityTraceCategory,
                            "SSL certificate validation failed - remote certificate not provided");
                    }
                    return(false);
                }
                else
                {
                    errors ^= SslPolicyErrors.RemoteCertificateNotAvailable;
                    message.Append("\nremote certificate not provided (ignored)");
                }
            }

            if ((errors & SslPolicyErrors.RemoteCertificateNameMismatch) > 0)
            {
                if (_engine.SecurityTraceLevel >= 1)
                {
                    _communicator.Logger.Trace(
                        SslEngine.SecurityTraceCategory,
                        "SSL certificate validation failed - Hostname mismatch");
                }
                return(false);
            }

            X509Certificate2Collection?trustedCertificateAuthorities = _incoming ?
                                                                       _engine.TlsServerOptions.ClientCertificateCertificateAuthorities :
                                                                       _engine.TlsClientOptions.ServerCertificateCertificateAuthorities;

            bool useMachineContext = _incoming ?
                                     _engine.TlsServerOptions.UseMachineContex : _engine.TlsClientOptions.UseMachineContex;

            bool buildCustomChain =
                (trustedCertificateAuthorities != null || useMachineContext) && certificate != null;

            try
            {
                // If using custom certificate authorities or the machine context and the peer provides a certificate,
                // we rebuild the certificate chain with our custom chain policy.
                if (buildCustomChain)
                {
                    chain = new X509Chain(useMachineContext);
                    chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                    if (trustedCertificateAuthorities != null)
                    {
                        // We need to set this flag to be able to use a certificate authority from the extra store.
                        chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                        foreach (X509Certificate2 cert in trustedCertificateAuthorities)
                        {
                            chain.ChainPolicy.ExtraStore.Add(cert);
                        }
                    }
                    chain.Build((X509Certificate2)certificate !);
                }

                if (chain != null && chain.ChainStatus != null)
                {
                    var chainStatus = new List <X509ChainStatus>(chain.ChainStatus);

                    if (trustedCertificateAuthorities != null)
                    {
                        // Untrusted root is OK when using our custom chain engine if the CA certificate is present in
                        // the chain policy extra store.
                        X509ChainElement root = chain.ChainElements[^ 1];
Exemplo n.º 21
0
        private static uint HandleEventPeerCertificateReceived(State state, ref ConnectionEvent connectionEvent)
        {
            SslPolicyErrors            sslPolicyErrors        = SslPolicyErrors.None;
            X509Chain?                 chain                  = null;
            X509Certificate2?          certificate            = null;
            X509Certificate2Collection?additionalCertificates = null;

            MsQuicConnection?connection = state.Connection;

            if (connection == null)
            {
                return(MsQuicStatusCodes.InvalidState);
            }

            try
            {
                if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle != IntPtr.Zero)
                {
                    if (OperatingSystem.IsWindows())
                    {
                        certificate = new X509Certificate2(connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle);
                    }
                    else
                    {
                        unsafe
                        {
                            ReadOnlySpan <QuicBuffer> quicBuffer;
                            if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateChainHandle != IntPtr.Zero)
                            {
                                quicBuffer = new ReadOnlySpan <QuicBuffer>((void *)connectionEvent.Data.PeerCertificateReceived.PlatformCertificateChainHandle, sizeof(QuicBuffer));
                                if (quicBuffer[0].Length != 0 && quicBuffer[0].Buffer != null)
                                {
                                    ReadOnlySpan <byte> asn1 = new ReadOnlySpan <byte>(quicBuffer[0].Buffer, (int)quicBuffer[0].Length);
                                    additionalCertificates = new X509Certificate2Collection();
                                    additionalCertificates.Import(asn1);
                                    if (additionalCertificates.Count > 0)
                                    {
                                        certificate = additionalCertificates[0];
                                    }
                                }
                            }
                            else
                            {
                                quicBuffer = new ReadOnlySpan <QuicBuffer>((void *)connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle, sizeof(QuicBuffer));
                                ReadOnlySpan <byte> asn1 = new ReadOnlySpan <byte>(quicBuffer[0].Buffer, (int)quicBuffer[0].Length);
                                certificate = new X509Certificate2(asn1);
                            }
                        }
                    }
                }

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

                    if (additionalCertificates != null && additionalCertificates.Count > 1)
                    {
                        for (int i = 1; i < additionalCertificates.Count; i++)
                        {
                            chain.ChainPolicy.ExtraStore.Add(additionalCertificates[i]);
                        }
                    }

                    if (!chain.Build(certificate))
                    {
                        sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
                    }
                }

                if (!connection._remoteCertificateRequired)
                {
                    sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNotAvailable;
                }

                if (connection._remoteCertificateValidationCallback != null)
                {
                    bool success = connection._remoteCertificateValidationCallback(connection, certificate, chain, sslPolicyErrors);
                    if (!success && NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(state.Connection, "Remote certificate rejected by verification callback");
                    }
                    return(success ? MsQuicStatusCodes.Success : MsQuicStatusCodes.HandshakeFailure);
                }

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

                return((sslPolicyErrors == SslPolicyErrors.None) ? MsQuicStatusCodes.Success : MsQuicStatusCodes.HandshakeFailure);
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(state.Connection, $"Certificate validation failed ${ex.Message}");
                }
            }

            return(MsQuicStatusCodes.InternalError);
        }
Exemplo n.º 22
0
        private static uint HandleEventPeerCertificateReceived(State state, ref ConnectionEvent connectionEvent)
        {
            SslPolicyErrors            sslPolicyErrors        = SslPolicyErrors.None;
            X509Chain?                 chain                  = null;
            X509Certificate2?          certificate            = null;
            X509Certificate2Collection?additionalCertificates = null;

            try
            {
                if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle != IntPtr.Zero)
                {
                    if (OperatingSystem.IsWindows())
                    {
                        certificate = new X509Certificate2(connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle);
                    }
                    else
                    {
                        unsafe
                        {
                            ReadOnlySpan <QuicBuffer> quicBuffer = new ReadOnlySpan <QuicBuffer>((void *)connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle, sizeof(QuicBuffer));
                            certificate = new X509Certificate2(new ReadOnlySpan <byte>(quicBuffer[0].Buffer, (int)quicBuffer[0].Length));

                            if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateChainHandle != IntPtr.Zero)
                            {
                                quicBuffer = new ReadOnlySpan <QuicBuffer>((void *)connectionEvent.Data.PeerCertificateReceived.PlatformCertificateChainHandle, sizeof(QuicBuffer));
                                if (quicBuffer[0].Length != 0 && quicBuffer[0].Buffer != null)
                                {
                                    additionalCertificates = new X509Certificate2Collection();
                                    additionalCertificates.Import(new ReadOnlySpan <byte>(quicBuffer[0].Buffer, (int)quicBuffer[0].Length));
                                }
                            }
                        }
                    }
                }

                if (certificate == null)
                {
                    if (NetEventSource.Log.IsEnabled() && state.RemoteCertificateRequired)
                    {
                        NetEventSource.Error(state, $"{state.TraceId} 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);
                }

                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.TraceId} Remote certificate rejected by verification callback");
                    }

                    if (!success)
                    {
                        throw new AuthenticationException(SR.net_quic_cert_custom_validation);
                    }

                    return(MsQuicStatusCodes.Success);
                }

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


                if (sslPolicyErrors != SslPolicyErrors.None)
                {
                    throw new AuthenticationException(SR.Format(SR.net_quic_cert_chain_validation, sslPolicyErrors));
                }

                return(MsQuicStatusCodes.Success);
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(state, $"{state.TraceId} Certificate validation failed ${ex.Message}");
                }
                throw;
            }
        }
Exemplo n.º 23
0
        internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX509Handle?certHandle, SafeEvpPKeyHandle?certKeyHandle, EncryptionPolicy policy, SslAuthenticationOptions sslAuthenticationOptions)
        {
            SafeSslHandle?context = null;

            // Always use SSLv23_method, regardless of protocols.  It supports negotiating to the highest
            // mutually supported version and can thus handle any of the set protocols, and we then use
            // SetProtocolOptions to ensure we only allow the ones requested.
            using (SafeSslContextHandle innerContext = Ssl.SslCtxCreate(Ssl.SslMethods.SSLv23_method))
            {
                if (innerContext.IsInvalid)
                {
                    throw CreateSslException(SR.net_allocate_ssl_context_failed);
                }

                if (!Interop.Ssl.Tls13Supported)
                {
                    if (protocols != SslProtocols.None &&
                        CipherSuitesPolicyPal.WantsTls13(protocols))
                    {
                        protocols = protocols & (~SslProtocols.Tls13);
                    }
                }
                else if (CipherSuitesPolicyPal.WantsTls13(protocols) &&
                         CipherSuitesPolicyPal.ShouldOptOutOfTls13(sslAuthenticationOptions.CipherSuitesPolicy, policy))
                {
                    if (protocols == SslProtocols.None)
                    {
                        // we are using default settings but cipher suites policy says that TLS 1.3
                        // is not compatible with our settings (i.e. we requested no encryption or disabled
                        // all TLS 1.3 cipher suites)
                        protocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
                    }
                    else
                    {
                        // user explicitly asks for TLS 1.3 but their policy is not compatible with TLS 1.3
                        throw new SslException(
                                  SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy));
                    }
                }

                if (CipherSuitesPolicyPal.ShouldOptOutOfLowerThanTls13(sslAuthenticationOptions.CipherSuitesPolicy, policy))
                {
                    if (!CipherSuitesPolicyPal.WantsTls13(protocols))
                    {
                        // We cannot provide neither TLS 1.3 or non TLS 1.3, user disabled all cipher suites
                        throw new SslException(
                                  SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy));
                    }

                    protocols = SslProtocols.Tls13;
                }

                // Configure allowed protocols. It's ok to use DangerousGetHandle here without AddRef/Release as we just
                // create the handle, it's rooted by the using, no one else has a reference to it, etc.
                Ssl.SetProtocolOptions(innerContext.DangerousGetHandle(), protocols);

                // Sets policy and security level
                if (!Ssl.SetEncryptionPolicy(innerContext, policy))
                {
                    throw new SslException(
                              SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy));
                }

                // The logic in SafeSslHandle.Disconnect is simple because we are doing a quiet
                // shutdown (we aren't negotiating for session close to enable later session
                // restoration).
                //
                // If you find yourself wanting to remove this line to enable bidirectional
                // close-notify, you'll probably need to rewrite SafeSslHandle.Disconnect().
                // https://www.openssl.org/docs/manmaster/ssl/SSL_shutdown.html
                Ssl.SslCtxSetQuietShutdown(innerContext);

                byte[]? cipherList =
                    CipherSuitesPolicyPal.GetOpenSslCipherList(sslAuthenticationOptions.CipherSuitesPolicy, protocols, policy);

                Debug.Assert(cipherList == null || (cipherList.Length >= 1 && cipherList[cipherList.Length - 1] == 0));

                byte[]? cipherSuites =
                    CipherSuitesPolicyPal.GetOpenSslCipherSuites(sslAuthenticationOptions.CipherSuitesPolicy, protocols, policy);

                Debug.Assert(cipherSuites == null || (cipherSuites.Length >= 1 && cipherSuites[cipherSuites.Length - 1] == 0));

                unsafe
                {
                    fixed(byte *cipherListStr = cipherList)
                    fixed(byte *cipherSuitesStr = cipherSuites)
                    {
                        if (!Ssl.SetCiphers(innerContext, cipherListStr, cipherSuitesStr))
                        {
                            Crypto.ErrClearError();
                            throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy));
                        }
                    }
                }

                bool hasCertificateAndKey =
                    certHandle != null && !certHandle.IsInvalid &&
                    certKeyHandle != null && !certKeyHandle.IsInvalid;

                if (hasCertificateAndKey)
                {
                    SetSslCertificate(innerContext, certHandle !, certKeyHandle !);
                }

                if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired)
                {
                    Ssl.SslCtxSetVerify(innerContext, s_verifyClientCertificate);
                }

                GCHandle alpnHandle = default;
                try
                {
                    if (sslAuthenticationOptions.ApplicationProtocols != null)
                    {
                        if (sslAuthenticationOptions.IsServer)
                        {
                            alpnHandle = GCHandle.Alloc(sslAuthenticationOptions.ApplicationProtocols);
                            Interop.Ssl.SslCtxSetAlpnSelectCb(innerContext, s_alpnServerCallback, GCHandle.ToIntPtr(alpnHandle));
                        }
                        else
                        {
                            if (Interop.Ssl.SslCtxSetAlpnProtos(innerContext, sslAuthenticationOptions.ApplicationProtocols) != 0)
                            {
                                throw CreateSslException(SR.net_alpn_config_failed);
                            }
                        }
                    }

                    context = SafeSslHandle.Create(innerContext, sslAuthenticationOptions.IsServer);
                    Debug.Assert(context != null, "Expected non-null return value from SafeSslHandle.Create");
                    if (context.IsInvalid)
                    {
                        context.Dispose();
                        throw CreateSslException(SR.net_allocate_ssl_context_failed);
                    }

                    if (!sslAuthenticationOptions.IsServer)
                    {
                        // The IdnMapping converts unicode input into the IDNA punycode sequence.
                        string punyCode = s_idnMapping.GetAscii(sslAuthenticationOptions.TargetHost !);

                        // Similar to windows behavior, set SNI on openssl by default for client context, ignore errors.
                        if (!Ssl.SslSetTlsExtHostName(context, punyCode))
                        {
                            Crypto.ErrClearError();
                        }
                    }

                    if (hasCertificateAndKey)
                    {
                        bool hasCertReference = false;
                        try
                        {
                            certHandle !.DangerousAddRef(ref hasCertReference);
                            using (X509Certificate2 cert = new X509Certificate2(certHandle.DangerousGetHandle()))
                            {
                                X509Chain?chain = null;
                                try
                                {
                                    chain = TLSCertificateExtensions.BuildNewChain(cert, includeClientApplicationPolicy: false);
                                    if (chain != null && !Ssl.AddExtraChainCertificates(context, chain))
                                    {
                                        throw CreateSslException(SR.net_ssl_use_cert_failed);
                                    }
                                }
                                finally
                                {
                                    if (chain != null)
                                    {
                                        int elementsCount = chain.ChainElements.Count;
                                        for (int i = 0; i < elementsCount; i++)
                                        {
                                            chain.ChainElements[i].Certificate !.Dispose();
                                        }

                                        chain.Dispose();
                                    }
                                }
                            }
                        }
                        finally
                        {
                            if (hasCertReference)
                            {
                                certHandle !.DangerousRelease();
                            }
                        }
                    }

                    context.AlpnHandle = alpnHandle;
                }
                catch
                {
                    if (alpnHandle.IsAllocated)
                    {
                        alpnHandle.Free();
                    }

                    throw;
                }
            }

            return(context);
        }
Exemplo n.º 24
0
        private bool RemoteCertificateValidationCallback(object sender, X509Certificate?certificate, X509Chain?chain, SslPolicyErrors sslPolicyErrors)
        {
            Debug.Assert(_options != null, "Middleware must be created with options.");

            return(RemoteCertificateValidationCallback(_options.ClientCertificateMode, _options.ClientCertificateValidation, certificate, chain, sslPolicyErrors));
        }
Exemplo n.º 25
0
        private bool ValidateServerCertificate(object sender, X509Certificate?certificate, X509Chain?chain, SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
            {
                return(true);
            }

            if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable))
            {
                return(false);
            }

            if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch) && _verifyCertificateName)
            {
                return(false);
            }

            if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors) && _verifyCertificateAuthority)
            {
                if (_trustedCertificateAuthority is null || chain is null || certificate is null)
                {
                    return(false);
                }

                chain.ChainPolicy.ExtraStore.Add(_trustedCertificateAuthority);
                _ = chain.Build((X509Certificate2)certificate);

                for (var i = 0; i < chain.ChainElements.Count; i++)
                {
                    if (chain.ChainElements[i].Certificate.Thumbprint == _trustedCertificateAuthority.Thumbprint)
                    {
                        return(true);
                    }
                }

                return(false);
            }

            return(true);
        }
Exemplo n.º 26
0
        private static uint HandleEventPeerCertificateReceived(State state, ref ConnectionEvent connectionEvent)
        {
            SslPolicyErrors  sslPolicyErrors = SslPolicyErrors.None;
            X509Chain?       chain           = null;
            X509Certificate2?certificate     = null;

            if (!OperatingSystem.IsWindows())
            {
                // TODO fix validation with OpenSSL
                return(MsQuicStatusCodes.Success);
            }

            MsQuicConnection?connection = state.Connection;

            if (connection == null)
            {
                return(MsQuicStatusCodes.InvalidState);
            }

            if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle != IntPtr.Zero)
            {
                certificate = new X509Certificate2(connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle);
            }

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

                    if (!chain.Build(certificate))
                    {
                        sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
                    }
                }

                if (!connection._remoteCertificateRequired)
                {
                    sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNotAvailable;
                }

                if (connection._remoteCertificateValidationCallback != null)
                {
                    bool success = connection._remoteCertificateValidationCallback(connection, certificate, chain, sslPolicyErrors);
                    if (!success && NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(state.Connection, "Remote certificate rejected by verification callback");
                    }
                    return(success ? MsQuicStatusCodes.Success : MsQuicStatusCodes.HandshakeFailure);
                }

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

                return((sslPolicyErrors == SslPolicyErrors.None) ? MsQuicStatusCodes.Success : MsQuicStatusCodes.HandshakeFailure);
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(state.Connection, $"Certificate validation failed ${ex.Message}");
                }
            }

            return(MsQuicStatusCodes.InternalError);
        }
        //
        // Extracts a remote certificate upon request.
        //
        private static X509Certificate2?GetRemoteCertificate(
            SafeDeleteContext?securityContext,
            bool retrieveChainCertificates,
            ref X509Chain?chain,
            X509ChainPolicy?chainPolicy)
        {
            bool gotReference = false;

            if (securityContext == null)
            {
                return(null);
            }

            X509Certificate2?   result        = null;
            SafeFreeCertContext?remoteContext = null;

            try
            {
                QueryContextRemoteCertificate(securityContext, out remoteContext);

                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    remoteContext.DangerousAddRef(ref gotReference);
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }

                if (retrieveChainCertificates)
                {
                    chain ??= new X509Chain();
                    if (chainPolicy != null)
                    {
                        chain.ChainPolicy = chainPolicy;
                    }

                    using (SafeSharedX509StackHandle chainStack =
                               Interop.OpenSsl.GetPeerCertificateChain(((SafeDeleteSslContext)securityContext).SslContext))
                    {
                        if (!chainStack.IsInvalid)
                        {
                            int count = Interop.Crypto.GetX509StackFieldCount(chainStack);

                            for (int i = 0; i < count; i++)
                            {
                                IntPtr certPtr = Interop.Crypto.GetX509StackField(chainStack, i);

                                if (certPtr != IntPtr.Zero)
                                {
                                    // X509Certificate2(IntPtr) calls X509_dup, so the reference is appropriately tracked.
                                    X509Certificate2 chainCert = new X509Certificate2(certPtr);
                                    chain.ChainPolicy.ExtraStore.Add(chainCert);
                                }
                            }
                        }
                    }
                }
            }
            catch
            {
                result?.Dispose();
                throw;
            }
            finally
            {
                if (remoteContext != null)
                {
                    if (gotReference)
                    {
                        remoteContext.DangerousRelease();
                    }

                    remoteContext.Dispose();
                }
            }

            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Log.RemoteCertificate(result);
            }
            return(result);
        }
Exemplo n.º 28
0
 /// <summary>
 /// Initializes an instance of <see cref="ServerCertificateCustomValidationArgs"/>.
 /// </summary>
 /// <param name="certificate">The certificate</param>
 /// <param name="x509Chain"></param>
 /// <param name="sslPolicyErrors"></param>
 public ServerCertificateCustomValidationArgs(X509Certificate2?certificate, X509Chain?x509Chain, SslPolicyErrors sslPolicyErrors)
 {
     Certificate     = certificate;
     X509Chain       = x509Chain;
     SslPolicyErrors = sslPolicyErrors;
 }
Exemplo n.º 29
0
 internal static X509Certificate2?GetRemoteCertificate(SafeDeleteContext?securityContext, ref X509Chain?chain, X509ChainPolicy?chainPolicy) =>
 GetRemoteCertificate(securityContext, retrieveChainCertificates: true, ref chain, chainPolicy);
 private bool CertificateValidation(HttpRequestMessage requestMessage, X509Certificate?certificate, X509Chain?chain, SslPolicyErrors sslPolicyErrors)
 {
     return(true);
 }