A type to extend the Dispose on X509Chain to also dispose all of the X509Certificate objects in the ChainElements structure.
Наследование: IDisposable
Пример #1
0
        public static void BuildChain()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            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);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;

                // Halfway between microsoftDotCom's NotBefore and NotAfter
                // This isn't a boundary condition test.
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(microsoftDotCom);
                Assert.True(valid, "Chain built validly");

                // The chain should have 3 members
                Assert.Equal(3, chain.ChainElements.Count);

                // These are the three specific members.
                Assert.Equal(microsoftDotCom, chain.ChainElements[0].Certificate);
                Assert.Equal(microsoftDotComIssuer, chain.ChainElements[1].Certificate);
                Assert.Equal(microsoftDotComRoot, chain.ChainElements[2].Certificate);
            }
        }
Пример #2
0
        public static void VerifyExpiration_LocalTime(DateTime verificationTime, bool shouldBeValid, DateTimeKind kind)
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
                using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes))
                    using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
                        using (var chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;

                            chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                            chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot);

                            // Ignore anything except NotTimeValid
                            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags & ~X509VerificationFlags.IgnoreNotTimeValid;
                            chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationTime  = verificationTime;

                            bool builtSuccessfully = chain.Build(microsoftDotCom);

                            Assert.Equal(shouldBeValid, builtSuccessfully);

                            // If we failed to build the chain, ensure that NotTimeValid is one of the reasons.
                            if (!shouldBeValid)
                            {
                                Assert.Contains(chain.ChainStatus, s => s.Status == X509ChainStatusFlags.NotTimeValid);
                            }
                        }
        }
Пример #3
0
        public static void BuildChain()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
                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);
                                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;

                                // Halfway between microsoftDotCom's NotBefore and NotAfter
                                // This isn't a boundary condition test.
                                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                                chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;

                                bool valid = chain.Build(microsoftDotCom);
                                Assert.True(valid, "Chain built validly");

                                // The chain should have 3 members
                                Assert.Equal(3, chain.ChainElements.Count);

                                // These are the three specific members.
                                Assert.Equal(microsoftDotCom, chain.ChainElements[0].Certificate);
                                Assert.Equal(microsoftDotComIssuer, chain.ChainElements[1].Certificate);
                                Assert.Equal(microsoftDotComRoot, chain.ChainElements[2].Certificate);
                            }
        }
Пример #4
0
        public static void BuildChain_WithCertificatePolicy_NoMatch()
        {
            using (var cert = new X509Certificate2(TestData.CertWithPolicies))
                using (var chainHolder = new ChainHolder())
                {
                    X509Chain chain = chainHolder.Chain;

                    chain.ChainPolicy.CertificatePolicy.Add(new Oid("2.999"));
                    chain.ChainPolicy.VerificationFlags =
                        X509VerificationFlags.AllowUnknownCertificateAuthority;

                    chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                    chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);

                    bool valid = chain.Build(cert);
                    Assert.False(valid, "Chain built validly");

                    Assert.InRange(chain.ChainElements.Count, 1, int.MaxValue);

                    Assert.NotSame(cert, chain.ChainElements[0].Certificate);
                    Assert.Equal(cert, chain.ChainElements[0].Certificate);

                    X509ChainStatus[] chainElementStatus = chain.ChainElements[0].ChainElementStatus;
                    Assert.InRange(chainElementStatus.Length, 1, int.MaxValue);
                    Assert.Contains(chainElementStatus, x => x.Status == X509ChainStatusFlags.NotValidForUsage);
                }
        }
Пример #5
0
        public static void TestResetMethod()
        {
            using (var sampleCert = new X509Certificate2(TestData.DssCer))
                using (var chainHolder = new ChainHolder())
                {
                    X509Chain chain = chainHolder.Chain;

                    chain.ChainPolicy.ExtraStore.Add(sampleCert);
                    bool valid = chain.Build(sampleCert);
                    Assert.False(valid);
                    chainHolder.DisposeChainElements();

                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                    chain.ChainPolicy.VerificationTime  = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;

                    valid = chain.Build(sampleCert);
                    Assert.True(valid, "Chain built validly");

                    Assert.Equal(1, chain.ChainElements.Count);
                    chainHolder.DisposeChainElements();

                    chain.Reset();
                    Assert.Equal(0, chain.ChainElements.Count);

                    // ChainPolicy did not reset (for desktop compat)
                    Assert.Equal(X509VerificationFlags.AllowUnknownCertificateAuthority, chain.ChainPolicy.VerificationFlags);

                    valid = chain.Build(sampleCert);
                    Assert.Equal(1, chain.ChainElements.Count);
                    // This succeeds because ChainPolicy did not reset
                    Assert.True(valid, "Chain built validly after reset");
                }
        }
Пример #6
0
        public static void CustomRootTrustDoesNotTrustIntermediates(
            bool saveAllInCustomTrustStore,
            X509ChainStatusFlags chainFlags)
        {
            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert);

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
                            chain.ChainPolicy.TrustMode        = X509ChainTrustMode.CustomRootTrust;
                            chain.ChainPolicy.CustomTrustStore.Add(intermediateCert);

                            if (saveAllInCustomTrustStore)
                            {
                                chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                            }
                            else
                            {
                                chain.ChainPolicy.ExtraStore.Add(rootCert);
                            }

                            Assert.Equal(saveAllInCustomTrustStore, chain.Build(endEntityCert));
                            Assert.Equal(3, chain.ChainElements.Count);
                            Assert.Equal(chainFlags, chain.AllStatusFlags());
                        }
        }
Пример #7
0
        public static void CustomTrustModeWithNoCustomTrustCerts()
        {
            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert);

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
                            chain.ChainPolicy.TrustMode        = X509ChainTrustMode.CustomRootTrust;

                            if (PlatformDetection.IsAndroid)
                            {
                                // Android does not support an empty custom root trust
                                Assert.Throws <PlatformNotSupportedException>(() => chain.Build(endEntityCert));
                            }
                            else
                            {
                                Assert.False(chain.Build(endEntityCert));
                                Assert.Equal(1, chain.ChainElements.Count);
                                Assert.Equal(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags());
                            }
                        }
        }
Пример #8
0
        public static void TestLeafCertificateWithUnknownCriticalExtension()
        {
            using (RSA key = RSA.Create())
            {
                CertificateRequest certReq = new CertificateRequest(
                    new X500DistinguishedName("CN=Cert"),
                    key,
                    HashAlgorithmName.SHA256,
                    RSASignaturePadding.Pkcs1);

                const string PrecertificatePoisonExtensionOid = "1.3.6.1.4.1.11129.2.4.3";
                certReq.CertificateExtensions.Add(new X509Extension(
                                                      new AsnEncodedData(
                                                          new Oid(PrecertificatePoisonExtensionOid),
                                                          new byte[] { 5, 0 }),
                                                      critical: true));

                DateTimeOffset notBefore = DateTimeOffset.UtcNow.AddDays(-1);
                DateTimeOffset notAfter  = notBefore.AddDays(30);

                using (X509Certificate2 cert = certReq.CreateSelfSigned(notBefore, notAfter))
                    using (ChainHolder holder = new ChainHolder())
                    {
                        X509Chain chain = holder.Chain;
                        chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                        Assert.False(chain.Build(cert));

                        X509ChainElement           certElement  = chain.ChainElements.OfType <X509ChainElement>().Single();
                        const X509ChainStatusFlags ExpectedFlag = X509ChainStatusFlags.HasNotSupportedCriticalExtension;
                        X509ChainStatusFlags       actualFlags  = certElement.AllStatusFlags();
                        Assert.True((actualFlags & ExpectedFlag) == ExpectedFlag, $"Has expected flag {ExpectedFlag} but was {actualFlags}");
                    }
            }
        }
Пример #9
0
        public static void BasicConstraints_ViolatesCaFalse()
        {
            X509Extension[] intermediateExtensions = new [] {
                new X509BasicConstraintsExtension(
                    certificateAuthority: false,
                    hasPathLengthConstraint: false,
                    pathLengthConstraint: 0,
                    critical: true)
            };

            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert,
                intermediateExtensions: intermediateExtensions);

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
                            chain.ChainPolicy.TrustMode        = X509ChainTrustMode.CustomRootTrust;
                            chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                            chain.ChainPolicy.ExtraStore.Add(intermediateCert);

                            Assert.False(chain.Build(endEntityCert));
                            Assert.Equal(X509ChainStatusFlags.InvalidBasicConstraints, chain.AllStatusFlags());
                        }
        }
        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);
                        }
        }
