Пример #1
0
        public static void RevocationCheckingMaximum(PkiOptions pkiOptions)
        {
            // Windows 10 has a different maximum from previous versions of Windows.
            // We are primarily testing that Linux behavior matches some behavior of
            // Windows, so we won't test except on Windows 10.
            if (PlatformDetection.WindowsVersion < 10)
            {
                return;
            }

            CertificateAuthority.BuildPrivatePki(
                pkiOptions,
                out RevocationResponder responder,
                out CertificateAuthority rootAuthority,
                out CertificateAuthority intermediateAuthority,
                out X509Certificate2 endEntityCert,
                nameof(RevocationCheckingMaximum));

            using (responder)
            using (rootAuthority)
            using (intermediateAuthority)
            using (endEntityCert)
            using (ChainHolder holder = new ChainHolder())
            using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
            using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
            {
                TimeSpan delay = TimeSpan.FromMinutes(1.5);

                X509Chain chain = holder.Chain;
                responder.ResponseDelay = delay;
                responder.DelayedActions = DelayedActionsFlag.All;

                chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromMinutes(2);
                chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
                chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly;

                chain.ChainPolicy.DisableCertificateDownloads = true;

                // Even though UrlRetrievalTimeout is more than the delay, it should
                // get clamped to 1 minute, and thus less than the actual delay.
                Assert.False(chain.Build(endEntityCert), "chain.Build");

                const X509ChainStatusFlags ExpectedFlags =
                    X509ChainStatusFlags.RevocationStatusUnknown |
                    X509ChainStatusFlags.OfflineRevocation;

                X509ChainStatusFlags eeFlags = GetFlags(chain, endEntityCert.Thumbprint);
                Assert.Equal(ExpectedFlags, eeFlags);
            }
        }
Пример #2
0
        public static void RevocationCheckingDelayed(PkiOptions pkiOptions)
        {
            RetryHelper.Execute(() => {
                CertificateAuthority.BuildPrivatePki(
                    pkiOptions,
                    out RevocationResponder responder,
                    out CertificateAuthority rootAuthority,
                    out CertificateAuthority intermediateAuthority,
                    out X509Certificate2 endEntityCert,
                    nameof(RevocationCheckingDelayed));

                using (responder)
                using (rootAuthority)
                using (intermediateAuthority)
                using (endEntityCert)
                using (ChainHolder holder = new ChainHolder())
                using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
                using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
                {
                    TimeSpan delay = TimeSpan.FromSeconds(8);

                    X509Chain chain = holder.Chain;
                    responder.ResponseDelay = delay;
                    responder.DelayedActions = DelayedActionsFlag.All;

                    // This needs to be greater than delay, but less than 2x delay to ensure
                    // that the time is a timeout for individual fetches, not a running total.
                    chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15);
                    chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
                    chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                    chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                    chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;

                    chain.ChainPolicy.DisableCertificateDownloads = true;

                    Stopwatch watch = Stopwatch.StartNew();
                    Assert.True(chain.Build(endEntityCert),  $"chain.Build; Chain status: {chain.AllStatusFlags()}");
                    watch.Stop();

                    // There should be two network fetches, OCSP/CRL to intermediate to get leaf status,
                    // OCSP/CRL to root to get intermediate statuses. It should take at least 2x the delay
                    // plus other non-network time, so we can at least ensure it took as long as
                    // the delay for each fetch.
                    // We expect the chain to build in at least 16 seconds (2 * delay) since each fetch
                    // should take `delay` number of seconds, and there are two fetchs that need to be
                    // performed. We allow a small amount of leeway to account for differences between
                    // how long the delay is performed and the stopwatch.
                    Assert.True(watch.Elapsed >= delay * 2 - TimeSpan.FromSeconds(1), $"watch.Elapsed: {watch.Elapsed}");
                }
            });
        }
