From 8615e1284613ffcca92a3f6e24d5563c8ff4a3c1 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Tue, 16 Jan 2024 17:35:40 +0100 Subject: [PATCH 1/5] Include necessary sources in unit test project --- ...lStreamCertificateContextOcspLinuxTests.cs | 136 ++++++++++++++++++ .../System.Net.Security.Unit.Tests.csproj | 97 ++++++++++++- 2 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs diff --git a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs new file mode 100644 index 0000000000000..bb191372e09b8 --- /dev/null +++ b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Security.Cryptography.X509Certificates.Tests.Common; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using System.Net.Security; + +using Xunit; + +namespace System.Net.Security.Tests; + +// [OuterLoop("Tests tests run long time")] +public class SslStreamCertificateContextOcspLinuxTests +{ + [Fact] + public async Task Runs() + { + var pkiOptions = PkiOptions.None; + await SimpleTest(pkiOptions, async (root, intermediate, endEntity, ctxFactory, responder) => + { + var ctx = ctxFactory(false); + var ocsp = await ctx.GetOcspResponseAsync(); + }); + } + + private delegate Task RunSimpleTest( + CertificateAuthority root, + CertificateAuthority intermediate, + X509Certificate2 endEntity, + Func ctxFactory, + RevocationResponder responder); + + private static async Task SimpleTest( + PkiOptions pkiOptions, + RunSimpleTest callback, + [CallerMemberName] string callerName = null, + bool pkiOptionsInTestName = true) + { + BuildPrivatePki( + pkiOptions, + out RevocationResponder responder, + out CertificateAuthority root, + out CertificateAuthority intermediate, + out X509Certificate2 endEntity, + callerName, + pkiOptionsInSubject: pkiOptionsInTestName); + + using (responder) + using (root) + using (intermediate) + using (endEntity) + using (X509Certificate2 rootCert = root.CloneIssuerCert()) + using (X509Certificate2 intermediateCert = intermediate.CloneIssuerCert()) + { + if (pkiOptions.HasFlag(PkiOptions.RootAuthorityHasDesignatedOcspResponder)) + { + using (RSA tmpKey = RSA.Create()) + using (X509Certificate2 tmp = root.CreateOcspSigner( + BuildSubject("A Root Designated OCSP Responder", callerName, pkiOptions, true), + tmpKey)) + { + root.DesignateOcspResponder(tmp.CopyWithPrivateKey(tmpKey)); + } + } + + if (pkiOptions.HasFlag(PkiOptions.IssuerAuthorityHasDesignatedOcspResponder)) + { + using (RSA tmpKey = RSA.Create()) + using (X509Certificate2 tmp = intermediate.CreateOcspSigner( + BuildSubject("An Intermediate Designated OCSP Responder", callerName, pkiOptions, true), + tmpKey)) + { + intermediate.DesignateOcspResponder(tmp.CopyWithPrivateKey(tmpKey)); + } + } + + X509Certificate2Collection additionalCerts = new(); + additionalCerts.Add(intermediateCert); + additionalCerts.Add(rootCert); + + Func factory = offline => SslStreamCertificateContext.Create( + endEntity, + additionalCerts, + offline, + trust: null); + + await RetryHelper.ExecuteAsync(() => + { + return callback(root, intermediate, endEntity, factory, responder); + }); + } + } + + internal static void BuildPrivatePki( + PkiOptions pkiOptions, + out RevocationResponder responder, + out CertificateAuthority rootAuthority, + out CertificateAuthority intermediateAuthority, + out X509Certificate2 endEntityCert, + [CallerMemberName] string testName = null, + bool registerAuthorities = true, + bool pkiOptionsInSubject = false) + { + bool issuerRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaCrl); + bool issuerRevocationViaOcsp = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaOcsp); + bool endEntityRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.EndEntityRevocationViaCrl); + bool endEntityRevocationViaOcsp = pkiOptions.HasFlag(PkiOptions.EndEntityRevocationViaOcsp); + + Assert.True( + issuerRevocationViaCrl || issuerRevocationViaOcsp || + endEntityRevocationViaCrl || endEntityRevocationViaOcsp, + "At least one revocation mode is enabled"); + + CertificateAuthority.BuildPrivatePki(pkiOptions, out responder, out rootAuthority, out intermediateAuthority, out endEntityCert, testName, registerAuthorities, pkiOptionsInSubject); + } + + private static string BuildSubject( + string cn, + string testName, + PkiOptions pkiOptions, + bool includePkiOptions) + { + if (includePkiOptions) + { + return $"CN=\"{cn}\", O=\"{testName}\", OU=\"{pkiOptions}\""; + } + + return $"CN=\"{cn}\", O=\"{testName}\""; + } +} diff --git a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj index 62e8134e3377d..e3e81ecb61a3d 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj @@ -40,7 +40,97 @@ Link="CommonTest\System\Net\SslProtocolSupport.cs" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + Date: Wed, 17 Jan 2024 14:42:15 +0100 Subject: [PATCH 2/5] Add tests --- .../SslStreamCertificateContext.Linux.cs | 10 +- ...lStreamCertificateContextOcspLinuxTests.cs | 160 +++++++++++++++++- 2 files changed, 160 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs index b62030a0c1df1..0a5b5c89004b7 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs @@ -17,6 +17,10 @@ namespace System.Net.Security { public partial class SslStreamCertificateContext { + internal static TimeSpan DefaultOcspRefreshInterval => TimeSpan.FromHours(24); + internal static TimeSpan MinRefreshBeforeExpirationInterval => TimeSpan.FromMinutes(5); + internal static TimeSpan RefreshAfterFailureBackOffInterval => TimeSpan.FromSeconds(5); + private const bool TrimRootCertificate = true; internal readonly ConcurrentDictionary SslContexts; internal readonly SafeX509Handle CertificateHandle; @@ -260,8 +264,8 @@ partial void AddRootCertificate(X509Certificate2? rootCertificate, ref bool tran _ocspUrls[i] = tmp; } - DateTimeOffset nextCheckA = DateTimeOffset.UtcNow.AddDays(1); - DateTimeOffset nextCheckB = expiration.AddMinutes(-5); + DateTimeOffset nextCheckA = DateTimeOffset.UtcNow.Add(DefaultOcspRefreshInterval); + DateTimeOffset nextCheckB = expiration.Subtract(MinRefreshBeforeExpirationInterval); _ocspResponse = ret; _ocspExpiration = expiration; @@ -285,7 +289,7 @@ partial void AddRootCertificate(X509Certificate2? rootCertificate, ref bool tran // All download attempts failed, don't try again for 5 seconds. // This backoff will be applied only if the OCSP staple is not expired. // If it is expired, we will force-refresh it during next GetOcspResponseAsync call. - _nextDownload = DateTimeOffset.UtcNow.AddSeconds(5); + _nextDownload = DateTimeOffset.UtcNow.Add(RefreshAfterFailureBackOffInterval); } return ret; } diff --git a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs index bb191372e09b8..3254f2c822b8d 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs @@ -15,17 +15,166 @@ namespace System.Net.Security.Tests; -// [OuterLoop("Tests tests run long time")] public class SslStreamCertificateContextOcspLinuxTests { [Fact] - public async Task Runs() + public async Task OfflineContext_NoFetchOcspResponse() + { + await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) => + { + intermediate.RevocationExpiration = null; + + var ctx = ctxFactory(true); + var ocsp = await ctx.GetOcspResponseAsync(); + Assert.Null(ocsp); + }); + } + + [Fact] + public async Task FetchOcspResponse_NoExpiration_Success() + { + await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) => + { + intermediate.RevocationExpiration = null; + + var ctx = ctxFactory(false); + var ocsp = await ctx.GetOcspResponseAsync(); + Assert.NotNull(ocsp); + }); + } + + [Theory] + [InlineData(PkiOptions.OcspEverywhere)] + [InlineData(PkiOptions.OcspEverywhere | PkiOptions.IssuerAuthorityHasDesignatedOcspResponder)] + public async Task FetchOcspResponse_WithExpiration_Success(PkiOptions pkiOptions) { - var pkiOptions = PkiOptions.None; await SimpleTest(pkiOptions, async (root, intermediate, endEntity, ctxFactory, responder) => { + intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddDays(1); + + var ctx = ctxFactory(false); + var ocsp = await ctx.GetOcspResponseAsync(); + Assert.NotNull(ocsp); + + // should cache and return the same + var ocsp2 = await ctx.GetOcspResponseAsync(); + Assert.Equal(ocsp, ocsp2); + }); + } + + [Fact] + public async Task FetchOcspResponse_Expired_ReturnsNull() + { + await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) => + { + intermediate.RevocationExpiration = DateTimeOffset.UtcNow; + + var ctx = ctxFactory(false); + var ocsp = await ctx.GetOcspResponseAsync(); + Assert.Null(ocsp); + }); + } + + [Fact] + public async Task FetchOcspResponse_FirstInvalidThenValid() + { + await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) => + { + responder.RespondKind = RespondKind.Invalid; + + var ctx = ctxFactory(false); + var ocsp = await ctx.GetOcspResponseAsync(); + Assert.Null(ocsp); + + responder.RespondKind = RespondKind.Normal; + ocsp = await ctx.GetOcspResponseAsync(); + Assert.NotNull(ocsp); + }); + } + + [Fact] + public async Task RefreshOcspResponse_BeforeExpiration() + { + await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) => + { + // Set the expiration to be in the future, but close enough that a refresh gets triggered + intermediate.RevocationExpiration = DateTimeOffset.UtcNow.Add(SslStreamCertificateContext.MinRefreshBeforeExpirationInterval); + var ctx = ctxFactory(false); var ocsp = await ctx.GetOcspResponseAsync(); + Assert.NotNull(ocsp); + + intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddDays(1); + + // first call will dispatch a download and return the cached response, the first call after + // the pending download finishes will return the updated response + var ocsp2 = ctx.GetOcspResponseNoWaiting(); + Assert.Equal(ocsp, ocsp2); + + await RetryHelper.ExecuteAsync(async () => + { + var ocsp3 = await ctx.GetOcspResponseAsync(); + Assert.NotNull(ocsp3); + Assert.NotEqual(ocsp, ocsp3); + }, maxAttempts: 5, backoffFunc: i => (i + 1) * 200 /* ms */); + }); + } + + [Fact] + [OuterLoop("Takes about 3 seconds")] + public async Task RefreshOcspResponse_AfterExpiration() + { + await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) => + { + intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddSeconds(1); + + var ctx = ctxFactory(false); + + await Task.Delay(2000); + + intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddDays(1); + + // The cached OCSP is expired, so the first call will dispatch a download and return the cached response, + var ocsp = ctx.GetOcspResponseNoWaiting(); + Assert.Null(ocsp); + + // subsequent call will return the new response + var ocsp2 = await ctx.GetOcspResponseAsync(); + Assert.NotNull(ocsp2); + }); + } + + [Fact] + [OuterLoop("Takes about 15 seconds")] + public async Task RefreshOcspResponse_FirstInvalidThenValid() + { + Assert.True(SslStreamCertificateContext.MinRefreshBeforeExpirationInterval > SslStreamCertificateContext.RefreshAfterFailureBackOffInterval * 4, "Backoff interval is too long"); + + await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) => + { + // Set the expiration to be in the future, but close enough that a refresh gets triggered + intermediate.RevocationExpiration = DateTimeOffset.UtcNow.Add(SslStreamCertificateContext.MinRefreshBeforeExpirationInterval); + + var ctx = ctxFactory(false); + var ocsp = await ctx.GetOcspResponseAsync(); + Assert.NotNull(ocsp); + + responder.RespondKind = RespondKind.Invalid; + for (int i = 0; i < 3; i++) + { + await Task.Delay(SslStreamCertificateContext.RefreshAfterFailureBackOffInterval); + var ocsp2 = await ctx.GetOcspResponseAsync(); + Assert.Equal(ocsp, ocsp2); + } + + // after responder comes back online, the staple is eventually refreshed + responder.RespondKind = RespondKind.Normal; + await RetryHelper.ExecuteAsync(async () => + { + var ocsp3 = await ctx.GetOcspResponseAsync(); + Assert.NotNull(ocsp3); + Assert.NotEqual(ocsp, ocsp3); + }, maxAttempts: 5, backoffFunc: i => (i + 1) * 200 /* ms */); }); } @@ -90,10 +239,7 @@ private static async Task SimpleTest( offline, trust: null); - await RetryHelper.ExecuteAsync(() => - { - return callback(root, intermediate, endEntity, factory, responder); - }); + await callback(root, intermediate, endEntity, factory, responder); } } From ef906fca0176dd99164970d7114e767d35b6cc09 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 18 Jan 2024 10:07:02 +0100 Subject: [PATCH 3/5] Remove usage of var --- ...lStreamCertificateContextOcspLinuxTests.cs | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs index 3254f2c822b8d..6f5673f431d3d 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs @@ -24,8 +24,8 @@ await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity { intermediate.RevocationExpiration = null; - var ctx = ctxFactory(true); - var ocsp = await ctx.GetOcspResponseAsync(); + SslStreamCertificateContext ctx = ctxFactory(true); + byte[] ocsp = await ctx.GetOcspResponseAsync(); Assert.Null(ocsp); }); } @@ -37,8 +37,8 @@ await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity { intermediate.RevocationExpiration = null; - var ctx = ctxFactory(false); - var ocsp = await ctx.GetOcspResponseAsync(); + SslStreamCertificateContext ctx = ctxFactory(false); + byte[] ocsp = await ctx.GetOcspResponseAsync(); Assert.NotNull(ocsp); }); } @@ -52,12 +52,12 @@ await SimpleTest(pkiOptions, async (root, intermediate, endEntity, ctxFactory, r { intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddDays(1); - var ctx = ctxFactory(false); - var ocsp = await ctx.GetOcspResponseAsync(); + SslStreamCertificateContext ctx = ctxFactory(false); + byte[] ocsp = await ctx.GetOcspResponseAsync(); Assert.NotNull(ocsp); // should cache and return the same - var ocsp2 = await ctx.GetOcspResponseAsync(); + byte[] ocsp2 = await ctx.GetOcspResponseAsync(); Assert.Equal(ocsp, ocsp2); }); } @@ -69,8 +69,8 @@ await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity { intermediate.RevocationExpiration = DateTimeOffset.UtcNow; - var ctx = ctxFactory(false); - var ocsp = await ctx.GetOcspResponseAsync(); + SslStreamCertificateContext ctx = ctxFactory(false); + byte[] ocsp = await ctx.GetOcspResponseAsync(); Assert.Null(ocsp); }); } @@ -82,8 +82,8 @@ await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity { responder.RespondKind = RespondKind.Invalid; - var ctx = ctxFactory(false); - var ocsp = await ctx.GetOcspResponseAsync(); + SslStreamCertificateContext ctx = ctxFactory(false); + byte[] ocsp = await ctx.GetOcspResponseAsync(); Assert.Null(ocsp); responder.RespondKind = RespondKind.Normal; @@ -100,20 +100,20 @@ await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity // Set the expiration to be in the future, but close enough that a refresh gets triggered intermediate.RevocationExpiration = DateTimeOffset.UtcNow.Add(SslStreamCertificateContext.MinRefreshBeforeExpirationInterval); - var ctx = ctxFactory(false); - var ocsp = await ctx.GetOcspResponseAsync(); + SslStreamCertificateContext ctx = ctxFactory(false); + byte[] ocsp = await ctx.GetOcspResponseAsync(); Assert.NotNull(ocsp); intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddDays(1); // first call will dispatch a download and return the cached response, the first call after // the pending download finishes will return the updated response - var ocsp2 = ctx.GetOcspResponseNoWaiting(); + byte[] ocsp2 = ctx.GetOcspResponseNoWaiting(); Assert.Equal(ocsp, ocsp2); await RetryHelper.ExecuteAsync(async () => { - var ocsp3 = await ctx.GetOcspResponseAsync(); + byte[] ocsp3 = await ctx.GetOcspResponseAsync(); Assert.NotNull(ocsp3); Assert.NotEqual(ocsp, ocsp3); }, maxAttempts: 5, backoffFunc: i => (i + 1) * 200 /* ms */); @@ -128,18 +128,18 @@ await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity { intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddSeconds(1); - var ctx = ctxFactory(false); + SslStreamCertificateContext ctx = ctxFactory(false); await Task.Delay(2000); intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddDays(1); // The cached OCSP is expired, so the first call will dispatch a download and return the cached response, - var ocsp = ctx.GetOcspResponseNoWaiting(); + byte[] ocsp = ctx.GetOcspResponseNoWaiting(); Assert.Null(ocsp); // subsequent call will return the new response - var ocsp2 = await ctx.GetOcspResponseAsync(); + byte[] ocsp2 = await ctx.GetOcspResponseAsync(); Assert.NotNull(ocsp2); }); } @@ -155,15 +155,15 @@ await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity // Set the expiration to be in the future, but close enough that a refresh gets triggered intermediate.RevocationExpiration = DateTimeOffset.UtcNow.Add(SslStreamCertificateContext.MinRefreshBeforeExpirationInterval); - var ctx = ctxFactory(false); - var ocsp = await ctx.GetOcspResponseAsync(); + SslStreamCertificateContext ctx = ctxFactory(false); + byte[] ocsp = await ctx.GetOcspResponseAsync(); Assert.NotNull(ocsp); responder.RespondKind = RespondKind.Invalid; for (int i = 0; i < 3; i++) { await Task.Delay(SslStreamCertificateContext.RefreshAfterFailureBackOffInterval); - var ocsp2 = await ctx.GetOcspResponseAsync(); + byte[] ocsp2 = await ctx.GetOcspResponseAsync(); Assert.Equal(ocsp, ocsp2); } @@ -171,7 +171,7 @@ await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity responder.RespondKind = RespondKind.Normal; await RetryHelper.ExecuteAsync(async () => { - var ocsp3 = await ctx.GetOcspResponseAsync(); + byte[] ocsp3 = await ctx.GetOcspResponseAsync(); Assert.NotNull(ocsp3); Assert.NotEqual(ocsp, ocsp3); }, maxAttempts: 5, backoffFunc: i => (i + 1) * 200 /* ms */); From a0d02d6e8b6127d4ddb5cc2fc4fff5fdac5c9b10 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Fri, 19 Jan 2024 10:50:11 +0100 Subject: [PATCH 4/5] Code review feedback --- .../UnitTests/SslStreamCertificateContextOcspLinuxTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs index 6f5673f431d3d..0ee4d1e986014 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs @@ -67,7 +67,7 @@ public async Task FetchOcspResponse_Expired_ReturnsNull() { await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) => { - intermediate.RevocationExpiration = DateTimeOffset.UtcNow; + intermediate.RevocationExpiration = DateTimeOffset.UtcNow.AddMinutes(-5); SslStreamCertificateContext ctx = ctxFactory(false); byte[] ocsp = await ctx.GetOcspResponseAsync(); From 6c22abd29d8524e5957b832ae5538b5162146b11 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Tue, 30 Jan 2024 18:56:36 +0100 Subject: [PATCH 5/5] Remove one OuterLoop attribute --- .../tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs index 0ee4d1e986014..a4d705fa454d3 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/SslStreamCertificateContextOcspLinuxTests.cs @@ -121,7 +121,6 @@ await RetryHelper.ExecuteAsync(async () => } [Fact] - [OuterLoop("Takes about 3 seconds")] public async Task RefreshOcspResponse_AfterExpiration() { await SimpleTest(PkiOptions.OcspEverywhere, async (root, intermediate, endEntity, ctxFactory, responder) =>