Пример #11
0
        public static void InvalidSelfSignedSignature()
        {
            X509ChainStatusFlags expectedFlags;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                expectedFlags = X509ChainStatusFlags.NotSignatureValid;
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // For OSX alone expectedFlags here means OR instead of AND.
                // Because the error code changed in 10.13.4 from UntrustedRoot to PartialChain
                // and we handle that later in this test.
                expectedFlags =
                    X509ChainStatusFlags.UntrustedRoot |
                    X509ChainStatusFlags.PartialChain;
            }
            else
            {
                expectedFlags =
                    X509ChainStatusFlags.NotSignatureValid |
                    X509ChainStatusFlags.UntrustedRoot;
            }

            byte[] certBytes = (byte[])TestData.MicrosoftDotComRootBytes.Clone();
            // The signature goes up to the very last byte, so flip some bits in it.
            certBytes[certBytes.Length - 1] ^= 0xFF;

            using (var cert = new X509Certificate2(certBytes))
                using (ChainHolder holder = new ChainHolder())
                {
                    X509Chain       chain  = holder.Chain;
                    X509ChainPolicy policy = chain.ChainPolicy;
                    policy.VerificationTime = cert.NotBefore.AddDays(3);
                    policy.RevocationMode   = X509RevocationMode.NoCheck;

                    chain.Build(cert);

                    X509ChainStatusFlags allFlags =
                        chain.ChainStatus.Select(cs => cs.Status).Aggregate(
                            X509ChainStatusFlags.NoError,
                            (a, b) => a | b);

                    if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                    {
                        // If we're on 10.13.3 or older we get UntrustedRoot.
                        // If we're on 10.13.4 or newer we get PartialChain.
                        //
                        // So make the expectedValue be whichever of those two is set.
                        expectedFlags = (expectedFlags & allFlags);
                        // One of them has to be set.
                        Assert.NotEqual(X509ChainStatusFlags.NoError, expectedFlags);
                        // Continue executing now to ensure that no other unexpected flags were set.
                    }

                    Assert.Equal(expectedFlags, allFlags);
                }
        }
Пример #12
0
        public static void MismatchKeyIdentifiers()
        {
            X509Extension[] intermediateExtensions = new [] {
                new X509BasicConstraintsExtension(
                    certificateAuthority: true,
                    hasPathLengthConstraint: false,
                    pathLengthConstraint: 0,
                    critical: true),
                new X509Extension(
                    "2.5.29.14",
                    "0414C7AC28EFB300F46F9406ED155628A123633E556F".HexToByteArray(),
                    critical: false)
            };

            X509Extension[] endEntityExtensions = new [] {
                new X509BasicConstraintsExtension(
                    certificateAuthority: false,
                    hasPathLengthConstraint: false,
                    pathLengthConstraint: 0,
                    critical: true),
                new X509Extension(
                    "2.5.29.35",
                    "30168014A84A6A63047DDDBAE6D139B7A64565EFF3A8ECA1".HexToByteArray(),
                    critical: false)
            };

            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert,
                intermediateExtensions: intermediateExtensions,
                endEntityExtensions: endEntityExtensions);

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
                            chain.ChainPolicy.TrustMode        = X509ChainTrustMode.CustomRootTrust;
                            chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                            chain.ChainPolicy.ExtraStore.Add(intermediateCert);

                            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                            {
                                Assert.False(chain.Build(endEntityCert), "chain.Build");
                                Assert.Equal(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags());
                            }
                            else
                            {
                                Assert.True(chain.Build(endEntityCert), "chain.Build");
                                Assert.Equal(3, chain.ChainElements.Count);
                            }
                        }
        }
Пример #13
0
        public static void VerifyWithRevocation()
        {
            using (var cert = new X509Certificate2(Path.Combine("TestData", "MS.cer")))
                using (var onlineChainHolder = new ChainHolder())
                    using (var offlineChainHolder = new ChainHolder())
                    {
                        X509Chain onlineChain  = onlineChainHolder.Chain;
                        X509Chain offlineChain = offlineChainHolder.Chain;

                        onlineChain.ChainPolicy.VerificationFlags =
                            X509VerificationFlags.AllowUnknownCertificateAuthority;

                        onlineChain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);
                        onlineChain.ChainPolicy.RevocationMode   = X509RevocationMode.Online;
                        onlineChain.ChainPolicy.RevocationFlag   = X509RevocationFlag.EntireChain;

                        bool valid = onlineChain.Build(cert);
                        Assert.True(valid, "Online Chain Built Validly");

                        // Since the network was enabled, we should get the whole chain.
                        Assert.Equal(3, onlineChain.ChainElements.Count);

                        Assert.Equal(0, onlineChain.ChainElements[0].ChainElementStatus.Length);
                        Assert.Equal(0, onlineChain.ChainElements[1].ChainElementStatus.Length);

                        // The root CA is not expected to be installed on everyone's machines,
                        // so allow for it to report UntrustedRoot, but nothing else..
                        X509ChainStatus[] rootElementStatus = onlineChain.ChainElements[2].ChainElementStatus;

                        if (rootElementStatus.Length != 0)
                        {
                            Assert.Equal(1, rootElementStatus.Length);
                            Assert.Equal(X509ChainStatusFlags.UntrustedRoot, rootElementStatus[0].Status);
                        }

                        // Now that everything is cached, try again in Offline mode.
                        offlineChain.ChainPolicy.VerificationFlags = onlineChain.ChainPolicy.VerificationFlags;
                        offlineChain.ChainPolicy.VerificationTime  = onlineChain.ChainPolicy.VerificationTime;
                        offlineChain.ChainPolicy.RevocationMode    = X509RevocationMode.Offline;
                        offlineChain.ChainPolicy.RevocationFlag    = onlineChain.ChainPolicy.RevocationFlag;

                        valid = offlineChain.Build(cert);
                        Assert.True(valid, "Offline Chain Built Validly");

                        // Everything should look just like the online chain:
                        Assert.Equal(onlineChain.ChainElements.Count, offlineChain.ChainElements.Count);

                        for (int i = 0; i < offlineChain.ChainElements.Count; i++)
                        {
                            X509ChainElement onlineElement  = onlineChain.ChainElements[i];
                            X509ChainElement offlineElement = offlineChain.ChainElements[i];

                            Assert.Equal(onlineElement.ChainElementStatus, offlineElement.ChainElementStatus);
                            Assert.Equal(onlineElement.Certificate, offlineElement.Certificate);
                        }
                    }
        }
Пример #14
0
        public static void BuildInvalidSignatureTwice()
        {
            byte[] bytes = (byte[])TestData.MsCertificate.Clone();
            bytes[bytes.Length - 1] ^= 0xFF;

            using (X509Certificate2 cert = new X509Certificate2(bytes))
                using (ChainHolder chainHolder = new ChainHolder())
                {
                    X509Chain chain = chainHolder.Chain;
                    chain.ChainPolicy.VerificationTime  = cert.NotBefore.AddHours(2);
                    chain.ChainPolicy.VerificationFlags =
                        X509VerificationFlags.AllowUnknownCertificateAuthority;

                    chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                    int iter = 0;

                    void CheckChain()
                    {
                        iter++;
                        bool valid = chain.Build(cert);
                        X509ChainStatusFlags allFlags = chain.AllStatusFlags();

                        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                        {
                            // OSX considers this to be valid because it doesn't report NotSignatureValid,
                            // just PartialChain ("I couldn't find an issuer that made the signature work"),
                            // and PartialChain + AllowUnknownCertificateAuthority == pass.
                            Assert.True(valid, $"Chain is valid on execution {iter}");

                            Assert.Equal(1, chain.ChainElements.Count);

                            Assert.Equal(
                                X509ChainStatusFlags.PartialChain,
                                allFlags);
                        }
                        else
                        {
                            Assert.False(valid, $"Chain is valid on execution {iter}");

                            Assert.Equal(3, chain.ChainElements.Count);

                            // Clear UntrustedRoot, if it happened.
                            allFlags &= ~X509ChainStatusFlags.UntrustedRoot;

                            Assert.Equal(
                                X509ChainStatusFlags.NotSignatureValid,
                                allFlags);
                        }

                        chainHolder.DisposeChainElements();
                    }

                    CheckChain();
                    CheckChain();
                }
        }
Пример #15
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))
            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);

                if (initialErrorCount > 0)
                {
                    Assert.Equal(X509ChainStatusFlags.UntrustedRoot, chain.ChainStatus[0].Status);
                }

                chainHolder.DisposeChainElements();

                chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;

                valid = chain.Build(microsoftDotComIssuer);
                Assert.False(valid, "Chain should not build validly");

                Assert.Equal(initialErrorCount + 1, chain.ChainStatus.Length);
                Assert.Equal(X509ChainStatusFlags.RevocationStatusUnknown, chain.ChainStatus[0].Status);

                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);
            }
        }
