Skip to content

Commit ae6e9c8

Browse files
authored
Make it easier to add certs to the extra store (#29828)
1 parent 0d981a0 commit ae6e9c8

File tree

4 files changed

+46
-1
lines changed

4 files changed

+46
-1
lines changed

src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ private X509ChainPolicy BuildChainPolicy(X509Certificate2 certificate)
212212
chainPolicy.TrustMode = Options.ChainTrustValidationMode;
213213
}
214214

215+
chainPolicy.ExtraStore.AddRange(Options.AdditionalChainCertificates);
216+
215217
if (!Options.ValidateValidityPeriod)
216218
{
217219
chainPolicy.VerificationFlags |= X509VerificationFlags.IgnoreNotTimeValid;

src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public class CertificateAuthenticationOptions : AuthenticationSchemeOptions
2222
/// Collection of X509 certificates which are trusted components of the certificate chain.
2323
/// </summary>
2424
public X509Certificate2Collection CustomTrustStore { get; set; } = new X509Certificate2Collection();
25+
26+
/// <summary>
27+
/// Collection of X509 certificates which are added to the X509Chain.ChainPolicy.ExtraStore of the certificate chain.
28+
/// </summary>
29+
public X509Certificate2Collection AdditionalChainCertificates { get; set; } = new X509Certificate2Collection();
2530

2631
/// <summary>
2732
/// Method used to validate certificate chains against <see cref="CustomTrustStore"/>.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
#nullable enable
2+
Microsoft.AspNetCore.Authentication.Certificate.CertificateAuthenticationOptions.AdditionalChainCertificates.get -> System.Security.Cryptography.X509Certificates.X509Certificate2Collection!
3+
Microsoft.AspNetCore.Authentication.Certificate.CertificateAuthenticationOptions.AdditionalChainCertificates.set -> void

src/Security/Authentication/test/CertificateTests.cs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,41 @@ public async Task VerifyValidClientCertWithTrustedChainAuthenticates()
319319
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
320320
}
321321

322+
[Fact]
323+
public async Task VerifyValidClientCertWithAdditionalCertificatesAuthenticates()
324+
{
325+
using var host = await CreateHost(
326+
new CertificateAuthenticationOptions
327+
{
328+
Events = successfulValidationEvents,
329+
ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust,
330+
CustomTrustStore = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot, },
331+
AdditionalChainCertificates = new X509Certificate2Collection() { Certificates.SignedSecondaryRoot },
332+
RevocationMode = X509RevocationMode.NoCheck
333+
}, Certificates.SignedClient);
334+
335+
using var server = host.GetTestServer();
336+
var response = await server.CreateClient().GetAsync("https://example.com/");
337+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
338+
}
339+
340+
[Fact]
341+
public async Task VerifyValidClientCertFailsWithoutAdditionalCertificatesAuthenticates()
342+
{
343+
using var host = await CreateHost(
344+
new CertificateAuthenticationOptions
345+
{
346+
Events = successfulValidationEvents,
347+
ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust,
348+
CustomTrustStore = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot, },
349+
RevocationMode = X509RevocationMode.NoCheck
350+
}, Certificates.SignedClient);
351+
352+
using var server = host.GetTestServer();
353+
var response = await server.CreateClient().GetAsync("https://example.com/");
354+
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
355+
}
356+
322357
[Fact]
323358
public async Task VerifyHeaderIsUsedIfCertIsNotPresent()
324359
{
@@ -570,7 +605,7 @@ public async Task VerifyValidationResultCanBeCached(bool cache)
570605
Assert.Equal(Expected, name.First().Value);
571606
count = responseAsXml.Elements("claim").Where(claim => claim.Attribute("Type").Value == "ValidationCount");
572607
Assert.Single(count);
573-
var expected = cache ? "1" : "2";
608+
var expected = cache ? "1" : "2";
574609
Assert.Equal(expected, count.First().Value);
575610
}
576611

@@ -693,6 +728,7 @@ private static async Task<IHost> CreateHost(
693728
options.RevocationFlag = configureOptions.RevocationFlag;
694729
options.RevocationMode = configureOptions.RevocationMode;
695730
options.ValidateValidityPeriod = configureOptions.ValidateValidityPeriod;
731+
options.AdditionalChainCertificates = configureOptions.AdditionalChainCertificates;
696732
});
697733
}
698734
else

0 commit comments

Comments
 (0)