Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit 9c8095b

Browse files
committed
Outline SNI APIs #2357
1 parent 623c27a commit 9c8095b

10 files changed

+316
-41
lines changed

build/dependencies.props

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,29 @@
77
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
88
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview2-15749</InternalAspNetCoreSdkPackageVersion>
99
<LibuvPackageVersion>1.10.0</LibuvPackageVersion>
10-
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-a-preview2-mpr-16443</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
11-
<MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>2.1.0-a-preview2-mpr-16443</MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>
12-
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview2-30478</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
13-
<MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview2-30478</MicrosoftAspNetCoreHostingPackageVersion>
14-
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.1.0-preview2-30478</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
15-
<MicrosoftAspNetCoreHttpFeaturesPackageVersion>2.1.0-preview2-30478</MicrosoftAspNetCoreHttpFeaturesPackageVersion>
16-
<MicrosoftAspNetCoreHttpPackageVersion>2.1.0-preview2-30478</MicrosoftAspNetCoreHttpPackageVersion>
17-
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview2-30478</MicrosoftAspNetCoreTestingPackageVersion>
18-
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.0-preview2-30478</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
19-
<MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion>
20-
<MicrosoftExtensionsBuffersSourcesPackageVersion>2.1.0-a-preview2-mpr-16443</MicrosoftExtensionsBuffersSourcesPackageVersion>
21-
<MicrosoftExtensionsBuffersTestingSourcesPackageVersion>2.1.0-a-preview2-mpr-16443</MicrosoftExtensionsBuffersTestingSourcesPackageVersion>
22-
<MicrosoftExtensionsConfigurationBinderPackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsConfigurationBinderPackageVersion>
23-
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsConfigurationJsonPackageVersion>
24-
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsDependencyInjectionPackageVersion>
25-
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
26-
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsLoggingConsolePackageVersion>
27-
<MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsLoggingPackageVersion>
28-
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsLoggingTestingPackageVersion>
29-
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview2-30478</MicrosoftExtensionsOptionsPackageVersion>
10+
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
11+
<MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>
12+
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
13+
<MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreHostingPackageVersion>
14+
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
15+
<MicrosoftAspNetCoreHttpFeaturesPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreHttpFeaturesPackageVersion>
16+
<MicrosoftAspNetCoreHttpPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreHttpPackageVersion>
17+
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreTestingPackageVersion>
18+
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.0-preview2-30544</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
19+
<MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion>
20+
<MicrosoftExtensionsBuffersSourcesPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsBuffersSourcesPackageVersion>
21+
<MicrosoftExtensionsBuffersTestingSourcesPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsBuffersTestingSourcesPackageVersion>
22+
<MicrosoftExtensionsConfigurationBinderPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsConfigurationBinderPackageVersion>
23+
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsConfigurationJsonPackageVersion>
24+
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsDependencyInjectionPackageVersion>
25+
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
26+
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsLoggingConsolePackageVersion>
27+
<MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsLoggingPackageVersion>
28+
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsLoggingTestingPackageVersion>
29+
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview2-30544</MicrosoftExtensionsOptionsPackageVersion>
3030
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
31-
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview3-26331-01</MicrosoftNETCoreApp21PackageVersion>
32-
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview2-30478</MicrosoftNetHttpHeadersPackageVersion>
31+
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview3-26403-03</MicrosoftNETCoreApp21PackageVersion>
32+
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview2-30544</MicrosoftNetHttpHeadersPackageVersion>
3333
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
3434
<MoqPackageVersion>4.7.49</MoqPackageVersion>
3535
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>

samples/SampleApp/Startup.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.AspNetCore.Hosting;
1313
using Microsoft.AspNetCore.Http;
1414
using Microsoft.AspNetCore.Server.Kestrel.Core;
15+
using Microsoft.AspNetCore.Server.Kestrel.Https.Internal;
1516
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
1617
using Microsoft.Extensions.Configuration;
1718
using Microsoft.Extensions.Logging;
@@ -105,10 +106,23 @@ public static Task Main(string[] args)
105106
listenOptions.UseHttps(StoreName.My, "localhost", allowInvalid: true);
106107
});
107108