Пример #16
0
        public static void VerifyChainFromHandle()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
                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);
                                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                                chain.ChainPolicy.VerificationTime  = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                                chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;

                                bool valid = chain.Build(microsoftDotCom);
                                Assert.True(valid, "Source chain built validly");
                                Assert.Equal(3, chain.ChainElements.Count);

                                using (var chainHolder2 = new ChainHolder(chain.ChainContext))
                                {
                                    X509Chain chain2 = chainHolder2.Chain;
                                    Assert.NotSame(chain, chain2);
                                    Assert.Equal(chain.ChainContext, chain2.ChainContext);

                                    Assert.Equal(3, chain2.ChainElements.Count);

                                    Assert.NotSame(chain.ChainElements[0], chain2.ChainElements[0]);
                                    Assert.NotSame(chain.ChainElements[1], chain2.ChainElements[1]);
                                    Assert.NotSame(chain.ChainElements[2], chain2.ChainElements[2]);

                                    Assert.Equal(microsoftDotCom, chain2.ChainElements[0].Certificate);
                                    Assert.Equal(microsoftDotComIssuer, chain2.ChainElements[1].Certificate);
                                    Assert.Equal(microsoftDotComRoot, chain2.ChainElements[2].Certificate);

                                    // ChainPolicy is not carried over from the Chain(IntPtr) constructor
                                    Assert.NotEqual(chain.ChainPolicy.VerificationFlags, chain2.ChainPolicy.VerificationFlags);
                                    Assert.NotEqual(chain.ChainPolicy.VerificationTime, chain2.ChainPolicy.VerificationTime);
                                    Assert.NotEqual(chain.ChainPolicy.RevocationMode, chain2.ChainPolicy.RevocationMode);
                                    Assert.Equal(X509VerificationFlags.NoFlag, chain2.ChainPolicy.VerificationFlags);

                                    // Re-set the ChainPolicy properties
                                    chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                                    chain2.ChainPolicy.VerificationTime  = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                                    chain2.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;

                                    valid = chain2.Build(microsoftDotCom);
                                    Assert.True(valid, "Cloned chain built validly");
                                }
                            }
        }
Пример #17
0
        private static void TestNameConstrainedChain(
            string intermediateNameConstraints,
            SubjectAlternativeNameBuilder endEntitySanBuilder,
            Action <bool, X509Chain> body)
        {
            X509Extension[] endEntityExtensions = new [] {
                new X509BasicConstraintsExtension(
                    certificateAuthority: false,
                    hasPathLengthConstraint: false,
                    pathLengthConstraint: 0,
                    critical: true),
                endEntitySanBuilder.Build()
            };

            X509Extension[] intermediateExtensions = new [] {
                new X509BasicConstraintsExtension(
                    certificateAuthority: true,
                    hasPathLengthConstraint: false,
                    pathLengthConstraint: 0,
                    critical: true),
                new X509Extension(
                    "2.5.29.30",
                    intermediateNameConstraints.HexToByteArray(),
                    critical: true)
            };

            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert,
                intermediateExtensions: intermediateExtensions,
                endEntityExtensions: endEntityExtensions);

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
                            chain.ChainPolicy.TrustMode        = X509ChainTrustMode.CustomRootTrust;
                            chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                            chain.ChainPolicy.ExtraStore.Add(intermediateCert);

                            bool result = chain.Build(endEntityCert);
                            body(result, chain);
                        }
        }
Пример #18
0
        public static void CustomRootTrustDoesNotTrustIntermediates(
            bool saveAllInCustomTrustStore,
            X509ChainStatusFlags chainFlags)
        {
            string testName = $"{nameof(CustomRootTrustDoesNotTrustIntermediates)} {saveAllInCustomTrustStore} {chainFlags}";

            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert,
                testName: testName);

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
                            chain.ChainPolicy.TrustMode        = X509ChainTrustMode.CustomRootTrust;
                            chain.ChainPolicy.CustomTrustStore.Add(intermediateCert);

                            if (saveAllInCustomTrustStore)
                            {
                                chain.ChainPolicy.CustomTrustStore.Add(rootCert);
                            }
                            else
                            {
                                chain.ChainPolicy.ExtraStore.Add(rootCert);
                            }

                            if (PlatformDetection.IsAndroid && !saveAllInCustomTrustStore)
                            {
                                // Android does not support an empty custom root trust
                                // Only self-issued certs are treated as trusted anchors, so building the chain
                                // should through PNSE even though the intermediate cert is added to the store
                                Assert.Throws <PlatformNotSupportedException>(() => chain.Build(endEntityCert));
                            }
                            else
                            {
                                Assert.Equal(saveAllInCustomTrustStore, chain.Build(endEntityCert));
                                Assert.Equal(3, chain.ChainElements.Count);
                                Assert.Equal(chainFlags, chain.AllStatusFlags());
                            }
                        }
        }
Пример #19
0
        public static void VerifyChainFromHandle_Unix()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
                using (var chainHolder = new ChainHolder())
                {
                    X509Chain chain = chainHolder.Chain;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                    chain.ChainPolicy.VerificationTime  = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;

                    bool valid = chain.Build(microsoftDotCom);

                    Assert.Equal(IntPtr.Zero, chain.ChainContext);
                }

            Assert.Throws <PlatformNotSupportedException>(() => new X509Chain(IntPtr.Zero));
        }
Пример #20
0
        public static void TestDispose()
        {
            X509Chain chain;

            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
                using (var chainHolder = new ChainHolder())
                {
                    chain = chainHolder.Chain;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                    chain.ChainPolicy.VerificationTime  = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                    chain.Build(microsoftDotCom);

                    Assert.NotEqual(IntPtr.Zero, chain.ChainContext);
                }
            // No exception thrown for accessing ChainContext on disposed chain
            Assert.Equal(IntPtr.Zero, chain.ChainContext);
        }
Пример #21
0
        public static void ChainWithEmptySubject()
        {
            using (var cert = new X509Certificate2(TestData.EmptySubjectCertificate))
                using (var issuer = new X509Certificate2(TestData.EmptySubjectIssuerCertificate))
                    using (ChainHolder chainHolder = new ChainHolder())
                    {
                        X509Chain chain = chainHolder.Chain;
                        chain.ChainPolicy.RevocationMode     = X509RevocationMode.NoCheck;
                        chain.ChainPolicy.VerificationFlags |= X509VerificationFlags.AllowUnknownCertificateAuthority;
                        chain.ChainPolicy.ExtraStore.Add(issuer);

                        Assert.True(chain.Build(cert), "chain.Build(cert)");
                        Assert.Equal(2, chain.ChainElements.Count);
                        Assert.Equal(string.Empty, cert.Subject);
                        Assert.Equal(cert.RawData, chain.ChainElements[0].Certificate.RawData);
                        Assert.Equal(issuer.RawData, chain.ChainElements[1].Certificate.RawData);
                    }
        }
Пример #22
0
        public static void BuildChainExtraStoreUntrustedRoot()
        {
            using (var testCert = new X509Certificate2(Path.Combine("TestData", "test.pfx"), TestData.ChainPfxPassword))
            using (ImportedCollection ic = Cert.Import(Path.Combine("TestData", "test.pfx"), TestData.ChainPfxPassword, X509KeyStorageFlags.DefaultKeySet))
            using (var chainHolder = new ChainHolder())
            {
                X509Certificate2Collection collection = ic.Collection;

                X509Chain chain = chainHolder.Chain;
                chain.ChainPolicy.ExtraStore.AddRange(collection);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 9, 22, 12, 25, 0);

                bool valid = chain.Build(testCert);

                Assert.False(valid);
                Assert.Contains(chain.ChainStatus, s => s.Status == X509ChainStatusFlags.UntrustedRoot);
            }
        }
Пример #23
0
        public static void BuildChainExtraStoreUntrustedRoot()
        {
            using (var testCert = new X509Certificate2(Path.Combine("TestData", "test.pfx"), TestData.ChainPfxPassword))
                using (ImportedCollection ic = Cert.Import(Path.Combine("TestData", "test.pfx"), TestData.ChainPfxPassword, X509KeyStorageFlags.DefaultKeySet))
                    using (var chainHolder = new ChainHolder())
                    {
                        X509Certificate2Collection collection = ic.Collection;

                        X509Chain chain = chainHolder.Chain;
                        chain.ChainPolicy.ExtraStore.AddRange(collection);
                        chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                        chain.ChainPolicy.VerificationTime = new DateTime(2015, 9, 22, 12, 25, 0);

                        bool valid = chain.Build(testCert);

                        Assert.False(valid);
                        Assert.Contains(chain.ChainStatus, s => s.Status == X509ChainStatusFlags.UntrustedRoot);
                    }
        }
