Skip to content

Commit f29b5c5

Browse files
authored
Include Root Certificates in Custom Trust Store (#5624)
* Add new tests * Include root CA's in custom trust store
1 parent 65f382e commit f29b5c5

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

src/Core/Platform/X509ChainCustomization/X509ChainOptions.cs

+8
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public bool TryGetCustomRemoteCertificateValidationCallback(
5353
return false;
5454
}
5555

56+
// Do this outside of the callback so that we aren't opening the root store every request.
57+
using var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine, OpenFlags.ReadOnly);
58+
var rootCertificates = store.Certificates;
59+
5660
// Ref: https://github.com/dotnet/runtime/issues/39835#issuecomment-663020581
5761
callback = (certificate, chain, errors) =>
5862
{
@@ -62,6 +66,10 @@ public bool TryGetCustomRemoteCertificateValidationCallback(
6266
}
6367

6468
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
69+
70+
// We want our additional certificates to be in addition to the machines root store.
71+
chain.ChainPolicy.CustomTrustStore.AddRange(rootCertificates);
72+
6573
foreach (var additionalCertificate in AdditionalCustomTrustCertificates)
6674
{
6775
chain.ChainPolicy.CustomTrustStore.Add(additionalCertificate);

test/Core.Test/Platform/X509ChainCustomization/X509ChainCustomizationServiceCollectionExtensionsTests.cs

+35
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,41 @@ public async Task CallHttpWithSelfSignedCert_SelfSignedCertificateConfigured_Wit
257257
Assert.Equal("Hi", response);
258258
}
259259

260+
[Fact]
261+
public async Task CallHttp_ReachingOutToServerTrustedThroughSystemCA()
262+
{
263+
var services = CreateServices((gs, environment, config) => { }, services =>
264+
{
265+
services.Configure<X509ChainOptions>(options =>
266+
{
267+
options.AdditionalCustomTrustCertificates = [];
268+
});
269+
});
270+
271+
var httpClient = services.GetRequiredService<IHttpClientFactory>().CreateClient();
272+
273+
var response = await httpClient.GetAsync("https://example.com");
274+
response.EnsureSuccessStatusCode();
275+
}
276+
277+
[Fact]
278+
public async Task CallHttpWithCustomTrustForSelfSigned_ReachingOutToServerTrustedThroughSystemCA()
279+
{
280+
var selfSignedCertificate = CreateSelfSignedCert("localhost");
281+
var services = CreateServices((gs, environment, config) => { }, services =>
282+
{
283+
services.Configure<X509ChainOptions>(options =>
284+
{
285+
options.AdditionalCustomTrustCertificates = [selfSignedCertificate];
286+
});
287+
});
288+
289+
var httpClient = services.GetRequiredService<IHttpClientFactory>().CreateClient();
290+
291+
var response = await httpClient.GetAsync("https://example.com");
292+
response.EnsureSuccessStatusCode();
293+
}
294+
260295
private static async Task<IAsyncDisposable> CreateServerAsync(int port, Action<HttpsConnectionAdapterOptions> configure)
261296
{
262297
var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions());

0 commit comments

Comments
 (0)