Updated to not use handle, centralize conversion logic.
This commit is contained in:
parent
9232029950
commit
b17c070e1c
|
|
@ -40,7 +40,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
||||||
|
|
||||||
if (string.Equals(context.Address.Scheme, "https", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(context.Address.Scheme, "https", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var certificateHandle = IntPtr.Zero;
|
|
||||||
SslStream sslStream;
|
SslStream sslStream;
|
||||||
if (_options.ClientCertificateMode == ClientCertificateMode.NoCertificate)
|
if (_options.ClientCertificateMode == ClientCertificateMode.NoCertificate)
|
||||||
{
|
{
|
||||||
|
|
@ -66,16 +65,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
X509Certificate2 certificate2 = certificate as X509Certificate2;
|
var certificate2 = ConvertToX509Certificate2(certificate);
|
||||||
if (certificate2 == null)
|
if (certificate2 == null)
|
||||||
{
|
{
|
||||||
#if NETSTANDARD1_3
|
|
||||||
// conversion X509Certificate to X509Certificate2 not supported
|
|
||||||
// https://github.com/dotnet/corefx/issues/4510
|
|
||||||
return false;
|
return false;
|
||||||
#else
|
|
||||||
certificate2 = new X509Certificate2(certificate);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_options.ClientCertificateValidation != null)
|
if (_options.ClientCertificateValidation != null)
|
||||||
|
|
@ -86,7 +79,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
certificateHandle = certificate2.Handle;
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
await sslStream.AuthenticateAsServerAsync(_options.ServerCertificate, clientCertificateRequired: true,
|
await sslStream.AuthenticateAsServerAsync(_options.ServerCertificate, clientCertificateRequired: true,
|
||||||
|
|
@ -98,9 +90,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
||||||
{
|
{
|
||||||
previousPrepareRequest?.Invoke(features);
|
previousPrepareRequest?.Invoke(features);
|
||||||
|
|
||||||
if (certificateHandle != IntPtr.Zero)
|
var clientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate);
|
||||||
|
if (clientCertificate != null)
|
||||||
{
|
{
|
||||||
features.Set<ITlsConnectionFeature>(new TlsConnectionFeature { ClientCertificate = new X509Certificate2(sslStream.RemoteCertificate.Handle) });
|
features.Set<ITlsConnectionFeature>(new TlsConnectionFeature { ClientCertificate = clientCertificate });
|
||||||
}
|
}
|
||||||
|
|
||||||
features.Get<IHttpRequestFeature>().Scheme = "https";
|
features.Get<IHttpRequestFeature>().Scheme = "https";
|
||||||
|
|
@ -108,5 +101,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
||||||
context.Connection = sslStream;
|
context.Connection = sslStream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private X509Certificate2 ConvertToX509Certificate2(X509Certificate certificate)
|
||||||
|
{
|
||||||
|
if (certificate == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
X509Certificate2 certificate2 = certificate as X509Certificate2;
|
||||||
|
if (certificate2 != null)
|
||||||
|
{
|
||||||
|
return certificate2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NETSTANDARD1_3
|
||||||
|
// conversion X509Certificate to X509Certificate2 not supported
|
||||||
|
// https://github.com/dotnet/corefx/issues/4510
|
||||||
|
return null;
|
||||||
|
#else
|
||||||
|
return new X509Certificate2(certificate);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -347,6 +347,69 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
#if NET451
|
#if NET451
|
||||||
ServicePointManager.ServerCertificateValidationCallback -= validationCallback;
|
ServicePointManager.ServerCertificateValidationCallback -= validationCallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "This test currently fails on Mono because of an issue with SslStream (https://github.com/aspnet/KestrelHttpServer/issues/240).")]
|
||||||
|
public async Task CertificatePassedToHttpContextIsNotDisposed()
|
||||||
|
{
|
||||||
|
RemoteCertificateValidationCallback validationCallback =
|
||||||
|
(sender, cert, chain, sslPolicyErrors) => true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if NET451
|
||||||
|
ServicePointManager.ServerCertificateValidationCallback += validationCallback;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var serviceContext = new TestServiceContext(new HttpsConnectionFilter(
|
||||||
|
new HttpsConnectionFilterOptions
|
||||||
|
{
|
||||||
|
ServerCertificate = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword"),
|
||||||
|
ClientCertificateMode = ClientCertificateMode.RequireCertificate,
|
||||||
|
ClientCertificateValidation = (certificate, chain, sslPolicyErrors) => true
|
||||||
|
},
|
||||||
|
new NoOpConnectionFilter())
|
||||||
|
);
|
||||||
|
|
||||||
|
RequestDelegate app = context =>
|
||||||
|
{
|
||||||
|
var tlsFeature = context.Features.Get<ITlsConnectionFeature>();
|
||||||
|
Assert.NotNull(tlsFeature);
|
||||||
|
Assert.NotNull(tlsFeature.ClientCertificate);
|
||||||
|
Assert.NotNull(context.Connection.ClientCertificate);
|
||||||
|
Assert.NotNull(context.Connection.ClientCertificate.PublicKey);
|
||||||
|
return context.Response.WriteAsync("hello world");
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var server = new TestServer(app, serviceContext, "https://localhost:0/"))
|
||||||
|
{
|
||||||
|
// SslStream is used to ensure the certificate is actually passed to the server
|
||||||
|
// HttpClient might not send the certificate because it is invalid or it doesn't match any
|
||||||
|
// of the certificate authorities sent by the server in the SSL handshake.
|
||||||
|
using (var client = new TcpClient())
|
||||||
|
{
|
||||||
|
await client.ConnectAsync("127.0.0.1", server.Port);
|
||||||
|
|
||||||
|
var stream = new SslStream(client.GetStream(), false, (sender, certificate, chain, errors) => true,
|
||||||
|
(sender, host, certificates, certificate, issuers) => new X509Certificate2(@"TestResources/testCert.pfx", "testPassword"));
|
||||||
|
await stream.AuthenticateAsClientAsync("localhost", new X509CertificateCollection(), SslProtocols.Tls12 | SslProtocols.Tls11, false);
|
||||||
|
|
||||||
|
var request = Encoding.UTF8.GetBytes("GET / HTTP/1.0\r\n\r\n");
|
||||||
|
await stream.WriteAsync(request, 0, request.Length);
|
||||||
|
|
||||||
|
var reader = new StreamReader(stream);
|
||||||
|
var line = await reader.ReadLineAsync();
|
||||||
|
Assert.Equal("HTTP/1.1 200 OK", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
#if NET451
|
||||||
|
ServicePointManager.ServerCertificateValidationCallback -= validationCallback;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue