Skip to content

Commit b68154b

Browse files
committed
Reapply "Change HttpClient/SslStream default certificate revocation check mode to Online (#116098)"
This reverts commit defd136.
1 parent defd136 commit b68154b

23 files changed

+450
-427
lines changed

src/libraries/Common/tests/System/Net/Configuration.Certificates.Dynamic.cs

Lines changed: 71 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Net.Security;
45
using System.Runtime.CompilerServices;
56
using System.Runtime.InteropServices;
67
using System.Security.Cryptography;
@@ -37,29 +38,6 @@ public static partial class Certificates
3738
private static readonly X509BasicConstraintsExtension s_eeConstraints =
3839
new X509BasicConstraintsExtension(false, false, 0, false);
3940

40-
private static X509Certificate2 s_dynamicServerCertificate;
41-
private static X509Certificate2Collection s_dynamicCaCertificates;
42-
private static object certLock = new object();
43-
44-
45-
// These Get* methods make a copy of the certificates so that consumers own the lifetime of the
46-
// certificates handed back. Consumers are expected to dispose of their certs when done with them.
47-
48-
public static X509Certificate2 GetDynamicServerCerttificate(X509Certificate2Collection? chainCertificates)
49-
{
50-
lock (certLock)
51-
{
52-
if (s_dynamicServerCertificate == null)
53-
{
54-
CleanupCertificates();
55-
(s_dynamicServerCertificate, s_dynamicCaCertificates) = GenerateCertificates("localhost", nameof(Configuration) + nameof(Certificates));
56-
}
57-
58-
chainCertificates?.AddRange(s_dynamicCaCertificates);
59-
return new X509Certificate2(s_dynamicServerCertificate);
60-
}
61-
}
62-
6341
public static void CleanupCertificates([CallerMemberName] string? testName = null, StoreName storeName = StoreName.CertificateAuthority)
6442
{
6543
string caName = $"O={testName}";
@@ -78,7 +56,9 @@ public static void CleanupCertificates([CallerMemberName] string? testName = nul
7856
}
7957
}
8058
}
81-
catch { };
59+
catch
60+
{
61+
}
8262

8363
try
8464
{
@@ -95,7 +75,9 @@ public static void CleanupCertificates([CallerMemberName] string? testName = nul
9575
}
9676
}
9777
}
98-
catch { };
78+
catch
79+
{
80+
}
9981
}
10082

10183
internal static X509ExtensionCollection BuildTlsServerCertExtensions(string serverName)
@@ -119,7 +101,68 @@ private static X509ExtensionCollection BuildTlsCertExtensions(string targetName,
119101
return extensions;
120102
}
121103

