Skip to content

Test Enhancement: Retry entire test for X509 TimeoutTests #42680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 25, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,55 +17,51 @@ public static class TimeoutTests
[PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)]
public static void RevocationCheckingDelayed(PkiOptions pkiOptions)
{
CertificateAuthority.BuildPrivatePki(
pkiOptions,
out RevocationResponder responder,
out CertificateAuthority rootAuthority,
out CertificateAuthority intermediateAuthority,
out X509Certificate2 endEntityCert,
nameof(RevocationCheckingDelayed));

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

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

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

chain.ChainPolicy.DisableCertificateDownloads = true;

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

// There should be two network fetches, OCSP/CRL to intermediate to get leaf status,
// OCSP/CRL to root to get intermediate statuses. It should take at least 2x the delay
// plus other non-network time, so we can at least ensure it took as long as
// the delay for each fetch.
Assert.True(watch.Elapsed >= delay * 2, $"watch.Elapsed: {watch.Elapsed}");
}
RetryHelper.Execute(() => {
CertificateAuthority.BuildPrivatePki(
pkiOptions,
out RevocationResponder responder,
out CertificateAuthority rootAuthority,
out CertificateAuthority intermediateAuthority,
out X509Certificate2 endEntityCert,
nameof(RevocationCheckingDelayed));

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

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

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

chain.ChainPolicy.DisableCertificateDownloads = true;

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

// There should be two network fetches, OCSP/CRL to intermediate to get leaf status,
// OCSP/CRL to root to get intermediate statuses. It should take at least 2x the delay
// plus other non-network time, so we can at least ensure it took as long as
// the delay for each fetch.
Assert.True(watch.Elapsed >= delay * 2, $"watch.Elapsed: {watch.Elapsed}");
}
});
}

[Theory]
Expand Down Expand Up @@ -182,85 +178,83 @@ public static void RevocationCheckingMaximum(PkiOptions pkiOptions)
[PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)]
public static void RevocationCheckingNegativeTimeout(PkiOptions pkiOptions)
{
CertificateAuthority.BuildPrivatePki(
pkiOptions,
out RevocationResponder responder,
out CertificateAuthority rootAuthority,
out CertificateAuthority intermediateAuthority,
out X509Certificate2 endEntityCert,
nameof(RevocationCheckingNegativeTimeout));

using (responder)
using (rootAuthority)
using (intermediateAuthority)
using (endEntityCert)
using (ChainHolder holder = new ChainHolder())
using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
{
// Delay is more than the 15 second default.
TimeSpan delay = TimeSpan.FromSeconds(25);
RetryHelper.Execute(() => {
CertificateAuthority.BuildPrivatePki(
pkiOptions,
out RevocationResponder responder,
out CertificateAuthority rootAuthority,
out CertificateAuthority intermediateAuthority,
out X509Certificate2 endEntityCert,
nameof(RevocationCheckingNegativeTimeout));

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

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

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

chain.ChainPolicy.DisableCertificateDownloads = true;
chain.ChainPolicy.DisableCertificateDownloads = true;

Assert.True(Retry(() => chain.Build(endEntityCert)), $"chain.Build; Chain status: {chain.AllStatusFlags()}");
}
Assert.True(chain.Build(endEntityCert), $"chain.Build; Chain status: {chain.AllStatusFlags()}");
}
});
}

[Fact]
[PlatformSpecific(TestPlatforms.Linux)]
public static void AiaFetchDelayed()
{
CertificateAuthority.BuildPrivatePki(
PkiOptions.OcspEverywhere,
out RevocationResponder responder,
out CertificateAuthority rootAuthority,
out CertificateAuthority intermediateAuthority,
out X509Certificate2 endEntityCert,
nameof(AiaFetchDelayed));
RetryHelper.Execute(() => {
CertificateAuthority.BuildPrivatePki(
PkiOptions.OcspEverywhere,
out RevocationResponder responder,
out CertificateAuthority rootAuthority,
out CertificateAuthority intermediateAuthority,
out X509Certificate2 endEntityCert,
nameof(AiaFetchDelayed));

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

using (responder)
using (rootAuthority)
using (intermediateAuthority)
using (endEntityCert)
using (ChainHolder holder = new ChainHolder())
using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert())
{
TimeSpan delay = TimeSpan.FromSeconds(1);
X509Chain chain = holder.Chain;
responder.ResponseDelay = delay;
responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All;

X509Chain chain = holder.Chain;
responder.ResponseDelay = delay;
responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All;
chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15);
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(rootCert);
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15);
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(rootCert);
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
Stopwatch watch = Stopwatch.StartNew();
Assert.True(chain.Build(endEntityCert), GetFlags(chain, endEntityCert.Thumbprint).ToString());
watch.Stop();

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

Assert.True(watch.Elapsed >= delay, $"watch.Elapsed: {watch.Elapsed}");
}
Assert.True(watch.Elapsed >= delay, $"watch.Elapsed: {watch.Elapsed}");
}
});
}

[Fact]
Expand Down Expand Up @@ -308,18 +302,5 @@ private static X509ChainStatusFlags GetFlags(X509Chain chain, string thumbprint)
chain.ChainElements.OfType<X509ChainElement>().
Single(e => e.Certificate.Thumbprint == thumbprint).
ChainElementStatus.Aggregate((X509ChainStatusFlags)0, (a, e) => a | e.Status);

private static bool Retry(Func<bool> body, int times = 3)
{
for (int attempt = 0; attempt < times; attempt++)
{
if (body())
{
return true;
}
}

return false;
}
}
}