Пример #3
0
        public static void RevocationCheckingDelayed(PkiOptions pkiOptions)
        {
            CertificateAuthority.BuildPrivatePki(
                pkiOptions,
                out RevocationResponder responder,
                out CertificateAuthority rootAuthority,
                out CertificateAuthority intermediateAuthority,
                out X509Certificate2 endEntityCert,
                nameof(RevocationCheckingDelayed));

            using (responder)
                using (rootAuthority)
                    using (intermediateAuthority)
                        using (endEntityCert)
                            using (ChainHolder holder = new ChainHolder())
                                using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
                                    using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
                                    {
                                        TimeSpan delay = TimeSpan.FromSeconds(3);

                                        X509Chain chain = holder.Chain;
                                        responder.ResponseDelay  = delay;
                                        responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All;

                                        // This needs to be greater than delay, but less than 2x delay to ensure
                                        // that the time is a timeout for individual fetches, not a running total.
                                        chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(5);
                                        chain.ChainPolicy.TrustMode           = X509ChainTrustMode.CustomRootTrust;
                                        chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                                        chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                                        chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                                        chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;

                                        chain.ChainPolicy.DisableCertificateDownloads = true;

                                        Stopwatch watch = Stopwatch.StartNew();
                                        Assert.True(chain.Build(endEntityCert));
                                        watch.Stop();

                                        // There should be two network fetches, OCSP/CRL to intermediate to get leaf status,
                                        // OCSP/CRL to root to get intermediate statuses. It should take at least 2x the delay
                                        // plus other non-network time, so we can at least ensure it took as long as
                                        // the delay for each fetch.
                                        Assert.True(watch.Elapsed >= delay * 2);
                                    }
        }
Пример #4
0
        public static void RevocationCheckingTimeout(PkiOptions pkiOptions)
        {
            CertificateAuthority.BuildPrivatePki(
                pkiOptions,
                out RevocationResponder responder,
                out CertificateAuthority rootAuthority,
                out CertificateAuthority intermediateAuthority,
                out X509Certificate2 endEntityCert,
                nameof(RevocationCheckingTimeout));

            using (responder)
            using (rootAuthority)
            using (intermediateAuthority)
            using (endEntityCert)
            using (ChainHolder holder = new ChainHolder())
            using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
            using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
            {
                TimeSpan delay = TimeSpan.FromSeconds(3);

                X509Chain chain = holder.Chain;
                responder.ResponseDelay = delay;
                responder.DelayedActions = DelayedActionsFlag.All;

                chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(1);
                chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
                chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;

                chain.ChainPolicy.DisableCertificateDownloads = true;

                Assert.False(chain.Build(endEntityCert), "chain.Build");

                const X509ChainStatusFlags ExpectedFlags =
                    X509ChainStatusFlags.RevocationStatusUnknown |
                    X509ChainStatusFlags.OfflineRevocation;

                X509ChainStatusFlags eeFlags = GetFlags(chain, endEntityCert.Thumbprint);
                X509ChainStatusFlags intermediateFlags = GetFlags(chain, intermediateCert.Thumbprint);
                Assert.Equal(ExpectedFlags, eeFlags);
                Assert.Equal(ExpectedFlags, intermediateFlags);
            }
        }
Пример #5
0
        public static void AiaFetchDelayed()
        {
            CertificateAuthority.BuildPrivatePki(
                PkiOptions.OcspEverywhere,
                out RevocationResponder responder,
                out CertificateAuthority rootAuthority,
                out CertificateAuthority intermediateAuthority,
                out X509Certificate2 endEntityCert,
                nameof(AiaFetchDelayed));

            using (responder)
                using (rootAuthority)
                    using (intermediateAuthority)
                        using (endEntityCert)
                            using (ChainHolder holder = new ChainHolder())
                                using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
                                    using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
                                    {
                                        TimeSpan delay = TimeSpan.FromSeconds(1);

                                        X509Chain chain = holder.Chain;
                                        responder.ResponseDelay  = delay;
                                        responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All;

                                        chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15);
                                        chain.ChainPolicy.TrustMode           = X509ChainTrustMode.CustomRootTrust;
                                        chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                                        chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                                        Stopwatch watch = Stopwatch.StartNew();
                                        Assert.True(
                                            Retry(() =>
                                        {
                                            watch.Restart();
                                            return(chain.Build(endEntityCert));
                                        }),
                                            GetFlags(chain, endEntityCert.Thumbprint).ToString());
                                        watch.Stop();

                                        Assert.True(watch.Elapsed >= delay, $"watch.Elapsed: {watch.Elapsed}");
                                    }
        }
