1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
4 using System.Collections.Generic;
5 using System.Diagnostics;
7 using System.Security.Cryptography.Apple;
8 using Microsoft.Win32.SafeHandles;
10 namespace System.Security.Cryptography.X509Certificates
12 internal sealed partial class StorePal
14 internal static partial IStorePal FromHandle(IntPtr storeHandle)
16 if (storeHandle == IntPtr.Zero)
18 throw new ArgumentNullException(nameof(storeHandle));
21 var keychainHandle = new SafeKeychainHandle(storeHandle);
22 Interop.CoreFoundation.CFRetain(storeHandle);
24 return new AppleKeychainStore(keychainHandle, OpenFlags.MaxAllowed);
27 internal static partial ILoaderPal FromBlob(ReadOnlySpan<byte> rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
29 Debug.Assert(password != null);
31 X509ContentType contentType = X509Certificate2.GetCertContentType(rawData);
33 if (contentType == X509ContentType.Pkcs12)
35 if ((keyStorageFlags & X509KeyStorageFlags.EphemeralKeySet) == X509KeyStorageFlags.EphemeralKeySet)
37 throw new PlatformNotSupportedException(SR.Cryptography_X509_NoEphemeralPfx);
40 bool exportable = (keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable;
43 (keyStorageFlags & X509KeyStorageFlags.PersistKeySet) == X509KeyStorageFlags.PersistKeySet;
45 SafeKeychainHandle keychain = persist
46 ? Interop.AppleCrypto.SecKeychainCopyDefault()
47 : Interop.AppleCrypto.CreateTemporaryKeychain();
49 return ImportPkcs12(rawData, password, exportable, ephemeralSpecified: false, keychain);
52 SafeCFArrayHandle certs = Interop.AppleCrypto.X509ImportCollection(
56 SafeTemporaryKeychainHandle.InvalidHandle,
59 return new AppleCertLoader(certs, null);
62 private static ILoaderPal ImportPkcs12(
63 ReadOnlySpan<byte> rawData,
64 SafePasswordHandle password,
66 bool ephemeralSpecified,
67 SafeKeychainHandle keychain)
69 ApplePkcs12Reader reader = new ApplePkcs12Reader(rawData);
73 reader.Decrypt(password, ephemeralSpecified);
74 return new ApplePkcs12CertLoader(reader, keychain, password, exportable);
84 internal static partial ILoaderPal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
86 Debug.Assert(password != null);
88 byte[] fileBytes = File.ReadAllBytes(fileName);
89 return FromBlob(fileBytes, password, keyStorageFlags);
92 internal static partial IExportPal FromCertificate(ICertificatePalCore cert)
94 return new AppleCertificateExporter(cert);
97 internal static partial IExportPal LinkFromCertificateCollection(X509Certificate2Collection certificates)
99 return new AppleCertificateExporter(certificates);
102 internal static partial IStorePal FromSystemStore(string storeName, StoreLocation storeLocation, OpenFlags openFlags)
104 StringComparer ordinalIgnoreCase = StringComparer.OrdinalIgnoreCase;
106 switch (storeLocation)
108 case StoreLocation.CurrentUser:
109 if (ordinalIgnoreCase.Equals("My", storeName))
110 return AppleKeychainStore.OpenDefaultKeychain(openFlags);
111 if (ordinalIgnoreCase.Equals("Root", storeName))
112 return AppleTrustStore.OpenStore(StoreName.Root, storeLocation, openFlags);
113 if (ordinalIgnoreCase.Equals("Disallowed", storeName))
114 return AppleTrustStore.OpenStore(StoreName.Disallowed, storeLocation, openFlags);
115 return FromCustomKeychainStore(storeName, openFlags);
117 case StoreLocation.LocalMachine:
118 if (ordinalIgnoreCase.Equals("My", storeName))
119 return AppleKeychainStore.OpenSystemSharedKeychain(openFlags);
120 if (ordinalIgnoreCase.Equals("Root", storeName))
121 return AppleTrustStore.OpenStore(StoreName.Root, storeLocation, openFlags);
122 if (ordinalIgnoreCase.Equals("Disallowed", storeName))
123 return AppleTrustStore.OpenStore(StoreName.Disallowed, storeLocation, openFlags);
127 if ((openFlags & OpenFlags.OpenExistingOnly) == OpenFlags.OpenExistingOnly)
128 throw new CryptographicException(SR.Cryptography_X509_StoreNotFound);
130 string message = SR.Format(
131 SR.Cryptography_X509_StoreCannotCreate,
135 throw new CryptographicException(message, new PlatformNotSupportedException(message));
138 private static IStorePal FromCustomKeychainStore(string storeName, OpenFlags openFlags)
142 if (!IsValidStoreName(storeName))
143 throw new CryptographicException(SR.Format(SR.Security_InvalidValue, nameof(storeName)));
145 storePath = Path.Combine(
146 Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
149 storeName.ToLowerInvariant() + ".keychain");
151 return AppleKeychainStore.CreateOrOpenKeychain(storePath, openFlags);
154 private static bool IsValidStoreName(string storeName)
158 return !string.IsNullOrWhiteSpace(storeName) && Path.GetFileName(storeName) == storeName;
166 private static void ReadCollection(SafeCFArrayHandle matches, HashSet<X509Certificate2> collection)
168 if (matches.IsInvalid)
173 long count = Interop.CoreFoundation.CFArrayGetCount(matches);
175 for (int i = 0; i < count; i++)
177 IntPtr handle = Interop.CoreFoundation.CFArrayGetValueAtIndex(matches, i);
179 SafeSecCertificateHandle certHandle;
180 SafeSecIdentityHandle identityHandle;
182 if (Interop.AppleCrypto.X509DemuxAndRetainHandle(handle, out certHandle, out identityHandle))
184 X509Certificate2 cert;
186 if (certHandle.IsInvalid)
188 certHandle.Dispose();
189 cert = new X509Certificate2(new AppleCertificatePal(identityHandle));
193 identityHandle.Dispose();
194 cert = new X509Certificate2(new AppleCertificatePal(certHandle));
197 if (!collection.Add(cert))