diff --git a/src/Servers/Kestrel/Core/src/IHttpsConfigurationService.cs b/src/Servers/Kestrel/Core/src/IHttpsConfigurationService.cs
index 7e5a955719fd..171b6a3a86fd 100644
--- a/src/Servers/Kestrel/Core/src/IHttpsConfigurationService.cs
+++ b/src/Servers/Kestrel/Core/src/IHttpsConfigurationService.cs
@@ -90,11 +90,21 @@ void ApplyHttpsConfiguration(
internal readonly struct CertificateAndConfig
{
public readonly X509Certificate2 Certificate;
+ public readonly X509Certificate2Collection CertificateChain;
public readonly CertificateConfig CertificateConfig;
public CertificateAndConfig(X509Certificate2 certificate, CertificateConfig certificateConfig)
+ : this(
+ certificate,
+ certificateConfig,
+ [])
+ {
+ }
+
+ public CertificateAndConfig(X509Certificate2 certificate, CertificateConfig certificateConfig, X509Certificate2Collection certificateChain)
{
Certificate = certificate;
CertificateConfig = certificateConfig;
+ CertificateChain = certificateChain;
}
}
diff --git a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs
index 49842d4c3389..e7e67c67c6d4 100644
--- a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs
+++ b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs
@@ -77,6 +77,8 @@ internal KestrelConfigurationLoader(
private CertificateConfig? DefaultCertificateConfig { get; set; }
internal X509Certificate2? DefaultCertificate { get; set; }
+ internal X509Certificate2Collection? DefaultCertificateChain { get; set; }
+
///
/// Specifies a configuration Action to run when an endpoint with the given name is loaded from configuration.
///
@@ -345,12 +347,14 @@ internal void ProcessEndpointsToAdd()
DefaultCertificateConfig = null;
DefaultCertificate = null;
+ DefaultCertificateChain = null;
ConfigurationReader = new ConfigurationReader(Configuration);
if (_httpsConfigurationService.IsInitialized && _httpsConfigurationService.LoadDefaultCertificate(ConfigurationReader) is CertificateAndConfig certPair)
{
DefaultCertificate = certPair.Certificate;
+ DefaultCertificateChain = certPair.CertificateChain;
DefaultCertificateConfig = certPair.CertificateConfig;
}
diff --git a/src/Servers/Kestrel/Core/src/KestrelServerOptions.cs b/src/Servers/Kestrel/Core/src/KestrelServerOptions.cs
index 63efe1767cad..30c703d9d87f 100644
--- a/src/Servers/Kestrel/Core/src/KestrelServerOptions.cs
+++ b/src/Servers/Kestrel/Core/src/KestrelServerOptions.cs
@@ -303,6 +303,10 @@ internal void ApplyDefaultCertificate(HttpsConnectionAdapterOptions httpsOptions
if (ConfigurationLoader?.DefaultCertificate is X509Certificate2 certificateFromLoader)
{
httpsOptions.ServerCertificate = certificateFromLoader;
+ if (ConfigurationLoader?.DefaultCertificateChain is X509Certificate2Collection certificateChainFromLoader)
+ {
+ httpsOptions.ServerCertificateChain = certificateChainFromLoader;
+ }
return;
}
diff --git a/src/Servers/Kestrel/Core/src/TlsConfigurationLoader.cs b/src/Servers/Kestrel/Core/src/TlsConfigurationLoader.cs
index 2f19ea9acd26..abeb9df5c392 100644
--- a/src/Servers/Kestrel/Core/src/TlsConfigurationLoader.cs
+++ b/src/Servers/Kestrel/Core/src/TlsConfigurationLoader.cs
@@ -128,9 +128,13 @@ public ListenOptions UseHttpsWithSni(
{
if (configurationReader.Certificates.TryGetValue("Default", out var defaultCertConfig))
{
- var (defaultCert, _ /* cert chain */) = _certificateConfigLoader.LoadCertificate(defaultCertConfig, "Default");
+ var (defaultCert, defaultCertChain) = _certificateConfigLoader.LoadCertificate(defaultCertConfig, "Default");
if (defaultCert != null)
{
+ if (defaultCertChain != null)
+ {
+ return new CertificateAndConfig(defaultCert, defaultCertConfig, defaultCertChain);
+ }
return new CertificateAndConfig(defaultCert, defaultCertConfig);
}
}
diff --git a/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs b/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs
index f361e01c903d..b4a55423038b 100644
--- a/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs
+++ b/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs
@@ -196,6 +196,33 @@ public void ConfigureDefaultsAppliesToNewConfigureEndpoints()
Assert.False(serverOptions.CodeBackedListenOptions[0].IsTls);
}
+ [Fact]
+ public void ConfigureDefaultCertificatePathLoadsChain()
+ {
+ var serverOptions = CreateServerOptions();
+ var testCertPath = TestResources.GetCertPath("leaf.com.crt");
+ var ran1 = false;
+ var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
+ {
+ new KeyValuePair("Endpoints:End1:Url", "https://*:5001"),
+ new KeyValuePair("Certificates:Default:Path", testCertPath)
+ }).Build();
+
+ serverOptions.Configure(config)
+ .Endpoint("End1", opt =>
+ {
+ ran1 = true;
+ Assert.True(opt.IsHttps);
+ Assert.NotNull(opt.HttpsOptions.ServerCertificate);
+ Assert.NotNull(opt.HttpsOptions.ServerCertificateChain);
+ Assert.Equal(2, opt.HttpsOptions.ServerCertificateChain.Count);
+ }).Load();
+
+ Assert.True(ran1);
+
+ Assert.True(serverOptions.ConfigurationBackedListenOptions[0].IsTls);
+ }
+
[Fact]
public void ConfigureEndpointDefaultCanEnableHttps()
{