Пример #6
0
        public static void RevocationCheckingNegativeTimeout(PkiOptions pkiOptions)
        {
            RetryHelper.Execute(() => {
                CertificateAuthority.BuildPrivatePki(
                    pkiOptions,
                    out RevocationResponder responder,
                    out CertificateAuthority rootAuthority,
                    out CertificateAuthority intermediateAuthority,
                    out X509Certificate2 endEntityCert,
                    nameof(RevocationCheckingNegativeTimeout));

                using (responder)
                using (rootAuthority)
                using (intermediateAuthority)
                using (endEntityCert)
                using (ChainHolder holder = new ChainHolder())
                using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
                using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
                {
                    // Delay is more than the 15 second default.
                    TimeSpan delay = TimeSpan.FromSeconds(25);

                    X509Chain chain = holder.Chain;
                    responder.ResponseDelay = delay;
                    responder.DelayedActions = DelayedActionsFlag.All;

                    chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromMinutes(-1);
                    chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
                    chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                    chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                    chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly;

                    chain.ChainPolicy.DisableCertificateDownloads = true;

                    Assert.True(chain.Build(endEntityCert), $"chain.Build; Chain status: {chain.AllStatusFlags()}");
                }
            });
        }
Пример #7
0
        public static void AiaFetchTimeout()
        {
            CertificateAuthority.BuildPrivatePki(
                PkiOptions.AllRevocation,
                out RevocationResponder responder,
                out CertificateAuthority rootAuthority,
                out CertificateAuthority intermediateAuthority,
                out X509Certificate2 endEntityCert,
                nameof(AiaFetchTimeout));

            using (responder)
            using (rootAuthority)
            using (intermediateAuthority)
            using (endEntityCert)
            using (ChainHolder holder = new ChainHolder())
            using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
            using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
            {
                TimeSpan delay = TimeSpan.FromSeconds(10);

                X509Chain chain = holder.Chain;
                responder.ResponseDelay = delay;
                responder.DelayedActions = DelayedActionsFlag.All;

                chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(2);
                chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
                chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                Assert.False(chain.Build(endEntityCert), "chain.Build");

                const X509ChainStatusFlags ExpectedFlags =
                    X509ChainStatusFlags.PartialChain;

                X509ChainStatusFlags eeFlags = GetFlags(chain, endEntityCert.Thumbprint);
                Assert.Equal(ExpectedFlags, eeFlags);
            }
        }
