Merge branch 'shanewalters/remote-cert' into dev

This commit is contained in:
Stephen Halter 2016-05-20 15:53:51 -07:00
commit c39546352a
2 changed files with 87 additions and 9 deletions

View File

@ -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
}
}
}

View File

@ -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
}
}