diff --git a/src/Servers/Kestrel/Core/src/CoreStrings.resx b/src/Servers/Kestrel/Core/src/CoreStrings.resx
index 46f2e263a326..49c2f5fb482c 100644
--- a/src/Servers/Kestrel/Core/src/CoreStrings.resx
+++ b/src/Servers/Kestrel/Core/src/CoreStrings.resx
@@ -614,4 +614,10 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
A TimeSpan value greater than or equal to {value} is required.
+
+ The provided key file is missing or invalid.
+
+
+ Unknown algorithm for certificate with public key type '{0}'.
+
\ No newline at end of file
diff --git a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs
index 31e4270131bd..2843bb014c5e 100644
--- a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs
@@ -205,6 +205,8 @@ public CertificateConfig(IConfigurationSection configSection)
public string Path { get; set; }
+ public string KeyPath { get; set; }
+
public string Password { get; set; }
// Cert store
diff --git a/src/Servers/Kestrel/Core/src/Internal/LoggerExtensions.cs b/src/Servers/Kestrel/Core/src/Internal/LoggerExtensions.cs
index 1fedf58ae5cd..a28c74ae872e 100644
--- a/src/Servers/Kestrel/Core/src/Internal/LoggerExtensions.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/LoggerExtensions.cs
@@ -46,6 +46,18 @@ internal static class LoggerExtensions
new EventId(5, "DeveloperCertificateFirstRun"),
"{Message}");
+ private static readonly Action _failedToLoadCertificate =
+ LoggerMessage.Define(
+ LogLevel.Error,
+ new EventId(6, "MissingOrInvalidCertificateFile"),
+ "The certificate file at '{CertificateFilePath}' can not be found, contains malformed data or does not contain a certificate.");
+
+ private static readonly Action _failedToLoadCertificateKey =
+ LoggerMessage.Define(
+ LogLevel.Error,
+ new EventId(7, "MissingOrInvalidCertificateKeyFile"),
+ "The certificate key file at '{CertificateKeyFilePath}' can not be found, contains malformed data or does not contain a PEM encoded key in PKCS8 format.");
+
public static void LocatedDevelopmentCertificate(this ILogger logger, X509Certificate2 certificate) => _locatedDevelopmentCertificate(logger, certificate.Subject, certificate.Thumbprint, null);
public static void UnableToLocateDevelopmentCertificate(this ILogger logger) => _unableToLocateDevelopmentCertificate(logger, null);
@@ -57,5 +69,8 @@ internal static class LoggerExtensions
public static void BadDeveloperCertificateState(this ILogger logger) => _badDeveloperCertificateState(logger, null);
public static void DeveloperCertificateFirstRun(this ILogger logger, string message) => _developerCertificateFirstRun(logger, message, null);
+
+ public static void FailedToLoadCertificate(this ILogger logger, string certificatePath) => _failedToLoadCertificate(logger, certificatePath, null);
+ public static void FailedToLoadCertificateKey(this ILogger logger, string certificateKeyPath) => _failedToLoadCertificateKey(logger, certificateKeyPath, null);
}
}
diff --git a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs
index ad7210b6d655..04349031e2d1 100644
--- a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs
+++ b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs
@@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Net;
+using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
@@ -429,20 +430,133 @@ private bool TryGetCertificatePath(out string path)
private X509Certificate2 LoadCertificate(CertificateConfig certInfo, string endpointName)
{
+ var logger = Options.ApplicationServices.GetRequiredService>();
if (certInfo.IsFileCert && certInfo.IsStoreCert)
{
throw new InvalidOperationException(CoreStrings.FormatMultipleCertificateSources(endpointName));
}
else if (certInfo.IsFileCert)
{
- var env = Options.ApplicationServices.GetRequiredService();
- return new X509Certificate2(Path.Combine(env.ContentRootPath, certInfo.Path), certInfo.Password);
+ var environment = Options.ApplicationServices.GetRequiredService();
+ var certificatePath = Path.Combine(environment.ContentRootPath, certInfo.Path);
+ if (certInfo.KeyPath != null)
+ {
+ var certificateKeyPath = Path.Combine(environment.ContentRootPath, certInfo.KeyPath);
+ var certificate = GetCertificate(certificatePath);
+
+ if (certificate != null)
+ {
+ certificate = LoadCertificateKey(certificate, certificateKeyPath, certInfo.Password);
+ }
+ else
+ {
+ logger.FailedToLoadCertificate(certificateKeyPath);
+ }
+
+ if (certificate != null)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return PersistKey(certificate);
+ }
+
+ return certificate;
+ }
+ else
+ {
+ logger.FailedToLoadCertificateKey(certificateKeyPath);
+ }
+
+ throw new InvalidOperationException(CoreStrings.InvalidPemKey);
+ }
+
+ return new X509Certificate2(Path.Combine(environment.ContentRootPath, certInfo.Path), certInfo.Password);
}
else if (certInfo.IsStoreCert)
{
return LoadFromStoreCert(certInfo);
}
return null;
+
+ static X509Certificate2 PersistKey(X509Certificate2 fullCertificate)
+ {
+ // We need to force the key to be persisted.
+ // See https://github.com/dotnet/runtime/issues/23749
+ var certificateBytes = fullCertificate.Export(X509ContentType.Pkcs12, "");
+ return new X509Certificate2(certificateBytes, "", X509KeyStorageFlags.DefaultKeySet);
+ }
+
+ static X509Certificate2 LoadCertificateKey(X509Certificate2 certificate, string keyPath, string password)
+ {
+ // OIDs for the certificate key types.
+ const string RSAOid = "1.2.840.113549.1.1.1";
+ const string DSAOid = "1.2.840.10040.4.1";
+ const string ECDsaOid = "1.2.840.10045.2.1";
+
+ var keyText = File.ReadAllText(keyPath);
+ return certificate.PublicKey.Oid.Value switch
+ {
+ RSAOid => AttachPemRSAKey(certificate, keyText, password),
+ ECDsaOid => AttachPemECDSAKey(certificate, keyText, password),
+ DSAOid => AttachPemDSAKey(certificate, keyText, password),
+ _ => throw new InvalidOperationException(string.Format(CoreStrings.UnrecognizedCertificateKeyOid, certificate.PublicKey.Oid.Value))
+ };
+ }
+
+ static X509Certificate2 GetCertificate(string certificatePath)
+ {
+ if (X509Certificate2.GetCertContentType(certificatePath) == X509ContentType.Cert)
+ {
+ return new X509Certificate2(certificatePath);
+ }
+
+ return null;
+ }
+ }
+
+ private static X509Certificate2 AttachPemRSAKey(X509Certificate2 certificate, string keyText, string password)
+ {
+ using var rsa = RSA.Create();
+ if (password == null)
+ {
+ rsa.ImportFromPem(keyText);
+ }
+ else
+ {
+ rsa.ImportFromEncryptedPem(keyText, password);
+ }
+
+ return certificate.CopyWithPrivateKey(rsa);
+ }
+
+ private static X509Certificate2 AttachPemDSAKey(X509Certificate2 certificate, string keyText, string password)
+ {
+ using var dsa = DSA.Create();
+ if (password == null)
+ {
+ dsa.ImportFromPem(keyText);
+ }
+ else
+ {
+ dsa.ImportFromEncryptedPem(keyText, password);
+ }
+
+ return certificate.CopyWithPrivateKey(dsa);
+ }
+
+ private static X509Certificate2 AttachPemECDSAKey(X509Certificate2 certificate, string keyText, string password)
+ {
+ using var ecdsa = ECDsa.Create();
+ if (password == null)
+ {
+ ecdsa.ImportFromPem(keyText);
+ }
+ else
+ {
+ ecdsa.ImportFromEncryptedPem(keyText, password);
+ }
+
+ return certificate.CopyWithPrivateKey(ecdsa);
}
private static X509Certificate2 LoadFromStoreCert(CertificateConfig certInfo)
diff --git a/src/Servers/Kestrel/Core/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj b/src/Servers/Kestrel/Core/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj
index 108edc514d13..8786fa6969ee 100644
--- a/src/Servers/Kestrel/Core/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj
+++ b/src/Servers/Kestrel/Core/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj
@@ -13,6 +13,8 @@
+
+
diff --git a/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs b/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs
index fb0b182cdd28..5053b3cffb12 100644
--- a/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs
+++ b/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs
@@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Security.Authentication;
+using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Microsoft.AspNetCore.Hosting;
@@ -25,7 +26,7 @@ public class KestrelConfigurationLoaderTests
private KestrelServerOptions CreateServerOptions()
{
var serverOptions = new KestrelServerOptions();
- var env = new MockHostingEnvironment { ApplicationName = "TestApplication" };
+ var env = new MockHostingEnvironment { ApplicationName = "TestApplication", ContentRootPath = Directory.GetCurrentDirectory() };
serverOptions.ApplicationServices = new ServiceCollection()
.AddLogging()
.AddSingleton(env)
@@ -254,6 +255,121 @@ public void ConfigureEndpointDevelopmentCertificateGetsLoadedWhenPresent()
}
}
+ [Fact]
+ public void ConfigureEndpoint_ThrowsWhen_The_PasswordIsMissing()
+ {
+ var serverOptions = CreateServerOptions();
+ var certificate = new X509Certificate2(TestResources.GetCertPath("https-aspnet.crt"));
+
+ var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
+ {
+ new KeyValuePair("Endpoints:End1:Url", "https://*:5001"),
+ new KeyValuePair("Certificates:Default:Path", Path.Combine("shared", "TestCertificates", "https-aspnet.crt")),
+ new KeyValuePair("Certificates:Default:KeyPath", Path.Combine("shared", "TestCertificates", "https-aspnet.key"))
+ }).Build();
+
+ var ex = Assert.Throws(() =>
+ {
+ serverOptions
+ .Configure(config)
+ .Endpoint("End1", opt =>
+ {
+ Assert.True(opt.IsHttps);
+ }).Load();
+ });
+ }
+
+ [Fact]
+ public void ConfigureEndpoint_ThrowsWhen_TheKeyDoesntMatchTheCertificateKey()
+ {
+ var serverOptions = CreateServerOptions();
+ var certificate = new X509Certificate2(TestResources.GetCertPath("https-aspnet.crt"));
+
+ var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
+ {
+ new KeyValuePair("Endpoints:End1:Url", "https://*:5001"),
+ new KeyValuePair("Certificates:Default:Path", Path.Combine("shared", "TestCertificates", "https-aspnet.crt")),
+ new KeyValuePair("Certificates:Default:KeyPath", Path.Combine("shared", "TestCertificates", "https-ecdsa.key")),
+ new KeyValuePair("Certificates:Default:Password", "aspnetcore")
+ }).Build();
+
+ var ex = Assert.Throws(() =>
+ {
+ serverOptions
+ .Configure(config)
+ .Endpoint("End1", opt =>
+ {
+ Assert.True(opt.IsHttps);
+ }).Load();
+ });
+ }
+
+ [Fact]
+ public void ConfigureEndpoint_ThrowsWhen_The_PasswordIsIncorrect()
+ {
+ var serverOptions = CreateServerOptions();
+ var certificate = new X509Certificate2(TestResources.GetCertPath("https-aspnet.crt"));
+
+ var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
+ {
+ new KeyValuePair("Endpoints:End1:Url", "https://*:5001"),
+ new KeyValuePair("Certificates:Default:Path", Path.Combine("shared", "TestCertificates", "https-aspnet.crt")),
+ new KeyValuePair("Certificates:Default:KeyPath", Path.Combine("shared", "TestCertificates", "https-aspnet.key")),
+ new KeyValuePair("Certificates:Default:Password", "abcde"),
+ }).Build();
+
+ var ex = Assert.Throws(() =>
+ {
+ serverOptions
+ .Configure(config)
+ .Endpoint("End1", opt =>
+ {
+ Assert.True(opt.IsHttps);
+ }).Load();
+ });
+ }
+
+ [Theory]
+ [InlineData("https-rsa.pem", "https-rsa.key", null)]
+ [InlineData("https-rsa.pem", "https-rsa-protected.key", "aspnetcore")]
+ [InlineData("https-rsa.crt", "https-rsa.key", null)]
+ [InlineData("https-rsa.crt", "https-rsa-protected.key", "aspnetcore")]
+ [InlineData("https-ecdsa.pem", "https-ecdsa.key", null)]
+ [InlineData("https-ecdsa.pem", "https-ecdsa-protected.key", "aspnetcore")]
+ [InlineData("https-ecdsa.crt", "https-ecdsa.key", null)]
+ [InlineData("https-ecdsa.crt", "https-ecdsa-protected.key", "aspnetcore")]
+ [InlineData("https-dsa.pem", "https-dsa.key", null)]
+ [InlineData("https-dsa.pem", "https-dsa-protected.key", "test")]
+ [InlineData("https-dsa.crt", "https-dsa.key", null)]
+ [InlineData("https-dsa.crt", "https-dsa-protected.key", "test")]
+ public void ConfigureEndpoint_CanLoadPemCertificates(string certificateFile, string certificateKey, string password)
+ {
+ var serverOptions = CreateServerOptions();
+ var certificate = new X509Certificate2(TestResources.GetCertPath(Path.ChangeExtension(certificateFile, "crt")));
+
+ var ran1 = false;
+ var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
+ {
+ new KeyValuePair("Endpoints:End1:Url", "https://*:5001"),
+ new KeyValuePair("Certificates:Default:Path", Path.Combine("shared", "TestCertificates", certificateFile)),
+ new KeyValuePair("Certificates:Default:KeyPath", Path.Combine("shared", "TestCertificates", certificateKey)),
+ }
+ .Concat(password != null ? new[] { new KeyValuePair("Certificates:Default:Password", password) } : Array.Empty>()))
+ .Build();
+
+ serverOptions
+ .Configure(config)
+ .Endpoint("End1", opt =>
+ {
+ ran1 = true;
+ Assert.True(opt.IsHttps);
+ Assert.Equal(opt.HttpsOptions.ServerCertificate.SerialNumber, certificate.SerialNumber);
+ }).Load();
+
+ Assert.True(ran1);
+ Assert.NotNull(serverOptions.DefaultCertificate);
+ }
+
[Fact]
public void ConfigureEndpointDevelopmentCertificateGetsIgnoredIfPasswordIsNotCorrect()
{
diff --git a/src/Servers/Kestrel/Kestrel/test/Microsoft.AspNetCore.Server.Kestrel.Tests.csproj b/src/Servers/Kestrel/Kestrel/test/Microsoft.AspNetCore.Server.Kestrel.Tests.csproj
index 571f2cda3028..f4106e104099 100644
--- a/src/Servers/Kestrel/Kestrel/test/Microsoft.AspNetCore.Server.Kestrel.Tests.csproj
+++ b/src/Servers/Kestrel/Kestrel/test/Microsoft.AspNetCore.Server.Kestrel.Tests.csproj
@@ -8,6 +8,9 @@
+
+
+
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/.gitattributes b/src/Servers/Kestrel/shared/test/TestCertificates/.gitattributes
new file mode 100644
index 000000000000..911dbdca5c4b
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/.gitattributes
@@ -0,0 +1,2 @@
+*.key binary
+*.pem binary
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-aspnet.crt b/src/Servers/Kestrel/shared/test/TestCertificates/https-aspnet.crt
new file mode 100644
index 000000000000..0421f377734d
Binary files /dev/null and b/src/Servers/Kestrel/shared/test/TestCertificates/https-aspnet.crt differ
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-aspnet.key b/src/Servers/Kestrel/shared/test/TestCertificates/https-aspnet.key
new file mode 100644
index 000000000000..34fba0f776de
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-aspnet.key
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFNjBgBgkqhkiG9w0BBQ0wUzAyBgkqhkiG9w0BBQwwJQQQ93oRxzJ5UoNOb/zN
+x5cdsAIDAYagMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAuHsE18X/Z9ZVe
+aBl7C55nBIIE0AABqjc9ERcLYNpCRpA6c/TFG62m4Mr9J4dU4g1WD07t7uLxZiRi
+Pl0YOjCulljMsevAW5PlLxi4ffJ+I0/UB1WOfzEMhcj7o1qG0Uv55B7WRuWKw1Zr
+jo0bDY5Man48ZjpqMMBdnWhyHdIDm+WD0OyN98mpsN6SCQMjvx91M+klrsp7LOMM
+88HHS0RFVKGF9hYSy6rCwMJWf+7QGO2wXfq+MKvJ/bBgPGDLwN4phUCyocnR0swD
+/XZNiiw0xIC8OxAKhc6BV4AJkjNs32THdBOCGY6B4P/9Zo5W29S3ja/hGsMQAA27
+QtIDg74HpX7TgIyqoc1oiLNIWW/+jUHSEYJsTPlg5VYWsXUfSHZpz8EJvKt2tyvt
+vBGOCLDDZD4GVXhPigKG6zJSJeTe94/VlwPhNSEucKeaALdax5t3HvPNzWKFX57E
+aC82/IxRrjgHmgsGSZdMi08HY6K9GAVBFpIGvXOGtRq7w8zO/KagAvSwAOLLtOs7
+iEuAQxD+cKLRT59c4E7r5W7BT+faq85ovqdXe5Edtl3cT81zsl27pZvQrcrTPbZe
+4OeIdWxOmOnC/bXvRHNd9XuYadXXazBoFbe9yPwjqnflEh39CyvlOZXeaQXSdsEM
+1IBhddRTorO/I8M/znu9glqIa5ya1NA+4ujmf4OnJLtsrlKQa65VPVTrFdeYuMr0
+VfOuuIye2OdyJ6jS0a1PYQm4bEEz6UR88dnmnhDx6i8/l2wW5+CArA/x8IBYboBM
+NJpJY9bHpic1AhjnjnTtFz2s4uYPi5g9peBizarZn+6OJvgYqs4a8SI92dA3E2o4
+a/1j7xlLlgXnVRLBMibxqzjMt4Zt7Nj+BaN1owrB/q04AWS2M4TSQz+NYOZwNFxB
+dzb+fysTLK5XNEYq6rSg+0i+EKZl8Jb/t4d8SLPVr/tdfDt9BtZ0nTgjvy1HWy1p
+kQdm13XfK1/9KsePH/Jb6dvN/u6ubV+ZqI7Bc7VyTi0bKMdpH2K8/dtopNyDZ/P+
+/IsyyDYTorgJB/klSih/W0hqpSBbEAmlSBfBxP1/ozBEGR2oF20JOCFyD6UXQR/1
+V7r2KtplpyfXaIWh4fABitAMHz7VgmEIQ2H9cB4Ey9jdRPQ/1p+OgGjfaFJQ0uYM
+987TDtjkuukJYnPZNIIx0Yv3iAX16XmhzJixWSMUIJiWfSiz0aTjBxsPQVPTQV+M
+6BgFf3riBApZYlVVJsGIie2XTvu/tHRhfQrxccl63HN7yAeJheQnoscin6Z5TKN/
+U8Ouy/QGiATatKUEUjr4lN+BYySf8F6e3cAAeAx/ZnFvGw5z8fwNYBjVWg/83bTw
+9rS+tSk8VsvTdkcKoNbbDtw+SwYfZSbMUBFm0B13190iJZoyWI+5ZKPnZ2CvOZhX
+PjGTOnh6Diq907l2Q7S/v8SLe0bCHCHVBy+CcPWVDZ6Z7V5cJ/W8TvFPcSGw1UCl
+tKPp862uDaPKvGxqGDq0vGouEUrtJKZ279Lnrtz1n8raUj0Gxa+KXqLACh8dXCzK
+ZgCTPhfAjZcYgA73edW0whNNH9MNInDGulT/arCK3HTkFPczD+7wA8Ojw/LxKFJs
+0d8vtILbmLv46CO+wvIdWrW1c7PCrGJDf9Zuw06vIH7hpW9swSM55k9/
+-----END ENCRYPTED PRIVATE KEY-----
\ No newline at end of file
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa-protected.key b/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa-protected.key
new file mode 100644
index 000000000000..196ea3217f94
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa-protected.key
@@ -0,0 +1,11 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBoTBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQI+PhdT1Kk/SkCAggA
+MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECGV1ZmaiQtz2BIIBUA/6pNqTkXpkOLlI
+22Lh0cm5+/foDRh3qTrAOSHHHV0Dz1xYvYMa9MFzONatLf55Rpb2ZPji3hXwUQfn
+gOJeTBRTaMNz5LaKJiOIWj0qDckhgKt9cmgiBzVTvXO4pERp1uz5zcvaUOKj2TSv
+ljxishj76MYQftIGMMkJQKf4OsHubCopuKUbzTPgJt0FuF4eT37+tiEMgbYrmA6p
+REPE0vT1aY+LYdJLV/Dax/l4lMvYmQYOWs9TCLPlI5RZQxxte6zbcA13ESg/qLE3
+4Mx8xgXrPvCxp3h8KBKNMaJR1xzpr7UQOpkI9qja++3cJAl6O/0mdeqZct0V9Z8P
+a3+wyUWo58z5sOPNdJHIMV6qw6m3w+IQoCJC7EbV0+Pyo5eSU5zbgm7YWZ9Yx6l8
+g1mCP4Q6Tqe6LjKfBsZAmYWSfKqoTKRjC3ocJMt53tIDpB5jFw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.crt b/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.crt
new file mode 100644
index 000000000000..2f087db08aa3
Binary files /dev/null and b/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.crt differ
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.key b/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.key
new file mode 100644
index 000000000000..7034a7b5a487
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.key
@@ -0,0 +1,9 @@
+-----BEGIN PRIVATE KEY-----
+MIIBSwIBADCCASsGByqGSM44BAEwggEeAoGBAJyiyioeXx1O98gRCMEjlPKMpr79
+KrcDkoroghtuXO1U6Cx34pBRjOQmQLDPqSOriEo5VuG6SJc/ppfZx9TrSrzqB26h
+KTUmiaOKmwpfIfzpi72wgsZeMOtU7JQ+FThfGyS8VxGh6G0h7xw26B/9ALxRw25z
+O1cy9ZJs0EY3hsHzAhUA/4dpclsck8K+SkWBTcPfU+x7wTUCgYB4LP6UvrvIiiFP
+xhk7AEGMMr0MhcJ3hhsgKWukUqIYsJKBM5MpKCnej5BHvnLXdKodIxygcKR4dJX7
+BRv69L+2RJk+UrYL1qBco5HpUslumA0e3gNdwRLoOoGD14dn1LD1LdESsyMgwfHH
+J0RRkYwacgCVXsvHv/eAkA8qq136dwQXAhUA216Tqp4OvdUBNv8QLv8Z5QPopGQ=
+-----END PRIVATE KEY-----
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.pem b/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.pem
new file mode 100644
index 000000000000..4f64dac50996
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-dsa.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAxWgAwIBAgIUFRQGA90GHC74cNK/hNzQDi7XJFYwCwYJYIZIAWUDBAMC
+MF0xCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhWaXJnaW5pYTETMBEGA1UEBwwKQWxl
+eGFuZHJpYTEQMA4GA1UECgwHQ29udG9zbzEUMBIGA1UECwwLRGV2ZWxvcG1lbnQw
+HhcNMjAwNjE5MTkyODIwWhcNMjAwNzE5MTkyODIwWjBdMQswCQYDVQQGEwJVUzER
+MA8GA1UECAwIVmlyZ2luaWExEzARBgNVBAcMCkFsZXhhbmRyaWExEDAOBgNVBAoM
+B0NvbnRvc28xFDASBgNVBAsMC0RldmVsb3BtZW50MIIBtjCCASsGByqGSM44BAEw
+ggEeAoGBAJyiyioeXx1O98gRCMEjlPKMpr79KrcDkoroghtuXO1U6Cx34pBRjOQm
+QLDPqSOriEo5VuG6SJc/ppfZx9TrSrzqB26hKTUmiaOKmwpfIfzpi72wgsZeMOtU
+7JQ+FThfGyS8VxGh6G0h7xw26B/9ALxRw25zO1cy9ZJs0EY3hsHzAhUA/4dpclsc
+k8K+SkWBTcPfU+x7wTUCgYB4LP6UvrvIiiFPxhk7AEGMMr0MhcJ3hhsgKWukUqIY
+sJKBM5MpKCnej5BHvnLXdKodIxygcKR4dJX7BRv69L+2RJk+UrYL1qBco5HpUslu
+mA0e3gNdwRLoOoGD14dn1LD1LdESsyMgwfHHJ0RRkYwacgCVXsvHv/eAkA8qq136
+dwOBhAACgYAHltgzkK3zD8yGdcGY0YgvN5l3lna1voLmcK+XtmehjMVy7OSSFICN
+KybLBOvO8paydhCb1J0klkLPAoAjgP2cEd+KueeRyJpx+jD1MsjIEXIn5jtjXdUH
+d0JJmHWAyHdNzmhXrXC7JLnj4ri7xMAV3GZGDpAnYvvL0LiXzFyomqNTMFEwHQYD
+VR0OBBYEFF1l4ZrF3ND05CjGd//ev0dJLCB7MB8GA1UdIwQYMBaAFF1l4ZrF3ND0
+5CjGd//ev0dJLCB7MA8GA1UdEwEB/wQFMAMBAf8wCwYJYIZIAWUDBAMCAzEAMC4C
+FQD6plYf60MDCvMjf1yQ8SBaFX3YYwIVAKqRQklh2b0Qhv+US222hb8xySJV
+-----END CERTIFICATE-----
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa-protected.key b/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa-protected.key
new file mode 100644
index 000000000000..bc4741ec91ec
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa-protected.key
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjGHXmGVX2JFwICCAAw
+DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEN5v5Ytosv3NT48Qg8C/Zh0EgZDK
+aWxzYPTIuIA4Tb1kCTd7BVGTsdeBxb5clCbEehF3yIZskalbRfjDso4n2HtVY9eq
++UZilRDSAt/XUhJqqViwbGg3pc+IHTdM2kTosG9vZK7WILRPvPphBFyn1NGwYPak
+zHeW1T2Y0PXdjxloqccS6xv4ySwHwv8Hp1pPbpUfRakH3KTrGzOlKouktkcrhfw=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.crt b/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.crt
new file mode 100644
index 000000000000..42a18cbb4144
Binary files /dev/null and b/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.crt differ
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.key b/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.key
new file mode 100644
index 000000000000..e6ca224e8a22
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.key
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIHteKGH6xLqUHhvsgtz9jIBuj+YCwAPHRg2C47rzX0L6oAoGCCqGSM49
+AwEHoUQDQgAES8Hf3hm1ygXcZ+4NLuNgrlY9mmyiQTA4bq+aW4s56IrorHy1Se0j
+WtOOngaYvYA7qvVV778h8DTKJcefzpxt1A==
+-----END EC PRIVATE KEY-----
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.pem b/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.pem
new file mode 100644
index 000000000000..73066f6b49a6
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-ecdsa.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICBjCCAa2gAwIBAgIUUHh7FUSJoSgSmhI5lnio2/R++gUwCgYIKoZIzj0EAwIw
+WTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
+dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIw
+MDcwMjEyMTIzOFoXDTIxMDcwMjEyMTIzOFowWTELMAkGA1UEBhMCQVUxEzARBgNV
+BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
+ZDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
+S8Hf3hm1ygXcZ+4NLuNgrlY9mmyiQTA4bq+aW4s56IrorHy1Se0jWtOOngaYvYA7
+qvVV778h8DTKJcefzpxt1KNTMFEwHQYDVR0OBBYEFO6n94lr7Fjk6Es+XC//WkHU
+SA09MB8GA1UdIwQYMBaAFO6n94lr7Fjk6Es+XC//WkHUSA09MA8GA1UdEwEB/wQF
+MAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgEjgE6bKKqDqfgDMmEgeRtWMnb3fIkRTH
+dxdHLobgzKMCICyJ13K6RBh3LCQ9CtysvLFROQBON/DD2xgXRN7xr9lG
+-----END CERTIFICATE-----
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa-protected.key b/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa-protected.key
new file mode 100644
index 000000000000..34fba0f776de
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa-protected.key
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFNjBgBgkqhkiG9w0BBQ0wUzAyBgkqhkiG9w0BBQwwJQQQ93oRxzJ5UoNOb/zN
+x5cdsAIDAYagMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAuHsE18X/Z9ZVe
+aBl7C55nBIIE0AABqjc9ERcLYNpCRpA6c/TFG62m4Mr9J4dU4g1WD07t7uLxZiRi
+Pl0YOjCulljMsevAW5PlLxi4ffJ+I0/UB1WOfzEMhcj7o1qG0Uv55B7WRuWKw1Zr
+jo0bDY5Man48ZjpqMMBdnWhyHdIDm+WD0OyN98mpsN6SCQMjvx91M+klrsp7LOMM
+88HHS0RFVKGF9hYSy6rCwMJWf+7QGO2wXfq+MKvJ/bBgPGDLwN4phUCyocnR0swD
+/XZNiiw0xIC8OxAKhc6BV4AJkjNs32THdBOCGY6B4P/9Zo5W29S3ja/hGsMQAA27
+QtIDg74HpX7TgIyqoc1oiLNIWW/+jUHSEYJsTPlg5VYWsXUfSHZpz8EJvKt2tyvt
+vBGOCLDDZD4GVXhPigKG6zJSJeTe94/VlwPhNSEucKeaALdax5t3HvPNzWKFX57E
+aC82/IxRrjgHmgsGSZdMi08HY6K9GAVBFpIGvXOGtRq7w8zO/KagAvSwAOLLtOs7
+iEuAQxD+cKLRT59c4E7r5W7BT+faq85ovqdXe5Edtl3cT81zsl27pZvQrcrTPbZe
+4OeIdWxOmOnC/bXvRHNd9XuYadXXazBoFbe9yPwjqnflEh39CyvlOZXeaQXSdsEM
+1IBhddRTorO/I8M/znu9glqIa5ya1NA+4ujmf4OnJLtsrlKQa65VPVTrFdeYuMr0
+VfOuuIye2OdyJ6jS0a1PYQm4bEEz6UR88dnmnhDx6i8/l2wW5+CArA/x8IBYboBM
+NJpJY9bHpic1AhjnjnTtFz2s4uYPi5g9peBizarZn+6OJvgYqs4a8SI92dA3E2o4
+a/1j7xlLlgXnVRLBMibxqzjMt4Zt7Nj+BaN1owrB/q04AWS2M4TSQz+NYOZwNFxB
+dzb+fysTLK5XNEYq6rSg+0i+EKZl8Jb/t4d8SLPVr/tdfDt9BtZ0nTgjvy1HWy1p
+kQdm13XfK1/9KsePH/Jb6dvN/u6ubV+ZqI7Bc7VyTi0bKMdpH2K8/dtopNyDZ/P+
+/IsyyDYTorgJB/klSih/W0hqpSBbEAmlSBfBxP1/ozBEGR2oF20JOCFyD6UXQR/1
+V7r2KtplpyfXaIWh4fABitAMHz7VgmEIQ2H9cB4Ey9jdRPQ/1p+OgGjfaFJQ0uYM
+987TDtjkuukJYnPZNIIx0Yv3iAX16XmhzJixWSMUIJiWfSiz0aTjBxsPQVPTQV+M
+6BgFf3riBApZYlVVJsGIie2XTvu/tHRhfQrxccl63HN7yAeJheQnoscin6Z5TKN/
+U8Ouy/QGiATatKUEUjr4lN+BYySf8F6e3cAAeAx/ZnFvGw5z8fwNYBjVWg/83bTw
+9rS+tSk8VsvTdkcKoNbbDtw+SwYfZSbMUBFm0B13190iJZoyWI+5ZKPnZ2CvOZhX
+PjGTOnh6Diq907l2Q7S/v8SLe0bCHCHVBy+CcPWVDZ6Z7V5cJ/W8TvFPcSGw1UCl
+tKPp862uDaPKvGxqGDq0vGouEUrtJKZ279Lnrtz1n8raUj0Gxa+KXqLACh8dXCzK
+ZgCTPhfAjZcYgA73edW0whNNH9MNInDGulT/arCK3HTkFPczD+7wA8Ojw/LxKFJs
+0d8vtILbmLv46CO+wvIdWrW1c7PCrGJDf9Zuw06vIH7hpW9swSM55k9/
+-----END ENCRYPTED PRIVATE KEY-----
\ No newline at end of file
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.crt b/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.crt
new file mode 100644
index 000000000000..0421f377734d
Binary files /dev/null and b/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.crt differ
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.key b/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.key
new file mode 100644
index 000000000000..3462b060b3d5
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCwK6M1tIuVqrKn
+JDT/uBvEz+dMR5dExiWh9Df0aHVL6ZIQs2upwiqoViJSduE3rvSdjZMpvOzE1YUO
+Mh8dAsHrcTkXzeF77yF4GnR8XA6FNvIWYhiCxSM1f/cOdLDv0wmaANHoNYHYtr9W
+nofuH4QQzI+njLWIE3ZEl95+YXM80nnP+L4ggD46nu2Dd5LRBcpFP6FkCthF+iN+
+IUMdVHylsxhRPY3Dj+xEccPmAUZvCchWXWgGwsW0UygFECqLhWupt0Ysd8rKGRTx
+HaI7z/5S1c8VlUgk4Q7FRxq7HiiNdbkrViJkES3ghJ2LbKYMwkGXmfbnam1qRagO
+BWnYnnZpAgMBAAECggEBAKlBs7Pke3tXHf/RnI3XX+6OZMX3vlDYIs3f6maKea9u
+f+RFzXmyz/MdliouhyFNmT1KCQq/tadDEWvbIeNog9Fl3ZmON0YwMLLIkAPvGhBJ
+AvwYUT5KkxJSmJWt7VTtKDtq8EEuL0t8AIcDFsvkQak2MAqk+L/9GtK6Koy3qdTT
+Nx0to6jcSvAz6cBC/WY4u2fmGJb6RoQR0K7KWdovkhb60/5PF+tI5afDF4zO6UzD
+c7qxb9/rPqhsqomC1isS+MdRWl6edW28RYzhZNxtux0KKy+HYfbrlya41HIYOdCN
+h9IEc46tOuEZ4aARHq0eNkLr8oBARcjHUlfPnBpmDGUCgYEA1DYAd45N13DTAITd
+MIwiKLHDH5XLmKdCGPk/LNd0asyw7Yw0ffJ2LUtCKt1HyvVKaRsCjzmC7pN1d/JG
+Sni+zDgdip9f9vERVF/F/sA9h+zH+Qwx5DUDhu6a4naey3t3t2hyRSbH+e+M7+1b
+4/i0nlsD35/lmwwfM7zgSZSmCIcCgYEA1IXOATUURWPilI9HoHt7yhGEvgXvquXC
+KF4K+1XNnC7AXO2jwz62xg6rnkFBxiPtvnN+fCVajMusyxCwarc/QyuctcQEm8jK
++vOI1dJM4Qgy+MNzcat7MjJCBpi6oFXAKDu3CGzfUw0SKNepc9cST8x9FsMgcC8K
+OKbLWLK2dY8CgYAIgMlwAPG5ijnKMYizY0oTG1xYLaZkzX7mhUY0w8VUajNEsXOB
+AHAfzH4wPYGc7ks2/vARURqf+KSiU8DhRwlOIYl9fnlX6bzqBpRmasmMYr54ijaN
+kFo909286Uffm2jmnnbFspIcv66EBpzB+7sxBTCYi02l8sxlRFIwYJZujQKBgAO5
+2NPCl3lj9+v82xegMppnVjlypzIK1y2YAH9JkNJFK5A1hmJ87f1o8m9S25FavedR
+5QzOJtlDFON2hnFIhy5pTFUPe7kzewONU3/UMQ7c8u/TlWmPxRgrM2ckNFltR3It
+Idde+UdeekwHA+yI/8QwZJ0KjL4KxRYbLoN+lp5XAoGAbVNfX57Hjc/TxrC7nTyQ
+0Mqi8S1t7Yo/Je/5Ow/8W3zVrzMYTipwJyBrAMhhhOTuvWc6lnJFW6XkyftQPwI6
+RDD3i9DELPhIPhh4kz7ID5OPtRnf3hrvXDOyucSV66RpxSSb5l7i92a8wTFWeGlN
+nLbTYpaPuX1fCIbRnigXI3A=
+-----END PRIVATE KEY-----
diff --git a/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.pem b/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.pem
new file mode 100644
index 000000000000..2a2d0312f342
--- /dev/null
+++ b/src/Servers/Kestrel/shared/test/TestCertificates/https-rsa.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIIS+Mx2/wTMMQwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UE
+AxMJbG9jYWxob3N0MB4XDTIwMDcwMTE5MjcwOVoXDTIxMDcwMTE5MjcwOVowFDES
+MBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAsCujNbSLlaqypyQ0/7gbxM/nTEeXRMYlofQ39Gh1S+mSELNrqcIqqFYiUnbh
+N670nY2TKbzsxNWFDjIfHQLB63E5F83he+8heBp0fFwOhTbyFmIYgsUjNX/3DnSw
+79MJmgDR6DWB2La/Vp6H7h+EEMyPp4y1iBN2RJfefmFzPNJ5z/i+IIA+Op7tg3eS
+0QXKRT+hZArYRfojfiFDHVR8pbMYUT2Nw4/sRHHD5gFGbwnIVl1oBsLFtFMoBRAq
+i4VrqbdGLHfKyhkU8R2iO8/+UtXPFZVIJOEOxUcaux4ojXW5K1YiZBEt4ISdi2ym
+DMJBl5n252ptakWoDgVp2J52aQIDAQABo2IwYDAMBgNVHRMBAf8EAjAAMA4GA1Ud
+DwEB/wQEAwIFoDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDATAXBgNVHREBAf8EDTAL
+gglsb2NhbGhvc3QwDwYKKwYBBAGCN1QBAQQBATANBgkqhkiG9w0BAQsFAAOCAQEA
+ZD9JA++dIuBke7GYYlJuKTMHJB0Sm1Ug2idNi1JiocXYsCVzY05sd4Qh+34PcED7
+B6592o1h47bgOh1ISolrOkt/23VjJweWGsa9rqt1zMdmmCulmPPFOiWWzMSm1OkN
+Q/Q5pzWXojxp/ArWLZbrghA44t+A4WJpWyEpEKKu5pD+ufG6dX6oPgz7yRXpkyJw
+rln219tjGACm2pXLgTO/WQdesaaquv6v2MEb5jJcxFeK5cQN/anYFqhjJvth1Wr0
+FQwbO4drt1lD+a30r6VjL/sEIlKK2Mi68rHQzeHug+663GLTtw2bZyvAoMwZoxo4
+Vwy3e5F7dw23onqQB92IoQ==
+-----END CERTIFICATE-----
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsConnectionMiddlewareTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsConnectionMiddlewareTests.cs
index fe0b8dae14fd..70b216e149e7 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsConnectionMiddlewareTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsConnectionMiddlewareTests.cs
@@ -21,7 +21,11 @@
using Microsoft.AspNetCore.Server.Kestrel.Https.Internal;
using Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.TestTransport;
using Microsoft.AspNetCore.Testing;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Testing;
+using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
@@ -51,6 +55,41 @@ void ConfigureListenOptions(ListenOptions listenOptions)
}
}
+ [Fact]
+ public async Task CanReadAndWriteWithHttpsConnectionMiddlewareWithPemCertificate()
+ {
+ var configuration = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary
+ {
+ ["Certificates:Default:Path"] = Path.Combine("shared", "TestCertificates", "https-aspnet.crt"),
+ ["Certificates:Default:KeyPath"] = Path.Combine("shared", "TestCertificates", "https-aspnet.key"),
+ ["Certificates:Default:Password"] = "aspnetcore",
+ }).Build();
+
+ var options = new KestrelServerOptions();
+ var env = new Mock();
+ env.SetupGet(e => e.ContentRootPath).Returns(Directory.GetCurrentDirectory());
+
+ options.ApplicationServices = new ServiceCollection().AddSingleton(env.Object).AddLogging().BuildServiceProvider();
+ var loader = new KestrelConfigurationLoader(options, configuration, reloadOnChange: false);
+ loader.Load();
+ void ConfigureListenOptions(ListenOptions listenOptions)
+ {
+ listenOptions.KestrelServerOptions = options;
+ listenOptions.UseHttps();
+ };
+
+ await using (var server = new TestServer(App, new TestServiceContext(LoggerFactory), ConfigureListenOptions))
+ {
+ var result = await server.HttpClientSlim.PostAsync($"https://localhost:{server.Port}/",
+ new FormUrlEncodedContent(new[] {
+ new KeyValuePair("content", "Hello World?")
+ }),
+ validateCertificate: false);
+
+ Assert.Equal("content=Hello+World%3F", result);
+ }
+ }
+
[Fact]
public async Task HandshakeDetailsAreAvailable()
{
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/InMemory.FunctionalTests.csproj b/src/Servers/Kestrel/test/InMemory.FunctionalTests/InMemory.FunctionalTests.csproj
index 952a0a9f50c9..9b2925609d38 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/InMemory.FunctionalTests.csproj
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/InMemory.FunctionalTests.csproj
@@ -11,6 +11,9 @@
+
+
+