Пример #8
0
        public static void RevocationCheckingTimeoutFallbackToOther(DelayedActionsFlag delayFlags)
        {
            RetryHelper.Execute(() => {
                CertificateAuthority.BuildPrivatePki(
                    PkiOptions.AllRevocation,
                    out RevocationResponder responder,
                    out CertificateAuthority rootAuthority,
                    out CertificateAuthority intermediateAuthority,
                    out X509Certificate2 endEntityCert,
                    nameof(RevocationCheckingTimeoutFallbackToOther));

                using (responder)
                using (rootAuthority)
                using (intermediateAuthority)
                using (endEntityCert)
                using (ChainHolder holder = new ChainHolder())
                using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
                using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
                {
                    X509Chain chain = holder.Chain;
                    responder.ResponseDelay = TimeSpan.FromSeconds(8);
                    responder.DelayedActions = delayFlags;

                    chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(4);
                    chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
                    chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                    chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                    chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly;

                    chain.ChainPolicy.DisableCertificateDownloads = true;

                    Assert.True(chain.Build(endEntityCert), $"chain.Build; Chain status: {chain.AllStatusFlags()}");
                }
            });
        }
        public static void DisableAiaOptionWorks()
        {
            CertificateAuthority.BuildPrivatePki(
                PkiOptions.AllRevocation,
                out RevocationResponder responder,
                out CertificateAuthority root,
                out CertificateAuthority intermediate,
                out X509Certificate2 endEntity,
                pkiOptionsInSubject: false);

            using (responder)
                using (root)
                    using (intermediate)
                        using (endEntity)
                            using (ChainHolder holder = new ChainHolder())
                                using (X509Certificate2 rootCert = root.CloneIssuerCert())
                                    using (X509Certificate2 intermediateCert = intermediate.CloneIssuerCert())
                                        using (var cuCaStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser))
                                        {
                                            cuCaStore.Open(OpenFlags.ReadWrite);

                                            X509Chain chain = holder.Chain;
                                            chain.ChainPolicy.DisableCertificateDownloads = true;
                                            chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                                            chain.ChainPolicy.TrustMode           = X509ChainTrustMode.CustomRootTrust;
                                            chain.ChainPolicy.VerificationTime    = endEntity.NotBefore.AddMinutes(1);
                                            chain.ChainPolicy.UrlRetrievalTimeout = DynamicRevocationTests.s_urlRetrievalLimit;

                                            Assert.False(chain.Build(endEntity), "Chain build with no intermediate, AIA disabled");

                                            // If a previous run of this test leaves contamination in the CU\CA store on Windows
                                            // the Windows chain engine will match the bad issuer and report NotSignatureValid instead
                                            // of PartialChain.
                                            X509ChainStatusFlags chainFlags = chain.AllStatusFlags();

                                            if (chainFlags.HasFlag(X509ChainStatusFlags.NotSignatureValid))
                                            {
                                                Assert.Equal(3, chain.ChainElements.Count);

                                                foreach (X509Certificate2 storeCert in cuCaStore.Certificates)
                                                {
                                                    if (storeCert.Subject.Equals(intermediateCert.Subject))
                                                    {
                                                        cuCaStore.Remove(storeCert);
                                                    }

                                                    storeCert.Dispose();
                                                }

                                                holder.DisposeChainElements();

                                                // Try again, with no caching side effect.
                                                Assert.False(chain.Build(endEntity), "Chain build 2 with no intermediate, AIA disabled");
                                            }

                                            Assert.Equal(1, chain.ChainElements.Count);
                                            Assert.Contains(X509ChainStatusFlags.PartialChain, chain.ChainStatus.Select(s => s.Status));
                                            holder.DisposeChainElements();

                                            // macOS doesn't like our revocation responder, so disable revocation checks there.
                                            if (PlatformDetection.IsOSX)
                                            {
                                                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                                            }

                                            chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                                            Assert.True(chain.Build(endEntity), "Chain build with intermediate, AIA disabled");
                                            Assert.Equal(3, chain.ChainElements.Count);
                                            Assert.Equal(X509ChainStatusFlags.NoError, chain.AllStatusFlags());
                                            holder.DisposeChainElements();

                                            chain.ChainPolicy.DisableCertificateDownloads = false;
                                            chain.ChainPolicy.ExtraStore.Clear();
                                            Assert.True(chain.Build(endEntity), "Chain build with no intermediate, AIA enabled");
                                            Assert.Equal(3, chain.ChainElements.Count);
                                            Assert.Equal(X509ChainStatusFlags.NoError, chain.AllStatusFlags());

                                            cuCaStore.Remove(intermediateCert);
                                        }
        }