From eba19659cad8d6c80329abf2fd198c60a532d22c Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 1 Feb 2021 09:37:01 -0800 Subject: [PATCH 1/6] Update CertificateAuthenticationOptions.cs --- .../Certificate/src/CertificateAuthenticationOptions.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs b/src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs index d533e5a978f0..417ae86e669a 100644 --- a/src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs +++ b/src/Security/Authentication/Certificate/src/CertificateAuthenticationOptions.cs @@ -22,6 +22,11 @@ public class CertificateAuthenticationOptions : AuthenticationSchemeOptions /// Collection of X509 certificates which are trusted components of the certificate chain. /// public X509Certificate2Collection CustomTrustStore { get; set; } = new X509Certificate2Collection(); + + /// + /// Collection of X509 certificates which are added to the X509Chain.ChainPolicy.ExtraStore of the certificate chain. + /// + public X509Certificate2Collection AdditionalChainCertificates { get; set; } = new X509Certificate2Collection(); /// /// Method used to validate certificate chains against . From 97828b215b1b0c5a512614e17ea75d4b30cf1b18 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 1 Feb 2021 09:40:26 -0800 Subject: [PATCH 2/6] Update CertificateAuthenticationHandler.cs --- .../Certificate/src/CertificateAuthenticationHandler.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs b/src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs index 0acb8b70c49c..8d5281847077 100644 --- a/src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs +++ b/src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs @@ -212,6 +212,8 @@ private X509ChainPolicy BuildChainPolicy(X509Certificate2 certificate) chainPolicy.TrustMode = Options.ChainTrustValidationMode; } + chainPolicy.ExtraStore.AddRange(Options.AdditionalChainCertificates); + if (!Options.ValidateValidityPeriod) { chainPolicy.VerificationFlags |= X509VerificationFlags.IgnoreNotTimeValid; From f3e805d5e06808a222da5bff702d8b8e141e3fa8 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 1 Feb 2021 09:49:18 -0800 Subject: [PATCH 3/6] Update CertificateTests.cs --- .../Authentication/test/CertificateTests.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Security/Authentication/test/CertificateTests.cs b/src/Security/Authentication/test/CertificateTests.cs index 7ece7586b8d4..9ec04d3e74ab 100644 --- a/src/Security/Authentication/test/CertificateTests.cs +++ b/src/Security/Authentication/test/CertificateTests.cs @@ -319,6 +319,22 @@ public async Task VerifyValidClientCertWithTrustedChainAuthenticates() Assert.Equal(HttpStatusCode.OK, response.StatusCode); } + [Fact] + public async Task VerifyValidClientCertWithAdditionalCertificatesAuthenticates() + { + using var host = await CreateHost( + new CertificateAuthenticationOptions + { + Events = successfulValidationEvents, + AdditionalChainCertificates = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot }, + RevocationMode = X509RevocationMode.NoCheck + }, Certificates.SignedClient); + + using var server = host.GetTestServer(); + var response = await server.CreateClient().GetAsync("https://example.com/"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + [Fact] public async Task VerifyHeaderIsUsedIfCertIsNotPresent() { From dbc6004a72765f1dee1ea42b6ae3abd660002459 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 1 Feb 2021 09:57:45 -0800 Subject: [PATCH 4/6] Update baseline --- .../Authentication/Certificate/src/PublicAPI.Unshipped.txt | 2 ++ src/Security/Authentication/test/CertificateTests.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Security/Authentication/Certificate/src/PublicAPI.Unshipped.txt b/src/Security/Authentication/Certificate/src/PublicAPI.Unshipped.txt index 7dc5c58110bf..ee3ca4344c56 100644 --- a/src/Security/Authentication/Certificate/src/PublicAPI.Unshipped.txt +++ b/src/Security/Authentication/Certificate/src/PublicAPI.Unshipped.txt @@ -1 +1,3 @@ #nullable enable +Microsoft.AspNetCore.Authentication.Certificate.CertificateAuthenticationOptions.AdditionalChainCertificates.get -> System.Security.Cryptography.X509Certificates.X509Certificate2Collection! +Microsoft.AspNetCore.Authentication.Certificate.CertificateAuthenticationOptions.AdditionalChainCertificates.set -> void diff --git a/src/Security/Authentication/test/CertificateTests.cs b/src/Security/Authentication/test/CertificateTests.cs index 9ec04d3e74ab..3c509f8ea68d 100644 --- a/src/Security/Authentication/test/CertificateTests.cs +++ b/src/Security/Authentication/test/CertificateTests.cs @@ -334,7 +334,7 @@ public async Task VerifyValidClientCertWithAdditionalCertificatesAuthenticates() var response = await server.CreateClient().GetAsync("https://example.com/"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } - + [Fact] public async Task VerifyHeaderIsUsedIfCertIsNotPresent() { @@ -586,7 +586,7 @@ public async Task VerifyValidationResultCanBeCached(bool cache) Assert.Equal(Expected, name.First().Value); count = responseAsXml.Elements("claim").Where(claim => claim.Attribute("Type").Value == "ValidationCount"); Assert.Single(count); - var expected = cache ? "1" : "2"; + var expected = cache ? "1" : "2"; Assert.Equal(expected, count.First().Value); } From 39dad31b25a3d4f442675529f8e535fd0011f8e7 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Tue, 2 Feb 2021 12:57:45 -0800 Subject: [PATCH 5/6] Actualy copy the additional chain certs --- src/Security/Authentication/test/CertificateTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Security/Authentication/test/CertificateTests.cs b/src/Security/Authentication/test/CertificateTests.cs index 3c509f8ea68d..39de0d4e38c9 100644 --- a/src/Security/Authentication/test/CertificateTests.cs +++ b/src/Security/Authentication/test/CertificateTests.cs @@ -326,7 +326,7 @@ public async Task VerifyValidClientCertWithAdditionalCertificatesAuthenticates() new CertificateAuthenticationOptions { Events = successfulValidationEvents, - AdditionalChainCertificates = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot }, + AdditionalChainCertificates = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot, Certificates.SignedSecondaryRoot }, RevocationMode = X509RevocationMode.NoCheck }, Certificates.SignedClient); @@ -709,6 +709,7 @@ private static async Task CreateHost( options.RevocationFlag = configureOptions.RevocationFlag; options.RevocationMode = configureOptions.RevocationMode; options.ValidateValidityPeriod = configureOptions.ValidateValidityPeriod; + options.AdditionalChainCertificates = configureOptions.AdditionalChainCertificates; }); } else From 42f0e70068d4fb606c9e7c0e72bcbe8e18e47d42 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Wed, 3 Feb 2021 13:51:41 -0800 Subject: [PATCH 6/6] Update tests --- .../Authentication/test/CertificateTests.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Security/Authentication/test/CertificateTests.cs b/src/Security/Authentication/test/CertificateTests.cs index 39de0d4e38c9..fc1dd46e0b1c 100644 --- a/src/Security/Authentication/test/CertificateTests.cs +++ b/src/Security/Authentication/test/CertificateTests.cs @@ -326,7 +326,9 @@ public async Task VerifyValidClientCertWithAdditionalCertificatesAuthenticates() new CertificateAuthenticationOptions { Events = successfulValidationEvents, - AdditionalChainCertificates = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot, Certificates.SignedSecondaryRoot }, + ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust, + CustomTrustStore = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot, }, + AdditionalChainCertificates = new X509Certificate2Collection() { Certificates.SignedSecondaryRoot }, RevocationMode = X509RevocationMode.NoCheck }, Certificates.SignedClient); @@ -335,6 +337,23 @@ public async Task VerifyValidClientCertWithAdditionalCertificatesAuthenticates() Assert.Equal(HttpStatusCode.OK, response.StatusCode); } + [Fact] + public async Task VerifyValidClientCertFailsWithoutAdditionalCertificatesAuthenticates() + { + using var host = await CreateHost( + new CertificateAuthenticationOptions + { + Events = successfulValidationEvents, + ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust, + CustomTrustStore = new X509Certificate2Collection() { Certificates.SelfSignedPrimaryRoot, }, + RevocationMode = X509RevocationMode.NoCheck + }, Certificates.SignedClient); + + using var server = host.GetTestServer(); + var response = await server.CreateClient().GetAsync("https://example.com/"); + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + [Fact] public async Task VerifyHeaderIsUsedIfCertIsNotPresent() {