109+
options.ListenAnyIP(basePort + 5, listenOptions =>
110+
{
111+
listenOptions.UseHttps(httpsOptions =>
112+
{
113+
var localhostCert = CertificateLoader.LoadFromStoreCert("localhost", "My", StoreLocation.CurrentUser, allowInvalid: true);
114+
httpsOptions.ServerCertificateSelector = (features, name) =>
115+
{
116+
// TODO: Name check, multiple certs, null names.
117+
return localhostCert;
118+
};
119+
});
120+
});
121+
108122
options
109123
.Configure()
110-
.Endpoint(IPAddress.Loopback, basePort + 5)
111-
.LocalhostEndpoint(basePort + 6)
124+
.Endpoint(IPAddress.Loopback, basePort + 6)
125+
.LocalhostEndpoint(basePort + 7)
112126
.Load();
113127

114128
options

src/Kestrel.Core/CoreStrings.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@
477477
<data name="PositiveTimeSpanRequired1" xml:space="preserve">
478478
<value>Value must be a positive TimeSpan.</value>
479479
</data>
480-
<data name="ServiceCertificateRequired" xml:space="preserve">
480+
<data name="ServerCertificateRequired" xml:space="preserve">
481481
<value>The server certificate parameter is required.</value>
482482
</data>
483483
<data name="BindingToDefaultAddresses" xml:space="preserve">

src/Kestrel.Core/HttpsConnectionAdapterOptions.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Security.Authentication;
77
using System.Security.Cryptography.X509Certificates;
88
using System.Threading;
9+
using Microsoft.AspNetCore.Http.Features;
910
using Microsoft.AspNetCore.Server.Kestrel.Core;
1011

1112
namespace Microsoft.AspNetCore.Server.Kestrel.Https
@@ -29,14 +30,25 @@ public HttpsConnectionAdapterOptions()
2930

3031
/// <summary>
3132
/// <para>
32-
/// Specifies the server certificate used to authenticate HTTPS connections.
33+
/// Specifies the server certificate used to authenticate HTTPS connections. This is ignored if ServerCertificateSelector is set.
3334
/// </para>
3435
/// <para>
3536
/// If the server certificate has an Extended Key Usage extension, the usages must include Server Authentication (OID 1.3.6.1.5.5.7.3.1).
3637
/// </para>
3738
/// </summary>
3839
public X509Certificate2 ServerCertificate { get; set; }
3940

41+
/// <summary>
42+
/// <para>
43+
/// A callback that will be invoked to dynamically select a server certificate. This is higher priority than ServerCertificate.
44+
/// If SNI is not avialable then the name parameter will be null.
45+
/// </para>
46+
/// <para>
47+
/// If the server certificate has an Extended Key Usage extension, the usages must include Server Authentication (OID 1.3.6.1.5.5.7.3.1).
48+
/// </para>
49+
/// </summary>
50+
public Func<IFeatureCollection, string, X509Certificate2> ServerCertificateSelector { get; set; }
51+
4052
/// <summary>
4153
/// Specifies the client certificate requirements for a HTTPS connection. Defaults to <see cref="ClientCertificateMode.NoCertificate"/>.
4254
/// </summary>

src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public class HttpsConnectionAdapter : IConnectionAdapter
2222

2323
private readonly HttpsConnectionAdapterOptions _options;
2424
private readonly X509Certificate2 _serverCertificate;
25+
private readonly Func<IFeatureCollection, string, X509Certificate2> _serverCertificateSelector;
26+
2527
private readonly ILogger _logger;
2628

2729
public HttpsConnectionAdapter(HttpsConnectionAdapterOptions options)
@@ -36,15 +38,24 @@ public HttpsConnectionAdapter(HttpsConnectionAdapterOptions options, ILoggerFact
3638
throw new ArgumentNullException(nameof(options));
3739
}
3840

39-
if (options.ServerCertificate == null)
41+
// capture the certificate now so it can't be switched after validation
42+
_serverCertificate = options.ServerCertificate;
43+
_serverCertificateSelector = options.ServerCertificateSelector;
44+
if (_serverCertificate == null && _serverCertificateSelector == null)
4045
{
41-
throw new ArgumentException(CoreStrings.ServiceCertificateRequired, nameof(options));
46+
throw new ArgumentException(CoreStrings.ServerCertificateRequired, nameof(options));
4247
}
4348

