private static void RunX509StoreTest(Action <X509Store, string> testAction) { string certStoresFeaturePath = PersistedFiles.GetUserFeatureDirectory("cryptography", "x509stores"); string storeName = "TestStore" + Guid.NewGuid().ToString("N"); string storeDirectory = Path.Combine(certStoresFeaturePath, storeName.ToLowerInvariant()); if (Directory.Exists(storeDirectory)) { Directory.Delete(storeDirectory, true); } try { using (X509Store store = new X509Store(storeName, StoreLocation.CurrentUser)) { testAction(store, storeDirectory); } } finally { try { if (Directory.Exists(storeDirectory)) { Directory.Delete(storeDirectory, true); } } catch { // Don't allow any (additional?) I/O errors to propagate. } } }
private static string GetCachedCrlPath(X509Certificate2 cert, bool mkDir = false) { OpenSslX509CertificateReader pal = (OpenSslX509CertificateReader)cert.Pal; string crlDir = PersistedFiles.GetUserFeatureDirectory( X509Persistence.CryptographyFeatureName, X509Persistence.CrlsSubFeatureName); // X509_issuer_name_hash returns "unsigned long", which is marshalled as ulong. // But it only sets 32 bits worth of data, so force it down to uint just... in case. ulong persistentHashLong = Interop.Crypto.X509IssuerNameHash(pal.SafeHandle); if (persistentHashLong == 0) { Interop.Crypto.ErrClearError(); } uint persistentHash = unchecked ((uint)persistentHashLong); // OpenSSL's hashed filename algorithm is the 8-character hex version of the 32-bit value // of X509_issuer_name_hash (or X509_subject_name_hash, depending on the context). string localFileName = persistentHash.ToString("x8") + ".crl"; if (mkDir) { Directory.CreateDirectory(crlDir); } return(Path.Combine(crlDir, localFileName)); }
public static void VerifyCrlCache() { string crlDirectory = PersistedFiles.GetUserFeatureDirectory("cryptography", "crls"); string crlFile = Path.Combine(crlDirectory, MicrosoftDotComRootCrlFilename); Directory.CreateDirectory(crlDirectory); File.Delete(crlFile); using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes)) using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes)) using (var unrelated = new X509Certificate2(TestData.DssCer)) using (var chainHolder = new ChainHolder()) { X509Chain chain = chainHolder.Chain; chain.ChainPolicy.ExtraStore.Add(unrelated); chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot); // The very start of the CRL period. chain.ChainPolicy.VerificationTime = new DateTime(2015, 6, 17, 0, 0, 0, DateTimeKind.Utc); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly; chain.ChainPolicy.VerificationFlags |= X509VerificationFlags.AllowUnknownCertificateAuthority; bool valid = chain.Build(microsoftDotComIssuer); Assert.True(valid, "Precondition: Chain builds with no revocation checks"); int initialErrorCount = chain.ChainStatus.Length; Assert.InRange(initialErrorCount, 0, 1); X509ChainStatusFlags initialFlags = chain.AllStatusFlags(); if (initialFlags != X509ChainStatusFlags.NoError) { Assert.Equal(X509ChainStatusFlags.UntrustedRoot, initialFlags); } chainHolder.DisposeChainElements(); chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; valid = chain.Build(microsoftDotComIssuer); Assert.False(valid, "Chain should not build validly"); const X509ChainStatusFlags UnknownOffline = X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation; Assert.Equal(initialFlags | UnknownOffline, chain.AllStatusFlags()); File.WriteAllText(crlFile, MicrosoftDotComRootCrlPem, Encoding.ASCII); chainHolder.DisposeChainElements(); valid = chain.Build(microsoftDotComIssuer); Assert.True(valid, "Chain should build validly now"); Assert.Equal(initialErrorCount, chain.ChainStatus.Length); } }
internal static string GetStorePath(string storeName) { string directoryName = GetDirectoryName(storeName); // Do this here instead of a static field initializer so that // the static initializer isn't capable of throwing the "home directory not found" // exception. s_userStoreRoot ??= PersistedFiles.GetUserFeatureDirectory( X509Persistence.CryptographyFeatureName, X509Persistence.X509StoresSubFeatureName); return(Path.Combine(s_userStoreRoot, directoryName)); }
public static void VerifyCrlCache() { string crlDirectory = PersistedFiles.GetUserFeatureDirectory("cryptography", "crls"); string crlFile = Path.Combine(crlDirectory, MicrosoftDotComRootCrlFilename); Directory.CreateDirectory(crlDirectory); File.Delete(crlFile); using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes)) using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes)) using (var unrelated = new X509Certificate2(TestData.DssCer)) { X509Chain chain = new X509Chain(); chain.ChainPolicy.ExtraStore.Add(unrelated); chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot); // The very start of the CRL period. chain.ChainPolicy.VerificationTime = new DateTime(2015, 6, 17, 0, 0, 0, DateTimeKind.Utc); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly; bool valid = chain.Build(microsoftDotComIssuer); Assert.True(valid, "Precondition: Chain builds with no revocation checks"); chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; valid = chain.Build(microsoftDotComIssuer); Assert.False(valid, "Chain should not build validly"); Assert.Equal(1, chain.ChainStatus.Length); Assert.Equal(X509ChainStatusFlags.RevocationStatusUnknown, chain.ChainStatus[0].Status); File.WriteAllText(crlFile, MicrosoftDotComRootCrlPem, Encoding.ASCII); valid = chain.Build(microsoftDotComIssuer); Assert.True(valid, "Chain should build validly now"); Assert.Equal(0, chain.ChainStatus.Length); // Rewind one second, the CRL is not "not yet valid" chain.ChainPolicy.VerificationTime = chain.ChainPolicy.VerificationTime.Subtract(TimeSpan.FromSeconds(1)); valid = chain.Build(microsoftDotComIssuer); Assert.False(valid, "Chain should not build validly, CRL is not yet valid"); Assert.Equal(1, chain.ChainStatus.Length); Assert.Equal(X509ChainStatusFlags.RevocationStatusUnknown, chain.ChainStatus[0].Status); } }
internal DirectoryBasedStoreProvider(string storeName, OpenFlags openFlags) { if (string.IsNullOrEmpty(storeName)) { throw new CryptographicException(SR.Arg_EmptyOrNullString); } string directoryName = GetDirectoryName(storeName); if (s_userStoreRoot == null) { // Do this here instead of a static field initializer so that // the static initializer isn't capable of throwing the "home directory not found" // exception. s_userStoreRoot = PersistedFiles.GetUserFeatureDirectory( X509Persistence.CryptographyFeatureName, X509Persistence.X509StoresSubFeatureName); } _storePath = Path.Combine(s_userStoreRoot, directoryName); if (0 != (openFlags & OpenFlags.OpenExistingOnly)) { if (!Directory.Exists(_storePath)) { throw new CryptographicException(SR.Cryptography_X509_StoreNotFound); } } // ReadOnly is 0x00, so it is implicit unless either ReadWrite or MaxAllowed // was requested. OpenFlags writeFlags = openFlags & (OpenFlags.ReadWrite | OpenFlags.MaxAllowed); if (writeFlags == OpenFlags.ReadOnly) { _readOnly = true; } }
private static bool DetermineCanModifyStores() { // Check the directory permissions and whether the filesystem supports chmod. // The only real expected failure from this method is that at the very end // `stat.Mode == mode` will fail, because fuseblk (NTFS) returns success on chmod, // but is a no-op. uint userId = Interop.Sys.GetEUid(); string certStoresFeaturePath = PersistedFiles.GetUserFeatureDirectory("cryptography", "x509stores"); Directory.CreateDirectory(certStoresFeaturePath); // Check directory permissions: Interop.Sys.FileStatus dirStat; if (Interop.Sys.Stat(certStoresFeaturePath, out dirStat) != 0) { return(false); } if (dirStat.Uid != userId) { return(false); } if ((dirStat.Mode & (int)Interop.Sys.Permissions.S_IRWXU) != (int)Interop.Sys.Permissions.S_IRWXU) { return(false); } string probeFilename = Path.Combine(certStoresFeaturePath, $"{Guid.NewGuid().ToString("N")}.chmod"); try { using (FileStream stream = new FileStream(probeFilename, FileMode.Create)) { Interop.Sys.FileStatus stat; if (Interop.Sys.FStat(stream.SafeFileHandle, out stat) != 0) { return(false); } if (stat.Uid != userId) { return(false); } // The product code here has a lot of stuff it does. // This capabilities probe will just check that chmod works. int mode = stat.Mode; // Flip all of the O bits. mode ^= (int)Interop.Sys.Permissions.S_IRWXO; if (Interop.Sys.FChMod(stream.SafeFileHandle, mode) < 0) { return(false); } // Verify the chmod applied. if (Interop.Sys.FStat(stream.SafeFileHandle, out stat) != 0) { return(false); } // On fuseblk (NTFS) this will return false, because the fchmod // call returned success without being able to actually apply // mode-bits. return(stat.Mode == mode); } } finally { try { File.Delete(probeFilename); } catch { // Ignore any failure on delete. } } }