122-
public static (X509Certificate2 certificate, X509Certificate2Collection) GenerateCertificates(string targetName, [CallerMemberName] string? testName = null, bool longChain = false, bool serverCertificate = true, bool ephemeralKey = false)
104+
internal class PkiHolder : IDisposable
105+
{
106+
internal CertificateAuthority Root { get; }
107+
internal CertificateAuthority[] Intermediates { get; }
108+
public X509Certificate2 EndEntity { get; }
109+
public X509Certificate2Collection IssuerChain { get; }
110+
internal RevocationResponder Responder { get; }
111+
112+
private readonly string? _testName;
113+
114+
public PkiHolder(string? testName, CertificateAuthority root, CertificateAuthority[] intermediates, X509Certificate2 endEntity, RevocationResponder responder)
115+
{
116+
_testName = testName;
117+
Root = root;
118+
Intermediates = intermediates;
119+
EndEntity = endEntity;
120+
Responder = responder;
121+
122+
// Walk the intermediates backwards so we build the chain collection as
123+
// Issuer3
124+
// Issuer2
125+
// Issuer1
126+
// Root
127+
IssuerChain = new X509Certificate2Collection();
128+
for (int i = intermediates.Length - 1; i >= 0; i--)
129+
{
130+
CertificateAuthority authority = intermediates[i];
131+
132+
IssuerChain.Add(authority.CloneIssuerCert());
133+
}
134+
135+
IssuerChain.Add(root.CloneIssuerCert());
136+
}
137+
138+
public SslStreamCertificateContext CreateSslStreamCertificateContext()
139+
{
140+
return SslStreamCertificateContext.Create(EndEntity, IssuerChain);
141+
}
142+
143+
public void Dispose()
144+
{
145+
foreach (CertificateAuthority authority in Intermediates)
146+
{
147+
authority.Dispose();
148+
}
149+
Root.Dispose();
150+
EndEntity.Dispose();
151+
Responder.Dispose();
152+
153+
foreach (X509Certificate2 authority in IssuerChain)
154+
{
155+
authority.Dispose();
156+
}
157+
158+
if (PlatformDetection.IsWindows && _testName != null)
159+
{
160+
CleanupCertificates(_testName);
161+
}
162+
}
163+
}
164+
165+
internal static PkiHolder GenerateCertificates(string targetName, [CallerMemberName] string? testName = null, bool longChain = false, bool serverCertificate = true, bool ephemeralKey = false)
123166
{
124167
const int keySize = 2048;
125168
if (PlatformDetection.IsWindows && testName != null)
@@ -131,7 +174,7 @@ public static (X509Certificate2 certificate, X509Certificate2Collection) Generat
131174
X509ExtensionCollection extensions = BuildTlsCertExtensions(targetName, serverCertificate);
132175

133176
CertificateAuthority.BuildPrivatePki(
134-
PkiOptions.IssuerRevocationViaCrl,
177+
PkiOptions.AllRevocation,
135178
out RevocationResponder responder,
136179
out CertificateAuthority root,
137180
out CertificateAuthority[] intermediates,
@@ -142,34 +185,15 @@ public static (X509Certificate2 certificate, X509Certificate2Collection) Generat
142185
keyFactory: CertificateAuthority.KeyFactory.RSASize(keySize),
143186
extensions: extensions);
144187

145-
// Walk the intermediates backwards so we build the chain collection as
146-
// Issuer3
147-
// Issuer2
148-
// Issuer1
149-
// Root
150-
for (int i = intermediates.Length - 1; i >= 0; i--)
151-
{
152-
CertificateAuthority authority = intermediates[i];
153-
154-
chain.Add(authority.CloneIssuerCert());
155-
authority.Dispose();
156-
}
157-
158-
chain.Add(root.CloneIssuerCert());
159-
160-
responder.Dispose();
161-
root.Dispose();
162-
163188
if (!ephemeralKey && PlatformDetection.IsWindows)
164189
{
165190
X509Certificate2 ephemeral = endEntity;
166191
endEntity = X509CertificateLoader.LoadPkcs12(endEntity.Export(X509ContentType.Pfx), (string?)null, X509KeyStorageFlags.Exportable);
167192
ephemeral.Dispose();
168193
}
169194

170-
return (endEntity, chain);
195+
return new PkiHolder(testName, root, intermediates, endEntity, responder);
171196
}
172-
173197
}
174198
}
175199
}

src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public void Ctor_ExpectedDefaultValues()
4848
using (HttpClientHandler handler = CreateHttpClientHandler())
4949
{
5050
Assert.Null(handler.ServerCertificateCustomValidationCallback);
51-
Assert.False(handler.CheckCertificateRevocationList);
51+
Assert.True(handler.CheckCertificateRevocationList);
5252
}
5353
}
5454

