From 51b719abf811311c5ef5a9d910362399fea5aecc Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sat, 15 Aug 2020 02:09:15 -0700 Subject: [PATCH] Minimal changes to support certificate chain-preloading at startup --- .../Kestrel/Core/src/Internal/SniOptionsSelector.cs | 7 +++++++ .../Core/src/Middleware/HttpsConnectionMiddleware.cs | 6 ++++++ src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs | 5 ++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/SniOptionsSelector.cs b/src/Servers/Kestrel/Core/src/Internal/SniOptionsSelector.cs index 279ca5c65c38..c5801c46be1f 100644 --- a/src/Servers/Kestrel/Core/src/Internal/SniOptionsSelector.cs +++ b/src/Servers/Kestrel/Core/src/Internal/SniOptionsSelector.cs @@ -68,6 +68,13 @@ public SniOptionsSelector( } } + if (sslOptions.ServerCertificate != null) + { + // This might be do blocking IO but it'll resolve the certificate chain up front before any connections are + // made to the server + sslOptions.ServerCertificateContext = SslStreamCertificateContext.Create((X509Certificate2)sslOptions.ServerCertificate, additionalCertificates: null); + } + if (!certifcateConfigLoader.IsTestMock && sslOptions.ServerCertificate is X509Certificate2 cert2) { HttpsConnectionMiddleware.EnsureCertificateIsAllowedForServerAuth(cert2); diff --git a/src/Servers/Kestrel/Core/src/Middleware/HttpsConnectionMiddleware.cs b/src/Servers/Kestrel/Core/src/Middleware/HttpsConnectionMiddleware.cs index eb8ab43591bf..b131323693ba 100644 --- a/src/Servers/Kestrel/Core/src/Middleware/HttpsConnectionMiddleware.cs +++ b/src/Servers/Kestrel/Core/src/Middleware/HttpsConnectionMiddleware.cs @@ -39,6 +39,7 @@ internal class HttpsConnectionMiddleware // The following fields are only set by HttpsConnectionAdapterOptions ctor. private readonly HttpsConnectionAdapterOptions _options; + private readonly SslStreamCertificateContext _serverCertificateContext; private readonly X509Certificate2 _serverCertificate; private readonly Func _serverCertificateSelector; @@ -89,6 +90,10 @@ public HttpsConnectionMiddleware(ConnectionDelegate next, HttpsConnectionAdapter else { EnsureCertificateIsAllowedForServerAuth(_serverCertificate); + + // This might be do blocking IO but it'll resolve the certificate chain up front before any connections are + // made to the server + _serverCertificateContext = SslStreamCertificateContext.Create(_serverCertificate, additionalCertificates: null); } var remoteCertificateValidationCallback = _options.ClientCertificateMode == ClientCertificateMode.NoCertificate ? @@ -232,6 +237,7 @@ private Task DoOptionsBasedHandshakeAsync(ConnectionContext context, SslStream s var sslOptions = new SslServerAuthenticationOptions { ServerCertificate = _serverCertificate, + ServerCertificateContext = _serverCertificateContext, ServerCertificateSelectionCallback = selector, ClientCertificateRequired = _options.ClientCertificateMode != ClientCertificateMode.NoCertificate, EnabledSslProtocols = _options.SslProtocols, diff --git a/src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs b/src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs index a2c2be973b99..adbe314802be 100644 --- a/src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs +++ b/src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs @@ -385,10 +385,9 @@ public void FallsBackToHttpsConnectionAdapterCertificate() { { "www.example.org", new SniConfig() } }; - var fallbackOptions = new HttpsConnectionAdapterOptions { - ServerCertificate = new X509Certificate2() + ServerCertificate = new X509Certificate2(TestResources.GetCertPath("aspnetdevcert.pfx"), "testPassword") }; var sniOptionsSelector = new SniOptionsSelector( @@ -761,7 +760,7 @@ public X509Certificate2 LoadCertificate(CertificateConfig certInfo, string endpo return null; } - var cert = new X509Certificate2(); + var cert = TestResources.GetTestCertificate(); CertToPathDictionary.Add(cert, certInfo.Path); return cert; }