Exemplo n.º 1
0
        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.
                }
            }
        }
Exemplo n.º 2
0
        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));
        }
Exemplo n.º 5
0
        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.
                }
            }
        }