Пример #24
0
        public static void BuildChain_WithCertificatePolicy_Match()
        {
            using (var cert = new X509Certificate2(TestData.CertWithPolicies))
                using (var chainHolder = new ChainHolder())
                {
                    X509Chain chain = chainHolder.Chain;

                    // Code Signing
                    chain.ChainPolicy.CertificatePolicy.Add(new Oid("2.18.19"));
                    chain.ChainPolicy.VerificationFlags =
                        X509VerificationFlags.AllowUnknownCertificateAuthority;
                    chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);

                    chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                    bool valid = chain.Build(cert);
                    Assert.True(valid, "Chain built validly");
                }
        }
Пример #25
0
        public static void BuildChain_WithApplicationPolicy_Match()
        {
            using (var msCer = new X509Certificate2(TestData.MsCertificate))
                using (var chainHolder = new ChainHolder())
                {
                    X509Chain chain = chainHolder.Chain;

                    // Code Signing
                    chain.ChainPolicy.ApplicationPolicy.Add(new Oid("1.3.6.1.5.5.7.3.3"));
                    chain.ChainPolicy.VerificationTime  = msCer.NotBefore.AddHours(2);
                    chain.ChainPolicy.VerificationFlags =
                        X509VerificationFlags.AllowUnknownCertificateAuthority;

                    chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                    bool valid = chain.Build(msCer);
                    Assert.True(valid, "Chain built validly");
                }
        }
Пример #26
0
        public static void BuildChain_FailOnlyApplicationPolicy()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
                using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
                    using (ChainHolder holder = new ChainHolder())
                    {
                        holder.Chain.ChainPolicy.ApplicationPolicy.Add(new Oid("0.1.2.3.4", null));
                        holder.Chain.ChainPolicy.VerificationTime = microsoftDotCom.NotBefore.AddDays(1);
                        holder.Chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;

                        Assert.False(holder.Chain.Build(microsoftDotCom));

                        Assert.Equal(
                            X509ChainStatusFlags.NotValidForUsage,
                            holder.Chain.ChainStatus.Aggregate(
                                X509ChainStatusFlags.NoError,
                                (a, status) => a | status.Status));

                        Assert.Equal(3, holder.Chain.ChainElements.Count);

                        Assert.Equal(microsoftDotCom.RawData, holder.Chain.ChainElements[0].Certificate.RawData);
                        Assert.Equal(microsoftDotComRoot.RawData, holder.Chain.ChainElements[2].Certificate.RawData);

                        Assert.Equal(
                            X509ChainStatusFlags.NotValidForUsage,
                            holder.Chain.ChainElements[0].ChainElementStatus.Aggregate(
                                X509ChainStatusFlags.NoError,
                                (a, status) => a | status.Status));

                        Assert.Equal(
                            X509ChainStatusFlags.NotValidForUsage,
                            holder.Chain.ChainElements[1].ChainElementStatus.Aggregate(
                                X509ChainStatusFlags.NoError,
                                (a, status) => a | status.Status));

                        Assert.Equal(
                            X509ChainStatusFlags.NotValidForUsage,
                            holder.Chain.ChainElements[2].ChainElementStatus.Aggregate(
                                X509ChainStatusFlags.NoError,
                                (a, status) => a | status.Status));
                    }
        }
Пример #27
0
        public static void InvalidSelfSignedSignature()
        {
            X509ChainStatusFlags expectedFlags;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                expectedFlags = X509ChainStatusFlags.NotSignatureValid;
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                expectedFlags = X509ChainStatusFlags.UntrustedRoot;
            }
            else
            {
                expectedFlags =
                    X509ChainStatusFlags.NotSignatureValid |
                    X509ChainStatusFlags.UntrustedRoot;
            }

            byte[] certBytes = (byte[])TestData.MicrosoftDotComRootBytes.Clone();
            // The signature goes up to the very last byte, so flip some bits in it.
            certBytes[certBytes.Length - 1] ^= 0xFF;

            using (var cert = new X509Certificate2(certBytes))
                using (ChainHolder holder = new ChainHolder())
                {
                    X509Chain       chain  = holder.Chain;
                    X509ChainPolicy policy = chain.ChainPolicy;
                    policy.VerificationTime = cert.NotBefore.AddDays(3);
                    policy.RevocationMode   = X509RevocationMode.NoCheck;

                    chain.Build(cert);

                    X509ChainStatusFlags allFlags =
                        chain.ChainStatus.Select(cs => cs.Status).Aggregate(
                            X509ChainStatusFlags.NoError,
                            (a, b) => a | b);

                    Assert.Equal(expectedFlags, allFlags);
                }
        }
Пример #28
0
        public static void CustomTrustModeWithNoCustomTrustCerts()
        {
            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert);

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
                            chain.ChainPolicy.TrustMode        = X509ChainTrustMode.CustomRootTrust;

                            Assert.False(chain.Build(endEntityCert));
                            Assert.Equal(1, chain.ChainElements.Count);
                            Assert.Equal(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags());
                        }
        }
Пример #29
0
        public static void X509ChainElementCollection_CopyTo_NonZeroLowerBound_ThrowsIndexOutOfRangeException()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes))
            using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
            using (var chainHolder = new ChainHolder())
            {
                X509Chain chain = chainHolder.Chain;

                chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;

                chain.Build(microsoftDotCom);
                ICollection collection = chain.ChainElements;
                Array array = Array.CreateInstance(typeof(object), new int[] { 10 }, new int[] { 10 });
                Assert.Throws<IndexOutOfRangeException>(() => collection.CopyTo(array, 0));
            }
        }