@@ -232,7 +232,9 @@ public async Task NoCallback_BadCertificate_ThrowsException(string url)
232232
[ActiveIssue("https://github.com/dotnet/runtime/issues/106634", typeof(PlatformDetection), nameof(PlatformDetection.IsAlpine))]
233233
public async Task NoCallback_RevokedCertificate_NoRevocationChecking_Succeeds()
234234
{
235-
using (HttpClient client = CreateHttpClient())
235+
HttpClientHandler handler = CreateHttpClientHandler();
236+
handler.CheckCertificateRevocationList = false;
237+
using (HttpClient client = CreateHttpClient(handler))
236238
using (HttpResponseMessage response = await client.GetAsync(Configuration.Http.RevokedCertRemoteServer))
237239
{
238240
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -244,7 +246,6 @@ public async Task NoCallback_RevokedCertificate_NoRevocationChecking_Succeeds()
244246
public async Task NoCallback_RevokedCertificate_RevocationChecking_Fails()
245247
{
246248
HttpClientHandler handler = CreateHttpClientHandler();
247-
handler.CheckCertificateRevocationList = true;
248249
using (HttpClient client = CreateHttpClient(handler))
249250
{
250251
await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(Configuration.Http.RevokedCertRemoteServer));

src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public void Ctor_ExpectedDefaultPropertyValues()
7878
Assert.True(handler.SupportsRedirectConfiguration);
7979

8080
// Changes from .NET Framework.
81-
Assert.False(handler.CheckCertificateRevocationList);
81+
Assert.True(handler.CheckCertificateRevocationList);
8282
Assert.Equal(0, handler.MaxRequestContentBufferSize);
8383
Assert.Equal(SslProtocols.None, handler.SslProtocols);
8484
}

src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ System.Net.Http.WinHttpHandler</PackageDescription>
9696
<Compile Include="System\Net\Http\WinHttpTraceHelper.cs" />
9797
<Compile Include="System\Net\Http\WinHttpTrailersHelper.cs" />
9898
<Compile Include="System\Net\Http\WinHttpTransportContext.cs" />
99+
<Compile Include="$(CommonPath)System\AppContextSwitchHelper.cs"
100+
Link="Common\System\AppContextSwitchHelper.cs" />
99101
<Compile Include="$(CommonPath)System\IO\StreamHelpers.CopyValidation.cs"
100102
Link="Common\System\IO\StreamHelpers.CopyValidation.cs" />
101103
<Compile Include="$(CommonPath)System\Net\Logging\NetEventSource.Common.cs"

src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ public class WinHttpHandler : HttpMessageHandler
4343
internal static readonly Version HttpVersion20 = new Version(2, 0);
4444
internal static readonly Version HttpVersion30 = new Version(3, 0);
4545
internal static readonly Version HttpVersionUnknown = new Version(0, 0);
46+
internal static bool DefaultCertificateRevocationCheck { get; } =
47+
AppContextSwitchHelper.GetBooleanConfig(
48+
"System.Net.Security.NoRevocationCheckByDefault",
49+
"DOTNET_SYSTEM_NET_SECURITY_NOREVOCATIONCHECKBYDEFAULT") ? false : true;
50+
4651
internal static bool CertificateCachingAppContextSwitchEnabled { get; } = AppContext.TryGetSwitch("System.Net.Http.UseWinHttpCertificateCaching", out bool enabled) && enabled;
4752
private static readonly TimeSpan s_maxTimeout = TimeSpan.FromMilliseconds(int.MaxValue);
4853

@@ -68,7 +73,7 @@ private Func<
6873
X509Chain,
6974
SslPolicyErrors,
7075
bool>? _serverCertificateValidationCallback;
71-
private bool _checkCertificateRevocationList;
76+
private bool _checkCertificateRevocationList = DefaultCertificateRevocationCheck;
7277
private ClientCertificateOption _clientCertificateOption = ClientCertificateOption.Manual;
7378
private X509Certificate2Collection? _clientCertificates; // Only create collection when required.
7479
private ICredentials? _serverCredentials;

src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
Link="Common\Interop\Windows\WinHttp\Interop.SafeWinHttpHandle.cs" />
2525
<Compile Include="$(CommonPath)Interop\Windows\WinHttp\Interop.winhttp_types.cs"
2626
Link="Common\Interop\Windows\WinHttp\Interop.winhttp_types.cs" />
27+
<Compile Include="$(CommonPath)System\AppContextSwitchHelper.cs"
28+
Link="Common\System\AppContextSwitchHelper.cs" />
2729
<Compile Include="$(CommonPath)System\CharArrayHelpers.cs"
2830
Link="Common\System\CharArrayHelpers.cs" />
2931
<Compile Include="$(CommonPath)System\Obsoletions.cs"

src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public void Ctor_ExpectedDefaultPropertyValues()
4545
Assert.Equal(CookieUsePolicy.UseInternalCookieStoreOnly, handler.CookieUsePolicy);
4646
Assert.Null(handler.CookieContainer);
4747
Assert.Null(handler.ServerCertificateValidationCallback);
48-
Assert.False(handler.CheckCertificateRevocationList);
48+
Assert.True(handler.CheckCertificateRevocationList);
4949
Assert.Equal(ClientCertificateOption.Manual, handler.ClientCertificateOption);
5050
X509Certificate2Collection certs = handler.ClientCertificates;
5151
Assert.True(certs.Count == 0);

0 commit comments

Comments
 (0)