Merge branch 'shanewalters/remote-cert' into dev
This commit is contained in:
commit
c39546352a
|
|
@ -40,7 +40,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
|||
|
||||
if (string.Equals(context.Address.Scheme, "https", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
X509Certificate2 clientCertificate = null;
|
||||
SslStream sslStream;
|
||||
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 NETSTANDARD1_3
|
||||
// conversion X509Certificate to X509Certificate2 not supported
|
||||
// https://github.com/dotnet/corefx/issues/4510
|
||||
return false;
|
||||
#else
|
||||
certificate2 = new X509Certificate2(certificate);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_options.ClientCertificateValidation != null)
|
||||
|
|
@ -86,7 +79,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
|||
}
|
||||
}
|
||||
|
||||
clientCertificate = certificate2;
|
||||
return true;
|
||||
});
|
||||
await sslStream.AuthenticateAsServerAsync(_options.ServerCertificate, clientCertificateRequired: true,
|
||||
|
|
@ -98,6 +90,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
|||
{
|
||||
previousPrepareRequest?.Invoke(features);
|
||||
|
||||
var clientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate);
|
||||
if (clientCertificate != null)
|
||||
{
|
||||
features.Set<ITlsConnectionFeature>(new TlsConnectionFeature { ClientCertificate = clientCertificate });
|
||||
|
|
@ -108,5 +101,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
|
|||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue