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"); } }
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); } }
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); } }
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(); } }
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(); } }