private static void LoadMachineStores() { Debug.Assert( Monitor.IsEntered(s_machineLoadLock), "LoadMachineStores assumes a lock(s_machineLoadLock)"); var rootStore = new List <X509Certificate2>(); var intermedStore = new List <X509Certificate2>(); DirectoryInfo rootStorePath = null; IEnumerable <FileInfo> trustedCertFiles; try { rootStorePath = new DirectoryInfo(Interop.Crypto.GetX509RootStorePath()); } catch (ArgumentException) { // If SSL_CERT_DIR is set to the empty string, or anything else which gives // "The path is not of a legal form", then the GetX509RootStorePath value is ignored. } if (rootStorePath != null && rootStorePath.Exists) { trustedCertFiles = rootStorePath.EnumerateFiles(); } else { trustedCertFiles = Array.Empty <FileInfo>(); } FileInfo rootStoreFile = null; try { rootStoreFile = new FileInfo(Interop.Crypto.GetX509RootStoreFile()); } catch (ArgumentException) { // If SSL_CERT_FILE is set to the empty string, or anything else which gives // "The path is not of a legal form", then the GetX509RootStoreFile value is ignored. } if (rootStoreFile != null && rootStoreFile.Exists) { trustedCertFiles = Append(trustedCertFiles, rootStoreFile); } HashSet <X509Certificate2> uniqueRootCerts = new HashSet <X509Certificate2>(); HashSet <X509Certificate2> uniqueIntermediateCerts = new HashSet <X509Certificate2>(); foreach (FileInfo file in trustedCertFiles) { using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(file.FullName, "rb")) { ICertificatePal pal; while (CertificatePal.TryReadX509Pem(fileBio, out pal) || CertificatePal.TryReadX509Der(fileBio, out pal)) { X509Certificate2 cert = new X509Certificate2(pal); // The HashSets are just used for uniqueness filters, they do not survive this method. if (StringComparer.Ordinal.Equals(cert.Subject, cert.Issuer)) { if (uniqueRootCerts.Add(cert)) { rootStore.Add(cert); continue; } } else { if (uniqueIntermediateCerts.Add(cert)) { intermedStore.Add(cert); continue; } } // There's a good chance we'll encounter duplicates on systems that have both one-cert-per-file // and one-big-file trusted certificate stores. Anything that wasn't unique will end up here. cert.Dispose(); } } } var rootStorePal = new CollectionBackedStoreProvider(rootStore); s_machineIntermediateStore = new CollectionBackedStoreProvider(intermedStore); // s_machineRootStore's nullarity is the loaded-state sentinel, so write it with Volatile. Debug.Assert(Monitor.IsEntered(s_machineLoadLock), "LoadMachineStores assumes a lock(s_machineLoadLock)"); Volatile.Write(ref s_machineRootStore, rootStorePal); }
private static void LoadMachineStores() { Debug.Assert( Monitor.IsEntered(s_machineLoadLock), "LoadMachineStores assumes a lock(s_machineLoadLock)"); var rootStore = new List <X509Certificate2>(); var intermedStore = new List <X509Certificate2>(); DirectoryInfo rootStorePath = null; IEnumerable <FileInfo> trustedCertFiles; try { rootStorePath = new DirectoryInfo(Interop.Crypto.GetX509RootStorePath()); } catch (ArgumentException) { // If SSL_CERT_DIR is set to the empty string, or anything else which gives // "The path is not of a legal form", then the GetX509RootStorePath value is ignored. } if (rootStorePath != null && rootStorePath.Exists) { trustedCertFiles = rootStorePath.EnumerateFiles(); } else { trustedCertFiles = Array.Empty <FileInfo>(); } FileInfo rootStoreFile = null; try { rootStoreFile = new FileInfo(Interop.Crypto.GetX509RootStoreFile()); } catch (ArgumentException) { // If SSL_CERT_FILE is set to the empty string, or anything else which gives // "The path is not of a legal form", then the GetX509RootStoreFile value is ignored. } if (rootStoreFile != null && rootStoreFile.Exists) { trustedCertFiles = trustedCertFiles.Prepend(rootStoreFile); } HashSet <X509Certificate2> uniqueRootCerts = new HashSet <X509Certificate2>(); HashSet <X509Certificate2> uniqueIntermediateCerts = new HashSet <X509Certificate2>(); foreach (FileInfo file in trustedCertFiles) { using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(file.FullName, "rb")) { // The handle may be invalid, for example when we don't have read permission for the file. if (fileBio.IsInvalid) { Interop.Crypto.ErrClearError(); continue; } ICertificatePal pal; // Some distros ship with two variants of the same certificate. // One is the regular format ('BEGIN CERTIFICATE') and the other // contains additional AUX-data ('BEGIN TRUSTED CERTIFICATE'). // The additional data contains the appropriate usage (e.g. emailProtection, serverAuth, ...). // Because corefx doesn't validate for a specific usage, derived certificates are rejected. // For now, we skip the certificates with AUX data and use the regular certificates. while (OpenSslX509CertificateReader.TryReadX509PemNoAux(fileBio, out pal) || OpenSslX509CertificateReader.TryReadX509Der(fileBio, out pal)) { X509Certificate2 cert = new X509Certificate2(pal); // The HashSets are just used for uniqueness filters, they do not survive this method. if (StringComparer.Ordinal.Equals(cert.Subject, cert.Issuer)) { if (uniqueRootCerts.Add(cert)) { rootStore.Add(cert); continue; } } else { if (uniqueIntermediateCerts.Add(cert)) { intermedStore.Add(cert); continue; } } // There's a good chance we'll encounter duplicates on systems that have both one-cert-per-file // and one-big-file trusted certificate stores. Anything that wasn't unique will end up here. cert.Dispose(); } } } var rootStorePal = new CollectionBackedStoreProvider(rootStore); s_machineIntermediateStore = new CollectionBackedStoreProvider(intermedStore); // s_machineRootStore's nullarity is the loaded-state sentinel, so write it with Volatile. Debug.Assert(Monitor.IsEntered(s_machineLoadLock), "LoadMachineStores assumes a lock(s_machineLoadLock)"); Volatile.Write(ref s_machineRootStore, rootStorePal); }