File: System\Net\CertificateValidationPal.cs
Web Access
Project: src\src\libraries\System.Net.Security\src\System.Net.Security.csproj (System.Net.Security)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
 
namespace System.Net
{
    internal static partial class CertificateValidationPal
    {
        private static readonly object s_syncObject = new object();
 
        private static volatile X509Store? s_myCertStoreEx;
        private static volatile X509Store? s_myMachineCertStoreEx;
        private static X509Chain? s_chain;
 
        internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext) =>
            GetRemoteCertificate(securityContext, retrieveChainCertificates: false, ref s_chain, null);
 
        internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext, ref X509Chain? chain, X509ChainPolicy? chainPolicy) =>
            GetRemoteCertificate(securityContext, retrieveChainCertificates: true, ref chain, chainPolicy);
 
        static partial void CheckSupportsStore(StoreLocation storeLocation, ref bool hasSupport);
 
        internal static X509Store? EnsureStoreOpened(bool isMachineStore)
        {
            X509Store? store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx;
 
            if (store == null)
            {
                StoreLocation storeLocation = isMachineStore ? StoreLocation.LocalMachine : StoreLocation.CurrentUser;
 
                // On Windows and OSX CheckSupportsStore is not defined, so the call is eliminated and the
                // if should be folded out.
                //
                // On Unix it will prevent the lock from being held and released over and over for the LocalMachine store.
                bool supportsStore = true;
                CheckSupportsStore(storeLocation, ref supportsStore);
 
                if (!supportsStore)
                {
                    return null;
                }
 
                lock (s_syncObject)
                {
                    store = isMachineStore ? s_myMachineCertStoreEx : s_myCertStoreEx;
 
                    if (store == null)
                    {
                        try
                        {
                            // NOTE: that if this call fails we won't keep track and the next time we enter we will try to open the store again.
                            store = OpenStore(storeLocation);
 
                            if (NetEventSource.Log.IsEnabled())
                                NetEventSource.Info(null, $"storeLocation: {storeLocation} returned store {store}");
 
                            if (isMachineStore)
                            {
                                s_myMachineCertStoreEx = store;
                            }
                            else
                            {
                                s_myCertStoreEx = store;
                            }
                        }
                        catch (Exception exception)
                        {
                            if (exception is CryptographicException || exception is SecurityException)
                            {
                                Debug.Fail($"Failed to open cert store, location: {storeLocation} exception: {exception}");
                                return null;
                            }
 
                            if (NetEventSource.Log.IsEnabled())
                                NetEventSource.Error(null, SR.Format(SR.net_log_open_store_failed, storeLocation, exception));
 
                            throw;
                        }
                    }
                }
            }
 
            return store;
        }
    }
}