diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/AiaTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/AiaTests.cs index 8e1a66a564a975..32a48fb77b8d4f 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/AiaTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/AiaTests.cs @@ -220,26 +220,29 @@ public static void AiaIgnoresCertOverLimit() [Fact] public static void AiaCompletionHasLimits() { - const int IntermediateCount = 6; + const int IntermediateCount = 8; + int iteration = 0; - CertificateAuthority.BuildPrivatePki( - PkiOptions.AllRevocation, - out RevocationResponder responder, - out CertificateAuthority root, - out CertificateAuthority[] intermediates, - out X509Certificate2 endEntity, - intermediateAuthorityCount: IntermediateCount, - pkiOptionsInSubject: false, - testName: nameof(AiaCompletionHasLimits)); - - using (responder) - using (root) - using (endEntity) - { - try + RetryHelper.Execute( + () => { - RetryHelper.Execute( - () => + iteration++; + + CertificateAuthority.BuildPrivatePki( + PkiOptions.AllRevocation, + out RevocationResponder responder, + out CertificateAuthority root, + out CertificateAuthority[] intermediates, + out X509Certificate2 endEntity, + intermediateAuthorityCount: IntermediateCount, + pkiOptionsInSubject: false, + testName: $"{nameof(AiaCompletionHasLimits)}_{iteration}"); + + using (responder) + using (root) + using (endEntity) + { + try { using (ChainHolder holder = new ChainHolder()) { @@ -260,25 +263,60 @@ public static void AiaCompletionHasLimits() // EE, intermediate0 (AIA), intermediate1 (ExtraStore), intermediate2 (AIA). AssertExtensions.TrueExpression(chain.Build(endEntity)); - Assert.Equal(4, chain.ChainElements.Count); - AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags()); - - CloneIntoExtraStore(chain, 1); - CloneIntoExtraStore(chain, 3); - holder.DisposeChainElements(); - // Previous 4 plus intermediate3 and intermediate4. - AssertExtensions.TrueExpression(chain.Build(endEntity)); - Assert.Equal(6, chain.ChainElements.Count); - AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags()); - - CloneIntoExtraStore(chain, 4); - CloneIntoExtraStore(chain, 5); - holder.DisposeChainElements(); + // Current Windows only allows 2, by black box testing, but 3 does seem to happen + // on some builds. So, variant test for it being over-sized + if (chain.ChainElements.Count == 5) + { + // The ones described above, plus intermediate3(AIA). + AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags()); + + CloneIntoExtraStore(chain, 1); + CloneIntoExtraStore(chain, 3); + CloneIntoExtraStore(chain, 4); + holder.DisposeChainElements(); + + // Previous 5 plus intermediate4, intermediate5, and intermediate6. + AssertExtensions.TrueExpression(chain.Build(endEntity)); + Assert.Equal(8, chain.ChainElements.Count); + AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags()); + + CloneIntoExtraStore(chain, 5); + CloneIntoExtraStore(chain, 6); + CloneIntoExtraStore(chain, 7); + holder.DisposeChainElements(); + } + else + { + Assert.Equal(4, chain.ChainElements.Count); + AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags()); + + CloneIntoExtraStore(chain, 1); + CloneIntoExtraStore(chain, 3); + holder.DisposeChainElements(); + + // Previous 4 plus intermediate3 and intermediate4. + AssertExtensions.TrueExpression(chain.Build(endEntity)); + Assert.Equal(6, chain.ChainElements.Count); + AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags()); + + CloneIntoExtraStore(chain, 4); + CloneIntoExtraStore(chain, 5); + holder.DisposeChainElements(); + + // Previous 6 plus intermediate5 and intermediate6. + AssertExtensions.TrueExpression(chain.Build(endEntity)); + Assert.Equal(8, chain.ChainElements.Count); + AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags()); + + CloneIntoExtraStore(chain, 6); + CloneIntoExtraStore(chain, 7); + holder.DisposeChainElements(); + } - // AIA fetches intermediate5 and root, chain finishes. + // AIA fetches intermediate7 and root, chain finishes. AssertExtensions.TrueExpression(chain.Build(endEntity)); - Assert.Equal(8, chain.ChainElements.Count); + Assert.Equal(10, chain.ChainElements.Count); Assert.Equal(X509ChainStatusFlags.UntrustedRoot, chain.AllStatusFlags()); } finally @@ -289,22 +327,25 @@ public static void AiaCompletionHasLimits() } } } - }); - } - finally - { - foreach (CertificateAuthority intermediate in intermediates) - { - intermediate.Dispose(); + } + finally + { + if (intermediates is not null) + { + foreach (CertificateAuthority intermediate in intermediates) + { + intermediate.Dispose(); + } + } + } } - } + }); - static void CloneIntoExtraStore(X509Chain chain, int index) - { - ReadOnlySpan source = chain.ChainElements[index].Certificate.RawDataMemory.Span; - X509Certificate2 cert = X509CertificateLoader.LoadCertificate(source); - chain.ChainPolicy.ExtraStore.Add(cert); - } + static void CloneIntoExtraStore(X509Chain chain, int index) + { + ReadOnlySpan source = chain.ChainElements[index].Certificate.RawDataMemory.Span; + X509Certificate2 cert = X509CertificateLoader.LoadCertificate(source); + chain.ChainPolicy.ExtraStore.Add(cert); } } }