< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 150
Coverable lines: 150
Total lines: 286
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 66
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Net.Security;
 6using System.Runtime.InteropServices;
 7using System.Security;
 8using System.Security.Cryptography;
 9using System.Security.Cryptography.X509Certificates;
 10
 11namespace System.Net
 12{
 13    internal static partial class CertificateValidationPal
 14    {
 015        private static readonly object s_syncObject = new object();
 16
 17        private static X509Store? s_myCertStoreEx;
 18        private static X509Store? s_myMachineCertStoreEx;
 19        private static X509Chain? s_chain;
 20
 21        internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext) =>
 022            GetRemoteCertificate(securityContext, retrieveChainCertificates: false, ref s_chain, null);
 23
 24        internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext, ref X509Chain? chain,
 025            GetRemoteCertificate(securityContext, retrieveChainCertificates: true, ref chain, chainPolicy);
 26
 27        static partial void CheckSupportsStore(StoreLocation storeLocation, ref bool hasSupport);
 28
 29        internal static X509Store? EnsureStoreOpened(bool isMachineStore)
 030        {
 031            X509Store? store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx;
 32
 033            if (store == null)
 034            {
 035                StoreLocation storeLocation = isMachineStore ? StoreLocation.LocalMachine : StoreLocation.CurrentUser;
 36
 37                // On Windows and OSX CheckSupportsStore is not defined, so the call is eliminated and the
 38                // if should be folded out.
 39                //
 40                // On Unix it will prevent the lock from being held and released over and over for the LocalMachine stor
 041                bool supportsStore = true;
 42                CheckSupportsStore(storeLocation, ref supportsStore);
 43
 044                if (!supportsStore)
 045                {
 046                    return null;
 47                }
 48
 049                lock (s_syncObject)
 050                {
 051                    store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx;
 52
 053                    if (store == null)
 054                    {
 55                        try
 056                        {
 57                            // NOTE: that if this call fails we won't keep track and the next time we enter we will try 
 058                            store = OpenStore(storeLocation);
 59
 060                            if (NetEventSource.Log.IsEnabled())
 061                                NetEventSource.Info(null, $"storeLocation: {storeLocation} returned store {store}");
 62
 063                            if (isMachineStore)
 064                            {
 065                                s_myMachineCertStoreEx = store;
 066                            }
 67                            else
 068                            {
 069                                s_myCertStoreEx = store;
 070                            }
 071                        }
 072                        catch (Exception exception)
 073                        {
 074                            if (exception is CryptographicException || exception is SecurityException)
 075                            {
 076                                Debug.Fail($"Failed to open cert store, location: {storeLocation} exception: {exception}
 77                                return null;
 78                            }
 79
 080                            if (NetEventSource.Log.IsEnabled())
 081                                NetEventSource.Error(null, SR.Format(SR.net_log_open_store_failed, storeLocation, except
 82
 083                            throw;
 84                        }
 085                    }
 086                }
 087            }
 88
 089            return store;
 090        }
 91    }
 92}
 93

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Net.Security;
 6using System.Runtime.InteropServices;
 7using System.Security.Cryptography;
 8using System.Security.Cryptography.X509Certificates;
 9using System.Security.Principal;
 10using Microsoft.Win32.SafeHandles;
 11using static Interop.SspiCli;
 12
 13namespace System.Net
 14{
 15    internal static partial class CertificateValidationPal
 16    {
 17        internal static SslPolicyErrors VerifyCertificateProperties(
 18            SafeDeleteContext? _ /*securityContext*/,
 19            X509Chain chain,
 20            X509Certificate2 remoteCertificate,
 21            bool checkCertName,
 22            bool isServer,
 23            string? hostName)
 024        {
 025            return CertificateValidation.BuildChainAndVerifyProperties(chain, remoteCertificate, checkCertName, isServer
 026        }
 27
 28        //
 29        // Extracts a remote certificate upon request.
 30        //
 31
 32        private static X509Certificate2? GetRemoteCertificate(
 33            SafeDeleteContext? securityContext,
 34            bool retrieveChainCertificates,
 35            ref X509Chain? chain,
 36            X509ChainPolicy? chainPolicy)
 037        {
 038            if (securityContext == null)
 039            {
 040                return null;
 41            }
 42
 043            X509Certificate2? result = null;
 044            SafeFreeCertContext? remoteContext = null;
 45            try
 046            {
 47                // SECPKG_ATTR_REMOTE_CERT_CONTEXT will not succeed before TLS handshake completes. Inside the handshake
 48                // we need to use (more expensive) SECPKG_ATTR_REMOTE_CERT_CHAIN. That one may be unsupported on older
 49                // versions of windows. In that case, we have no option than to return null.
 50                //
 51                // We can use retrieveCollection to distinguish between in-handshake and after-handshake calls, because
 52                // the collection is retrieved for cert validation purposes after the handshake completes.
 053                if (retrieveChainCertificates) // handshake completed
 054                {
 055                    SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, sec
 056                }
 57                else // in handshake
 058                {
 059                    SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CHAIN(GlobalSSPI.SSPISecureChannel, secur
 060                }
 61
 062                if (remoteContext != null && !remoteContext.IsInvalid)
 063                {
 064                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
 065                }
 066            }
 67            finally
 068            {
 069                if (remoteContext != null)
 070                {
 071                    if (!remoteContext.IsInvalid)
 072                    {
 073                        if (retrieveChainCertificates)
 074                        {
 075                            chain ??= new X509Chain();
 076                            if (chainPolicy != null)
 077                            {
 078                                chain.ChainPolicy = chainPolicy;
 079                            }
 80
 081                            UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext, chain.Chain
 082                        }
 083                    }
 84
 085                    remoteContext.Dispose();
 086                }
 087            }
 88
 089            if (NetEventSource.Log.IsEnabled()) NetEventSource.Log.RemoteCertificate(result);
 090            return result;
 091        }
 92
 93        // Check that local certificate was used by schannel.
 94        internal static bool IsLocalCertificateUsed(SafeFreeCredentials? _credentialsHandle, SafeDeleteContext securityC
 095        {
 096            SecPkgContext_SessionInfo info = default;
 97            // fails on Server 2008 and older. We will fall-back to probing LOCAL_CERT_CONTEXT in that case.
 098            if (SSPIWrapper.QueryBlittableContextAttributes(
 099                                    GlobalSSPI.SSPISecureChannel,
 0100                                    securityContext,
 0101                                    Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SESSION_INFO,
 0102                                    ref info) &&
 0103               ((SecPkgContext_SessionInfo.Flags)info.dwFlags).HasFlag(SecPkgContext_SessionInfo.Flags.SSL_SESSION_RECON
 0104            {
 105                // This is TLS Resumed session. Windows can fail to query the local cert bellow.
 106                // Instead, we will determine the usage form used credentials.
 0107                SafeFreeCredential_SECURITY creds = (SafeFreeCredential_SECURITY)_credentialsHandle!;
 0108                return creds.HasLocalCertificate;
 109            }
 110
 0111            SafeFreeCertContext? localContext = null;
 112            try
 0113            {
 0114                if (SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_LOCAL_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, secu
 0115                {
 0116                    return localContext != null ? !localContext.IsInvalid : false;
 117                }
 0118            }
 119            finally
 0120            {
 0121                localContext?.Dispose();
 0122            }
 123
 124            // Some older Windows do not support that. This is only called when client certificate was provided
 125            // so assume it was for a reason.
 0126            return true;
 0127        }
 128
 129        //
 130        // Used only by client SSL code, never returns null.
 131        //
 132        internal static string[] GetRequestCertificateAuthorities(SafeDeleteContext securityContext)
 0133        {
 0134            Interop.SspiCli.SecPkgContext_IssuerListInfoEx issuerList = default;
 0135            bool success = SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_ISSUER_LIST_EX(GlobalSSPI.SSPISecureChannel, s
 136
 0137            string[] issuers = Array.Empty<string>();
 138            try
 0139            {
 0140                if (success && issuerList.cIssuers > 0)
 0141                {
 142                    unsafe
 0143                    {
 0144                        issuers = new string[issuerList.cIssuers];
 0145                        var elements = new Span<Interop.SspiCli.CERT_CHAIN_ELEMENT>((void*)sspiHandle!.DangerousGetHandl
 0146                        for (int i = 0; i < elements.Length; ++i)
 0147                        {
 0148                            Debug.Assert(elements[i].cbSize > 0, $"Interop.SspiCli._CERT_CHAIN_ELEMENT size is not posit
 0149                            if (elements[i].cbSize > 0)
 0150                            {
 0151                                ReadOnlySpan<byte> x = new ReadOnlySpan<byte>((byte*)elements[i].pCertContext, checked((
 0152                                var x500DistinguishedName = new X500DistinguishedName(x);
 0153                                issuers[i] = x500DistinguishedName.Name;
 0154                                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(securityContext, $"IssuerListEx[
 0155                            }
 0156                        }
 0157                    }
 0158                }
 0159            }
 160            finally
 0161            {
 0162                sspiHandle?.Dispose();
 0163            }
 164
 0165            return issuers;
 0166        }
 167
 168        //
 169        // Security: We temporarily reset thread token to open the cert store under process account.
 170        //
 171        internal static X509Store OpenStore(StoreLocation storeLocation)
 0172        {
 0173            X509Store store = new X509Store(StoreName.My, storeLocation);
 174
 175            // For app-compat We want to ensure the store is opened under the **process** account.
 176            try
 0177            {
 0178                using SafeAccessTokenHandle invalidHandle = SafeAccessTokenHandle.InvalidHandle;
 0179                WindowsIdentity.RunImpersonated(invalidHandle, () =>
 0180                {
 0181                    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
 0182                });
 0183            }
 0184            catch
 0185            {
 0186                throw;
 187            }
 188
 0189            return store;
 0190        }
 191    }
 192}
 193