Пример #30
0
        public static void BuildChain_MicrosoftDotCom_WithRootCertInUserAndSystemRootCertStores()
        {
            // Verifies that when the same root cert is placed in both a user and machine root certificate store,
            // any certs chain building to that root cert will build correctly
            //
            // We use a copy of the microsoft.com SSL certs and root certs to validate that the chain can build
            // successfully

            bool shouldInstallCertToUserStore = true;
            bool installedCertToUserStore = false;

            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
            {
                // Check that microsoft.com's root certificate IS installed in the machine root store as a sanity step
                using (var machineRootStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
                {
                    machineRootStore.Open(OpenFlags.ReadOnly);
                    bool foundCert = false;

                    foreach (var machineCert in machineRootStore.Certificates)
                    {
                        if (machineCert.Equals(microsoftDotComRoot))
                        {
                            foundCert = true;
                        }

                        machineCert.Dispose();
                    }

                    Assert.True(foundCert, string.Format("Did not find expected certificate with thumbprint '{0}' in the machine root store", microsoftDotComRoot.Thumbprint));
                }

                // Concievably at this point there could still be something wrong and we still don't chain build correctly - if that's
                // the case, then there's likely something wrong with the machine. Validating that happy path is out of scope
                // of this particular test.

                // Check that microsoft.com's root certificate is NOT installed on in the user cert store as a sanity step
                // We won't try to install the microsoft.com root cert into the user root store if it's already there
                using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
                {
                    userRootStore.Open(OpenFlags.ReadOnly);

                    foreach (var userCert in userRootStore.Certificates)
                    {
                        bool foundCert = false;
                        if (userCert.Equals(microsoftDotComRoot))
                        {
                            foundCert = true;
                        }

                        userCert.Dispose();

                        if (foundCert)
                        {
                            shouldInstallCertToUserStore = false;
                        }
                    }
                }

                using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
                using (var chainHolder = new ChainHolder())
                {
                    try
                    {
                        if (shouldInstallCertToUserStore)
                        {
                            userRootStore.Open(OpenFlags.ReadWrite);
                            userRootStore.Add(microsoftDotComRoot); // throws CryptographicException
                            installedCertToUserStore = true;
                        }

                        X509Chain chainValidator = chainHolder.Chain;
                        chainValidator.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                        chainValidator.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                        bool chainBuildResult = chainValidator.Build(microsoftDotCom);

                        StringBuilder builder = new StringBuilder();
                        foreach (var status in chainValidator.ChainStatus)
                        {
                            builder.AppendFormat("{0} {1}{2}", status.Status, status.StatusInformation, Environment.NewLine);
                        }

                        Assert.True(chainBuildResult,
                            string.Format("Certificate chain build failed. ChainStatus is:{0}{1}", Environment.NewLine, builder.ToString()));
                    }
                    finally
                    {
                        if (installedCertToUserStore)
                        {
                            userRootStore.Remove(microsoftDotComRoot);
                        }
                    }
                }
            }
        }
Пример #31
0
        public static void VerifyWithRevocation()
        {
            using (var cert = new X509Certificate2(Path.Combine("TestData", "MS.cer")))
                using (var onlineChainHolder = new ChainHolder())
                    using (var offlineChainHolder = new ChainHolder())
                    {
                        X509Chain onlineChain  = onlineChainHolder.Chain;
                        X509Chain offlineChain = offlineChainHolder.Chain;

                        onlineChain.ChainPolicy.VerificationFlags =
                            X509VerificationFlags.AllowUnknownCertificateAuthority;

                        onlineChain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);
                        onlineChain.ChainPolicy.RevocationMode   = X509RevocationMode.Online;
                        onlineChain.ChainPolicy.RevocationFlag   = X509RevocationFlag.EntireChain;

                        // Attempt the online test a couple of times, in case there was just a CRL
                        // download failure.
                        const int RetryLimit = 3;
                        bool      valid      = false;

                        for (int i = 0; i < RetryLimit; i++)
                        {
                            valid = onlineChain.Build(cert);

                            if (valid)
                            {
                                break;
                            }

                            for (int j = 0; j < onlineChain.ChainElements.Count; j++)
                            {
                                X509ChainStatusFlags chainFlags = onlineChain.ChainStatus.Aggregate(
                                    X509ChainStatusFlags.NoError,
                                    (cur, status) => cur | status.Status);

                                const X509ChainStatusFlags WontCheck =
                                    X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.UntrustedRoot;

                                if (chainFlags == WontCheck)
                                {
                                    Console.WriteLine($"{nameof(VerifyWithRevocation)}: online chain failed with {{{chainFlags}}}, skipping");
                                    return;
                                }

                                X509ChainElement chainElement = onlineChain.ChainElements[j];

                                // Since `NoError` gets mapped as the empty array, just look for non-empty arrays
                                if (chainElement.ChainElementStatus.Length > 0)
                                {
                                    X509ChainStatusFlags allFlags = chainElement.ChainElementStatus.Aggregate(
                                        X509ChainStatusFlags.NoError,
                                        (cur, status) => cur | status.Status);

                                    Console.WriteLine(
                                        $"{nameof(VerifyWithRevocation)}: online attempt {i} - errors at depth {j}: {allFlags}");
                                }

                                chainElement.Certificate.Dispose();
                            }

                            Thread.Sleep(1000); // For network flakiness
                        }

                        if (TestEnvironmentConfiguration.RunManualTests)
                        {
                            Assert.True(valid, $"Online Chain Built Validly within {RetryLimit} tries");
                        }
                        else if (!valid)
                        {
                            Console.WriteLine($"SKIP [{nameof(VerifyWithRevocation)}]: Chain failed to build within {RetryLimit} tries.");
                            return;
                        }

                        // Since the network was enabled, we should get the whole chain.
                        Assert.Equal(3, onlineChain.ChainElements.Count);

                        Assert.Equal(0, onlineChain.ChainElements[0].ChainElementStatus.Length);
                        Assert.Equal(0, onlineChain.ChainElements[1].ChainElementStatus.Length);

                        // The root CA is not expected to be installed on everyone's machines,
                        // so allow for it to report UntrustedRoot, but nothing else..
                        X509ChainStatus[] rootElementStatus = onlineChain.ChainElements[2].ChainElementStatus;

                        if (rootElementStatus.Length != 0)
                        {
                            Assert.Equal(1, rootElementStatus.Length);
                            Assert.Equal(X509ChainStatusFlags.UntrustedRoot, rootElementStatus[0].Status);
                        }

                        // Now that everything is cached, try again in Offline mode.
                        offlineChain.ChainPolicy.VerificationFlags = onlineChain.ChainPolicy.VerificationFlags;
                        offlineChain.ChainPolicy.VerificationTime  = onlineChain.ChainPolicy.VerificationTime;
                        offlineChain.ChainPolicy.RevocationMode    = X509RevocationMode.Offline;
                        offlineChain.ChainPolicy.RevocationFlag    = onlineChain.ChainPolicy.RevocationFlag;

                        valid = offlineChain.Build(cert);
                        Assert.True(valid, "Offline Chain Built Validly");

                        // Everything should look just like the online chain:
                        Assert.Equal(onlineChain.ChainElements.Count, offlineChain.ChainElements.Count);

                        for (int i = 0; i < offlineChain.ChainElements.Count; i++)
                        {
                            X509ChainElement onlineElement  = onlineChain.ChainElements[i];
                            X509ChainElement offlineElement = offlineChain.ChainElements[i];

                            Assert.Equal(onlineElement.ChainElementStatus, offlineElement.ChainElementStatus);
                            Assert.Equal(onlineElement.Certificate, offlineElement.Certificate);
                        }
                    }
        }
Пример #32
0
        public static void BuildChain_MicrosoftDotCom_WithRootCertInUserAndSystemRootCertStores()
        {
            // Verifies that when the same root cert is placed in both a user and machine root certificate store,
            // any certs chain building to that root cert will build correctly
            //
            // We use a copy of the microsoft.com SSL certs and root certs to validate that the chain can build
            // successfully

            bool shouldInstallCertToUserStore = true;
            bool installedCertToUserStore     = false;

            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
                using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
                {
                    // Check that microsoft.com's root certificate IS installed in the machine root store as a sanity step
                    using (var machineRootStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
                    {
                        machineRootStore.Open(OpenFlags.ReadOnly);
                        bool foundCert = false;

                        foreach (var machineCert in machineRootStore.Certificates)
                        {
                            if (machineCert.Equals(microsoftDotComRoot))
                            {
                                foundCert = true;
                            }

                            machineCert.Dispose();
                        }

                        Assert.True(foundCert, string.Format("Did not find expected certificate with thumbprint '{0}' in the machine root store", microsoftDotComRoot.Thumbprint));
                    }

                    // Concievably at this point there could still be something wrong and we still don't chain build correctly - if that's
                    // the case, then there's likely something wrong with the machine. Validating that happy path is out of scope
                    // of this particular test.

                    // Check that microsoft.com's root certificate is NOT installed on in the user cert store as a sanity step
                    // We won't try to install the microsoft.com root cert into the user root store if it's already there
                    using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
                    {
                        userRootStore.Open(OpenFlags.ReadOnly);

                        foreach (var userCert in userRootStore.Certificates)
                        {
                            bool foundCert = false;
                            if (userCert.Equals(microsoftDotComRoot))
                            {
                                foundCert = true;
                            }

                            userCert.Dispose();

                            if (foundCert)
                            {
                                shouldInstallCertToUserStore = false;
                            }
                        }
                    }

                    using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
                        using (var chainHolder = new ChainHolder())
                        {
                            try
                            {
                                if (shouldInstallCertToUserStore)
                                {
                                    try
                                    {
                                        userRootStore.Open(OpenFlags.ReadWrite);
                                    }
                                    catch (CryptographicException)
                                    {
                                        return;
                                    }

                                    userRootStore.Add(microsoftDotComRoot); // throws CryptographicException
                                    installedCertToUserStore = true;
                                }

                                X509Chain chainValidator = chainHolder.Chain;
                                chainValidator.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                                chainValidator.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;

                                bool chainBuildResult = chainValidator.Build(microsoftDotCom);

                                StringBuilder builder = new StringBuilder();
                                foreach (var status in chainValidator.ChainStatus)
                                {
                                    builder.AppendFormat("{0} {1}{2}", status.Status, status.StatusInformation, Environment.NewLine);
                                }

                                Assert.True(chainBuildResult,
                                            string.Format("Certificate chain build failed. ChainStatus is:{0}{1}", Environment.NewLine, builder.ToString()));
                            }
                            finally
                            {
                                if (installedCertToUserStore)
                                {
                                    userRootStore.Remove(microsoftDotComRoot);
                                }
                            }
                        }
                }
        }
Пример #33
0
        public static void TestDispose()
        {
            X509Chain chain;

            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var chainHolder = new ChainHolder())
            {
                chain = chainHolder.Chain;
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.Build(microsoftDotCom);

                Assert.NotEqual(IntPtr.Zero, chain.ChainContext);
            }
            // No exception thrown for accessing ChainContext on disposed chain
            Assert.Equal(IntPtr.Zero, chain.ChainContext);
        }