44-
// capture the certificate now so it can be switched after validation
45-
_serverCertificate = options.ServerCertificate;
46-
47-
EnsureCertificateIsAllowedForServerAuth(_serverCertificate);
49+
// If a selector is provided then ignore the cert, it may be a default cert.
50+
if (_serverCertificateSelector != null)
51+
{
52+
// SslStream doesn't allow both.
53+
_serverCertificate = null;
54+
}
55+
else
56+
{
57+
EnsureCertificateIsAllowedForServerAuth(_serverCertificate);
58+
}
4859

4960
_options = options;
5061
_logger = loggerFactory?.CreateLogger(nameof(HttpsConnectionAdapter));
@@ -115,9 +126,26 @@ private async Task<IAdaptedConnection> InnerOnConnectionAsync(ConnectionAdapterC
115126
try
116127
{
117128
#if NETCOREAPP2_1
129+
// Adapt to the SslStream signature
130+
ServerCertificateSelectionCallback selector = null;
131+
if (_serverCertificateSelector != null)
132+
{
133+
selector = (sender, name) =>
134+
{
135+
context.Features.Set(sslStream);
136+
var cert = _serverCertificateSelector(context.Features, name);
137+
if (cert != null)
138+
{
139+
EnsureCertificateIsAllowedForServerAuth(cert);
140+
}
141+
return cert;
142+
};
143+
}
144+
118145
var sslOptions = new SslServerAuthenticationOptions()
119146
{
120147
ServerCertificate = _serverCertificate,
148+
ServerCertificateSelectionCallback = selector,
121149
ClientCertificateRequired = certificateRequired,
122150
EnabledSslProtocols = _options.SslProtocols,
123151
CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
@@ -137,7 +165,17 @@ private async Task<IAdaptedConnection> InnerOnConnectionAsync(ConnectionAdapterC
137165

138166
await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None);
139167
#else
140-
await sslStream.AuthenticateAsServerAsync(_serverCertificate, certificateRequired,
168+
var serverCert = _serverCertificate;
169+
if (_serverCertificateSelector != null)
170+
{
171+
context.Features.Set(sslStream);
172+
serverCert = _serverCertificateSelector(context.Features, null);
173+
if (serverCert != null)
174+
{
175+
EnsureCertificateIsAllowedForServerAuth(serverCert);
176+
}
177+
}
178+
await sslStream.AuthenticateAsServerAsync(serverCert, certificateRequired,
141179
_options.SslProtocols, _options.CheckCertificateRevocation);
142180
#endif
143181
}

src/Kestrel.Core/KestrelConfigurationLoader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ public void Load()
236236
// EndpointDefaults or configureEndpoint may have added an https adapter.
237237
if (https && !listenOptions.ConnectionAdapters.Any(f => f.IsHttps))
238238
{
239-
if (httpsOptions.ServerCertificate == null)
239+
if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
240240
{
241241
throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
242242
}

src/Kestrel.Core/ListenOptionsHttpsExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public static ListenOptions UseHttps(this ListenOptions listenOptions, Action<Ht
179179
listenOptions.KestrelServerOptions.ApplyHttpsDefaults(options);
180180
configureOptions(options);
181181

182-
if (options.ServerCertificate == null)
182+
if (options.ServerCertificate == null && options.ServerCertificateSelector == null)
183183
{
184184
throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
185185
}
@@ -192,7 +192,7 @@ internal static bool TryUseHttps(this ListenOptions listenOptions)
192192
var options = new HttpsConnectionAdapterOptions();
193193
listenOptions.KestrelServerOptions.ApplyHttpsDefaults(options);
194194

195-
if (options.ServerCertificate == null)
195+
if (options.ServerCertificate == null && options.ServerCertificateSelector == null)
196196
{
197197
return false;
198198
}

src/Kestrel.Core/Properties/CoreStrings.Designer.cs

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)