Пример #34
0
        public static void TestResetMethod()
        {
            using (var sampleCert = new X509Certificate2(TestData.DssCer))
            using (var chainHolder = new ChainHolder())
            {
                X509Chain chain = chainHolder.Chain;

                chain.ChainPolicy.ExtraStore.Add(sampleCert);
                bool valid = chain.Build(sampleCert);
                Assert.False(valid);

                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                valid = chain.Build(sampleCert);
                Assert.True(valid, "Chain built validly");

                Assert.Equal(1, chain.ChainElements.Count);

                chain.Reset();
                Assert.Equal(0, chain.ChainElements.Count);

                // ChainPolicy did not reset (for desktop compat)
                Assert.Equal(X509VerificationFlags.AllowUnknownCertificateAuthority, chain.ChainPolicy.VerificationFlags);

                valid = chain.Build(sampleCert);
                Assert.Equal(1, chain.ChainElements.Count);
                // This succeeds because ChainPolicy did not reset
                Assert.True(valid, "Chain built validly after reset");
            }
        }
Пример #35
0
        public static void ChainErrorsAtMultipleLayers()
        {
            // These certificates were generated for this test using CertificateRequest
            // but the netstandard(2.0) version of this test library doesn't have
            // CertificateRequest available.
            //
            // These certificates have been hard-coded to enable the scenario on
            // netstandard.
            byte[] endEntityBytes    = Encoding.ASCII.GetBytes(@"
-----BEGIN CERTIFICATE-----
MIIC6DCCAdCgAwIBAgIQAKjmD7+TWUwQN2ucajn9kTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQD
EwxJbnRlcm1lZGlhdGUwHhcNMTkwMzAzMjM1NzA3WhcNMTkwNjAzMjM1NzA3WjAVMRMwEQYDVQQD
EwpFbmQtRW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTybBkpMdQ8IeL1C
jG755+ifQfqjNt4+Xhm3pbMi+nCRD68tym1xviUka1hQmx+I1mptswW0Laq1owur0r2KanKoIP2F
i2h6orOOdslMFPMWqCuNTU4C7cUxokaWah0R7FihwW+aBeWgxG948Cvt+ByQeR1ns9yo7wa8f8kT
IwzOUu0v1Yj5oW5bOn/cmIBE1C5CD5RivPMGUXX8mZ/myNh16dLQqJW5yQt/uvfr7lkNWC0qq+v7
Ely4+X27acwMTdtk4chcr5/bTS5FXV7HVqwhajOmm6WrzagPZBELWKRk2EaJkha/MLrBqNfHExs4
sx2ks+TTclrOrRzG+AUBuQIDAQABozIwMDAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIF4DATBgNV
HSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAbrEbiw4gpgWi3SJ+sGrfcWCAldpx
0735hkkYz94OsJjIwWfgQ03pYZwjcnIE4Ln0PU2E52D2ldsJlAE376hpNxdO0X4RLpZVZPEjKGTF
v2Rf+d0cpqha5J//mqcTTm7F58JRKyfEQn0pqfxx4VyXeLfEsqYbT3kY7ufK0km3Jst0DGw2AGue
MPmiZicaNlXPVO9vyW4s6J23+kol6X8K2rnVht9jagfnOQ990Ux2xXGyDGM4I0pvW1Zo4vid/eli
psHHsU9xg0o7L2WXD5qYhD2JCQIVWNRmRZCf1luWlKqUaqWWONMJ44hk8Md+ohxpyCRmbtLRZPzd
wlkQzPsc9A==
-----END CERTIFICATE-----");
            byte[] intermediateBytes = Encoding.ASCII.GetBytes(@"
-----BEGIN CERTIFICATE-----
MIIC1DCCAbygAwIBAgIPRoY1rB2tMVJeYB4GILkNMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNVBAMT
CVRlc3QgUm9vdDAeFw0xOTAyMTgyMzU3MDdaFw0yMDAyMTgyMzU3MDdaMBcxFTATBgNVBAMTDElu
dGVybWVkaWF0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxYzEN6nYvQ0TOg/jOF
wdBGRUYhTiJpYGFBh9826X5vKlbCS1UAcjFRXmKtJ4WZ8v3peCBPxvVe/1KR38+MWNVtO4B1GBvr
qR2T9k1ewgn0lO3i6krnIAhJQ+F94xGcsRAfZjXBh7lOmTE9ZlDhDJWkehBIs5TteiBOfbGDml2S
v7x81cmm2o/sDoP1oVGhezOkFtI2/NdZYKxRthnjDywN3W4KFataJFATVv/yq+QjcLEWrXFRpzDE
rpVdYmj66kaAnu9D4sHhFqOk1SX3JvcB361stVuUPp2ri75MaaXakweH6X/Yb4nPNV6m1ENwMoDy
HqrZrHSK8SpzfhY9aB0CAwEAAaMgMB4wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBAC4oJ2SH+Ov4QIMXo7mwGSrwONkdMuKyyM9shZiGEH+zIO9SVuPuvtQG
cePR2bijSz2DtjySi+ST8y3Ql7A3isfbXYPDFmnkzKP6hGvLkctc8eO8U1x7ny+QW1max0gm3UA8
CY0IMP8pCHUZH9OX/K0N9L+GItqlBK8G4grJ4o43da2x9L0hIrdauPadaGcJalf8k1ymhJ4VDj7t
ueuTl2qTtbBh015GuEld61EBXSBLIUqwOAeFYrNJbC4J2mXgnLTWC380cBf5KWeSdjLYgk2sZ1V4
FKKQecZIhxdlDGzMAbbmEV+2EqS+As2C7+y4dkpG4nnbQe/4AFr8vekHdrI=
-----END CERTIFICATE-----");
            byte[] rootBytes         = Encoding.ASCII.GetBytes(@"
-----BEGIN CERTIFICATE-----
MIICyjCCAbKgAwIBAgIIKKt3K3rRbvQwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAxMJVGVzdCBS
b290MB4XDTE5MDIwNDIzNTcwN1oXDTIxMDIwNDIzNTcwN1owFDESMBAGA1UEAxMJVGVzdCBSb290
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiM7tv4YvqmWYGF1vbeM2cQWV1NVBxKU4
ZK5XEJHZirzE2HCiA0+hI/UD7xnfBrzGQRLsHnp9vfhBi/0wenSIKTckxcGGpuM+JzNoVF97uFSd
bKvfIwQZzbdRGyTF1eoQWCylsZsnZOXg8c/yoFhG2TJB38l09RYn+HkMkapQERFKSXPZ7taNVJNb
Sedp3l9jO0aVmh9rmJ7taBXBfWDmSWqhkxjkEcbiRxB7z5K8YxZBlHQCLqf43JiCbKIMBHdzTg+N
lEBkBGp6T2hoJ4/A1uwvhesjmyqagZrC2NnzOWOxUQ/WujIUfS62ii/yDkP4Jo3745lJ9XXoPbIw
AwvWYQIDAQABoyAwHjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBhjANBgkqhkiG9w0BAQsF
AAOCAQEAA/pfswrUzcLP5UfmHgQDc1slJjh0btnkN+4dxCCTLcnteJCTumYw+/82qL+O4t1KlzlS
2Eqgyx0u48YmwDp/5jWAvT8RX8pvV3Prd7T8/dp/ucES7R9r3zF2Rmw5Me9iq1yaLAypGyBGqV1J
HAwJjH/eKZ5iuOMhFljs2R5Gh5rRsQjNVUCRsolCds4d1f+76fi2SGaKqkAA4gzg1c71SPTAaUPR
ythjxnoCBDVFmwV5opXZj9qIZoUdH92gCVFgMWkxWCYWzyH78uIUzV1oo+KNwK1SCTnfVHcfWRIL
tHP28fj0LUop/QFojSZPsaPAW6JvoQ0t4hd6WoyX6z7FsA==
-----END CERTIFICATE-----");

            using (X509Certificate2 endEntityCert = new X509Certificate2(endEntityBytes))
                using (X509Certificate2 intermediateCert = new X509Certificate2(intermediateBytes))
                    using (X509Certificate2 rootCert = new X509Certificate2(rootBytes))
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.RevocationMode     = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationFlags |= X509VerificationFlags.AllowUnknownCertificateAuthority;
                            chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                            chain.ChainPolicy.ExtraStore.Add(rootCert);
                            chain.ChainPolicy.VerificationTime = endEntityCert.NotAfter.AddDays(1);

                            Assert.Equal(false, chain.Build(endEntityCert));

                            Assert.Equal(3, chain.ChainElements.Count);
                            Assert.Equal(X509ChainStatusFlags.NotTimeValid, chain.ChainElements[0].AllStatusFlags());
                            Assert.Equal(X509ChainStatusFlags.NoError, chain.ChainElements[1].AllStatusFlags());
                            Assert.Equal(X509ChainStatusFlags.UntrustedRoot, chain.ChainElements[2].AllStatusFlags());

                            Assert.Equal(
                                X509ChainStatusFlags.NotTimeValid | X509ChainStatusFlags.UntrustedRoot,
                                chain.AllStatusFlags());
                        }
        }
Пример #36
0
        public static void VerifyChainFromHandle_Unix()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var chainHolder = new ChainHolder())
            {
                X509Chain chain = chainHolder.Chain;
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(microsoftDotCom);

                Assert.Equal(IntPtr.Zero, chain.ChainContext);
            }

            Assert.Throws<PlatformNotSupportedException>(() => new X509Chain(IntPtr.Zero));
        }
Пример #37
0
        public static void BuildChain_WithApplicationPolicy_Match()
        {
            using (var msCer = new X509Certificate2(TestData.MsCertificate))
            using (var chainHolder = new ChainHolder())
            {
                X509Chain chain = chainHolder.Chain;

                // Code Signing
                chain.ChainPolicy.ApplicationPolicy.Add(new Oid("1.3.6.1.5.5.7.3.3"));
                chain.ChainPolicy.VerificationTime = msCer.NotBefore.AddHours(2);
                chain.ChainPolicy.VerificationFlags =
                    X509VerificationFlags.AllowUnknownCertificateAuthority;

                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(msCer);
                Assert.True(valid, "Chain built validly");
            }
        }
Пример #38
0
        public static void VerifyExpiration_LocalTime(DateTime verificationTime, bool shouldBeValid, DateTimeKind kind)
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes))
            using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
            using (var chainHolder = new ChainHolder())
            {
                X509Chain chain = chainHolder.Chain;

                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot);

                // Ignore anything except NotTimeValid
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags & ~X509VerificationFlags.IgnoreNotTimeValid;
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.ChainPolicy.VerificationTime = verificationTime;

                bool builtSuccessfully = chain.Build(microsoftDotCom);

                Assert.Equal(shouldBeValid, builtSuccessfully);

                // If we failed to build the chain, ensure that NotTimeValid is one of the reasons.
                if (!shouldBeValid)
                {
                    Assert.Contains(chain.ChainStatus, s => s.Status == X509ChainStatusFlags.NotTimeValid);
                }
            }
        }
Пример #39
0
        public static void BuildChain_WithCertificatePolicy_Match()
        {
            using (var cert = new X509Certificate2(TestData.CertWithPolicies))
            using (var chainHolder = new ChainHolder())
            {
                X509Chain chain = chainHolder.Chain;

                // Code Signing
                chain.ChainPolicy.CertificatePolicy.Add(new Oid("2.18.19"));
                chain.ChainPolicy.VerificationFlags =
                    X509VerificationFlags.AllowUnknownCertificateAuthority;
                chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);

                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(cert);
                Assert.True(valid, "Chain built validly");
            }
        }
Пример #40
0
        public static void BuildChain_WithCertificatePolicy_NoMatch()
        {
            using (var cert = new X509Certificate2(TestData.CertWithPolicies))
            using (var chainHolder = new ChainHolder())
            {
                X509Chain chain = chainHolder.Chain;

                chain.ChainPolicy.CertificatePolicy.Add(new Oid("2.999"));
                chain.ChainPolicy.VerificationFlags =
                    X509VerificationFlags.AllowUnknownCertificateAuthority;

                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);

                bool valid = chain.Build(cert);
                Assert.False(valid, "Chain built validly");

                Assert.InRange(chain.ChainElements.Count, 1, int.MaxValue);

                Assert.NotSame(cert, chain.ChainElements[0].Certificate);
                Assert.Equal(cert, chain.ChainElements[0].Certificate);

                X509ChainStatus[] chainElementStatus = chain.ChainElements[0].ChainElementStatus;
                Assert.InRange(chainElementStatus.Length, 1, int.MaxValue);
                Assert.Contains(chainElementStatus, x => x.Status == X509ChainStatusFlags.NotValidForUsage);
            }
        }
Пример #41
0
        public static void BuildInvalidSignatureTwice(
            X509ChainStatusFlags endEntityErrors,
            X509ChainStatusFlags intermediateErrors,
            X509ChainStatusFlags rootErrors)
        {
            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert);

            X509Certificate2 TamperIfNeeded(X509Certificate2 input, X509ChainStatusFlags flags)
            {
                if ((flags & X509ChainStatusFlags.NotSignatureValid) != 0)
                {
                    X509Certificate2 tampered = TamperSignature(input);
                    input.Dispose();
                    return(tampered);
                }

                return(input);
            }

            DateTime RewindIfNeeded(DateTime input, X509Certificate2 cert, X509ChainStatusFlags flags)
            {
                if ((flags & X509ChainStatusFlags.NotTimeValid) != 0)
                {
                    return(cert.NotBefore.AddMinutes(-1));
                }

                return(input);
            }

            int expectedCount = 3;

            DateTime verificationTime = endEntityCert.NotBefore.AddMinutes(1);

            verificationTime = RewindIfNeeded(verificationTime, endEntityCert, endEntityErrors);
            verificationTime = RewindIfNeeded(verificationTime, intermediateCert, intermediateErrors);
            verificationTime = RewindIfNeeded(verificationTime, rootCert, rootErrors);

            // Replace the certs for the scenario.
            endEntityCert    = TamperIfNeeded(endEntityCert, endEntityErrors);
            intermediateCert = TamperIfNeeded(intermediateCert, intermediateErrors);
            rootCert         = TamperIfNeeded(rootCert, rootErrors);

            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // For the lower levels, turn NotSignatureValid into PartialChain,
                // and clear all errors at higher levels.

                if ((endEntityErrors & X509ChainStatusFlags.NotSignatureValid) != 0)
                {
                    expectedCount      = 1;
                    endEntityErrors   &= ~X509ChainStatusFlags.NotSignatureValid;
                    endEntityErrors   |= X509ChainStatusFlags.PartialChain;
                    intermediateErrors = X509ChainStatusFlags.NoError;
                    rootErrors         = X509ChainStatusFlags.NoError;
                }
                else if ((intermediateErrors & X509ChainStatusFlags.NotSignatureValid) != 0)
                {
                    expectedCount       = 2;
                    intermediateErrors &= ~X509ChainStatusFlags.NotSignatureValid;
                    intermediateErrors |= X509ChainStatusFlags.PartialChain;
                    rootErrors          = X509ChainStatusFlags.NoError;
                }
                else if ((rootErrors & X509ChainStatusFlags.NotSignatureValid) != 0)
                {
                    rootErrors &= ~X509ChainStatusFlags.NotSignatureValid;

                    // On 10.13+ it becomes PartialChain, and UntrustedRoot goes away.
                    if (PlatformDetection.IsOSX)
                    {
                        rootErrors &= ~X509ChainStatusFlags.UntrustedRoot;
                        rootErrors |= X509ChainStatusFlags.PartialChain;
                    }
                }
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                // Windows only reports NotTimeValid on the start-of-chain (end-entity in this case)
                // If it were possible in this suite to get only a higher-level cert as NotTimeValid
                // without the lower one, that would have resulted in NotTimeNested.
                intermediateErrors &= ~X509ChainStatusFlags.NotTimeValid;
                rootErrors         &= ~X509ChainStatusFlags.NotTimeValid;
            }

            X509ChainStatusFlags expectedAllErrors = endEntityErrors | intermediateErrors | rootErrors;

            // If PartialChain or UntrustedRoot are the only remaining errors, the chain will succeed.
            const X509ChainStatusFlags SuccessCodes =
                X509ChainStatusFlags.UntrustedRoot | X509ChainStatusFlags.PartialChain;

            bool expectSuccess = (expectedAllErrors & ~SuccessCodes) == 0;

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.VerificationTime = verificationTime;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                            chain.ChainPolicy.ExtraStore.Add(rootCert);

                            chain.ChainPolicy.VerificationFlags |=
                                X509VerificationFlags.AllowUnknownCertificateAuthority;

                            int i = 0;

                            void CheckChain()
                            {
                                i++;

                                bool valid = chain.Build(endEntityCert);

                                if (expectSuccess)
                                {
                                    Assert.True(valid, $"Chain build on iteration {i}");
                                }
                                else
                                {
                                    Assert.False(valid, $"Chain build on iteration {i}");
                                }

                                Assert.Equal(expectedCount, chain.ChainElements.Count);
                                Assert.Equal(expectedAllErrors, chain.AllStatusFlags());

                                Assert.Equal(endEntityErrors, chain.ChainElements[0].AllStatusFlags());

                                if (expectedCount > 2)
                                {
                                    Assert.Equal(rootErrors, chain.ChainElements[2].AllStatusFlags());
                                }

                                if (expectedCount > 1)
                                {
                                    Assert.Equal(intermediateErrors, chain.ChainElements[1].AllStatusFlags());
                                }

                                chainHolder.DisposeChainElements();
                            }

                            CheckChain();
                            CheckChain();
                        }
        }
Пример #42
0
        public static void X509ChainElementCollection_IndexerVsEnumerator()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes))
            using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
            using (var chainHolder = new ChainHolder())
            {
                X509Chain chain = chainHolder.Chain;

                chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;

                // Halfway between microsoftDotCom's NotBefore and NotAfter
                // This isn't a boundary condition test.
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(microsoftDotCom);
                Assert.True(valid, "Precondition: Chain built validly");

                int position = 0;

                foreach (X509ChainElement chainElement in chain.ChainElements)
                {
                    X509ChainElement indexerElement = chain.ChainElements[position];

                    Assert.NotNull(chainElement);
                    Assert.NotNull(indexerElement);

                    Assert.Same(indexerElement, chainElement);
                    position++;
                }
            }
        }
Пример #43
0
        public static void VerifyChainFromHandle()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            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);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(microsoftDotCom);
                Assert.True(valid, "Source chain built validly");
                Assert.Equal(3, chain.ChainElements.Count);

                using (var chainHolder2 = new ChainHolder(chain.ChainContext))
                {
                    X509Chain chain2 = chainHolder2.Chain;
                    Assert.NotSame(chain, chain2);
                    Assert.Equal(chain.ChainContext, chain2.ChainContext);

                    Assert.Equal(3, chain2.ChainElements.Count);

                    Assert.NotSame(chain.ChainElements[0], chain2.ChainElements[0]);
                    Assert.NotSame(chain.ChainElements[1], chain2.ChainElements[1]);
                    Assert.NotSame(chain.ChainElements[2], chain2.ChainElements[2]);

                    Assert.Equal(microsoftDotCom, chain2.ChainElements[0].Certificate);
                    Assert.Equal(microsoftDotComIssuer, chain2.ChainElements[1].Certificate);
                    Assert.Equal(microsoftDotComRoot, chain2.ChainElements[2].Certificate);

                    // ChainPolicy is not carried over from the Chain(IntPtr) constructor
                    Assert.NotEqual(chain.ChainPolicy.VerificationFlags, chain2.ChainPolicy.VerificationFlags);
                    Assert.NotEqual(chain.ChainPolicy.VerificationTime, chain2.ChainPolicy.VerificationTime);
                    Assert.NotEqual(chain.ChainPolicy.RevocationMode, chain2.ChainPolicy.RevocationMode);
                    Assert.Equal(X509VerificationFlags.NoFlag, chain2.ChainPolicy.VerificationFlags);

                    // Re-set the ChainPolicy properties
                    chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                    chain2.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                    chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                    valid = chain2.Build(microsoftDotCom);
                    Assert.True(valid, "Cloned chain built validly");
                }
            }
        }
Пример #44
0
        public static void FindByValidThumbprint_RootCert()
        {
            using (X509Store machineRoot = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
            {
                machineRoot.Open(OpenFlags.ReadOnly);

                using (var watchedStoreCerts = new ImportedCollection(machineRoot.Certificates))
                {
                    X509Certificate2Collection storeCerts = watchedStoreCerts.Collection;
                    X509Certificate2           rootCert   = null;
                    TimeSpan tolerance = TimeSpan.FromHours(12);

                    // These APIs use local time, so use DateTime.Now, not DateTime.UtcNow.
                    DateTime notBefore = DateTime.Now;
                    DateTime notAfter  = DateTime.Now.Subtract(tolerance);

                    foreach (X509Certificate2 cert in storeCerts)
                    {
                        if (cert.NotBefore >= notBefore || cert.NotAfter <= notAfter)
                        {
                            // Not (safely) valid, skip.
                            continue;
                        }

                        X509KeyUsageExtension keyUsageExtension = null;

                        foreach (X509Extension extension in cert.Extensions)
                        {
                            keyUsageExtension = extension as X509KeyUsageExtension;

                            if (keyUsageExtension != null)
                            {
                                break;
                            }
                        }

                        // Some tool is putting the com.apple.systemdefault utility cert in the
                        // LM\Root store on OSX machines; but it gets rejected by OpenSSL as an
                        // invalid root for not having the Certificate Signing key usage value.
                        //
                        // While the real problem seems to be with whatever tool is putting it
                        // in the bundle; we can work around it here.
                        const X509KeyUsageFlags RequiredFlags = X509KeyUsageFlags.KeyCertSign;

                        // No key usage extension means "good for all usages"
                        if (keyUsageExtension != null &&
                            (keyUsageExtension.KeyUsages & RequiredFlags) != RequiredFlags)
                        {
                            // Not a valid KeyUsage, skip.
                            continue;
                        }

                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            chainHolder.Chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                            if (!chainHolder.Chain.Build(cert))
                            {
                                // Despite being not expired and having a valid KeyUsage, it's
                                // not considered a valid root/chain.
                                continue;
                            }
                        }

                        rootCert = cert;
                        break;
                    }

                    // Just in case someone has a system with no valid trusted root certs whatsoever.
                    if (rootCert != null)
                    {
                        X509Certificate2Collection matches =
                            storeCerts.Find(X509FindType.FindByThumbprint, rootCert.Thumbprint, true);

                        using (new ImportedCollection(matches))
                        {
                            // Improve the debuggability, since the root cert found on each
                            // machine might be different
                            if (matches.Count == 0)
                            {
                                Assert.True(
                                    false,
                                    $"Root certificate '{rootCert.Subject}' ({rootCert.NotBefore} - {rootCert.NotAfter}) is findable with thumbprint '{rootCert.Thumbprint}' and validOnly=true");
                            }

                            Assert.NotSame(rootCert, matches[0]);
                            Assert.Equal(rootCert, matches[0]);
                        }
                    }
                }
            }
        }
Пример #45
0
        public static void VerifyWithRevocation()
        {
            using (var cert = new X509Certificate2(Path.Combine("TestData", "MS.cer")))
            using (var onlineChainHolder = new ChainHolder())
            using (var offlineChainHolder = new ChainHolder())
            {
                X509Chain onlineChain = onlineChainHolder.Chain;
                X509Chain offlineChain = offlineChainHolder.Chain;

                onlineChain.ChainPolicy.VerificationFlags =
                    X509VerificationFlags.AllowUnknownCertificateAuthority;

                onlineChain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);
                onlineChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                onlineChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;

                bool valid = onlineChain.Build(cert);
                Assert.True(valid, "Online Chain Built Validly");

                // Since the network was enabled, we should get the whole chain.
                Assert.Equal(3, onlineChain.ChainElements.Count);

                Assert.Equal(0, onlineChain.ChainElements[0].ChainElementStatus.Length);
                Assert.Equal(0, onlineChain.ChainElements[1].ChainElementStatus.Length);

                // The root CA is not expected to be installed on everyone's machines,
                // so allow for it to report UntrustedRoot, but nothing else..
                X509ChainStatus[] rootElementStatus = onlineChain.ChainElements[2].ChainElementStatus;
                
                if (rootElementStatus.Length != 0)
                {
                    Assert.Equal(1, rootElementStatus.Length);
                    Assert.Equal(X509ChainStatusFlags.UntrustedRoot, rootElementStatus[0].Status);
                }

                // Now that everything is cached, try again in Offline mode.
                offlineChain.ChainPolicy.VerificationFlags = onlineChain.ChainPolicy.VerificationFlags;
                offlineChain.ChainPolicy.VerificationTime = onlineChain.ChainPolicy.VerificationTime;
                offlineChain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
                offlineChain.ChainPolicy.RevocationFlag = onlineChain.ChainPolicy.RevocationFlag;

                valid = offlineChain.Build(cert);
                Assert.True(valid, "Offline Chain Built Validly");

                // Everything should look just like the online chain:
                Assert.Equal(onlineChain.ChainElements.Count, offlineChain.ChainElements.Count);

                for (int i = 0; i < offlineChain.ChainElements.Count; i++)
                {
                    X509ChainElement onlineElement = onlineChain.ChainElements[i];
                    X509ChainElement offlineElement = offlineChain.ChainElements[i];

                    Assert.Equal(onlineElement.ChainElementStatus, offlineElement.ChainElementStatus);
                    Assert.Equal(onlineElement.Certificate, offlineElement.Certificate);
                }
            }
        }