From 43c8d7ef8f70526654419d4199a6d66dbbf649b3 Mon Sep 17 00:00:00 2001 From: drawaes Date: Tue, 7 Nov 2017 21:37:42 +0000 Subject: [PATCH 1/2] [WIP] PFX --- src/Kestrel.Tls/ListenOptionsTlsExtensions.cs | 2 +- src/Kestrel.Tls/OpenSsl.cs | 62 +++++++++++++++++++ .../TlsConnectionAdapterOptions.cs | 2 +- src/Kestrel.Tls/TlsStream.cs | 4 +- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/Kestrel.Tls/ListenOptionsTlsExtensions.cs b/src/Kestrel.Tls/ListenOptionsTlsExtensions.cs index cb2c45915..ab491d255 100644 --- a/src/Kestrel.Tls/ListenOptionsTlsExtensions.cs +++ b/src/Kestrel.Tls/ListenOptionsTlsExtensions.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Hosting { public static class ListenOptionsTlsExtensions { - public static ListenOptions UseTls(this ListenOptions listenOptions, string certificatePath, string privateKeyPath) + public static ListenOptions UseTls(this ListenOptions listenOptions, string certificatePath, string password) { return listenOptions.UseTls(new TlsConnectionAdapterOptions { diff --git a/src/Kestrel.Tls/OpenSsl.cs b/src/Kestrel.Tls/OpenSsl.cs index 17568e4b9..7c209a299 100644 --- a/src/Kestrel.Tls/OpenSsl.cs +++ b/src/Kestrel.Tls/OpenSsl.cs @@ -49,6 +49,41 @@ public static void SSL_CTX_free(IntPtr ctx) NativeMethods.SSL_CTX_free(ctx); } + public unsafe static int SSL_CTX_Set_Pfx(IntPtr ctx, string path, string password) + { + var pass = Marshal.StringToHGlobalAnsi(password); + var key = IntPtr.Zero; + var cert = IntPtr.Zero; + var ca = IntPtr.Zero; + + try + { + var file = System.IO.File.ReadAllBytes(path); + + fixed (void* f = file) + { + var buffer = (IntPtr)f; + var pkcs = NativeMethods.d2i_PKCS12(IntPtr.Zero, ref buffer, file.Length); + var result = NativeMethods.PKCS12_parse(pkcs, pass, ref key, ref cert, ref ca); + if (result != 1) + { + return -1; + } + if (NativeMethods.SSL_CTX_use_certificate(ctx, cert) != 1) return -1; + if (NativeMethods.SSL_CTX_use_PrivateKey(ctx, key) != 1) return -1; + if (NativeMethods.SSL_CTX_set1_chain(ctx, ca) != 1) return -1; + return 1; + } + } + finally + { + Marshal.FreeHGlobal(pass); + if (key != IntPtr.Zero) NativeMethods.EVP_PKEY_free(key); + if (cert != IntPtr.Zero) NativeMethods.X509_free(cert); + if (ca != IntPtr.Zero) NativeMethods.sk_X509_pop_free(ca); + } + } + public static int SSL_CTX_set_ecdh_auto(IntPtr ctx, int onoff) { return (int)NativeMethods.SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, IntPtr.Zero); @@ -263,6 +298,33 @@ private class NativeMethods [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] public static extern void ERR_load_BIO_strings(); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr d2i_PKCS12(IntPtr unsused, ref IntPtr bufferPointer, long length); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern int PKCS12_parse(IntPtr p12, IntPtr pass, ref IntPtr pkey, ref IntPtr cert, ref IntPtr ca); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern void PKCS12_free(IntPtr p12); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern void EVP_PKEY_free(IntPtr pkey); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern void X509_free(IntPtr a); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern void sk_X509_pop_free(IntPtr ca); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern int SSL_CTX_set1_chain(IntPtr ctx, IntPtr sk); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern int SSL_CTX_use_certificate(IntPtr ctx, IntPtr x509); + + [DllImport("libssl", CallingConvention = CallingConvention.Cdecl)] + public static extern int SSL_CTX_use_PrivateKey(IntPtr ctx, IntPtr pkey); } } } diff --git a/src/Kestrel.Tls/TlsConnectionAdapterOptions.cs b/src/Kestrel.Tls/TlsConnectionAdapterOptions.cs index 88d107ffd..220bd47d9 100644 --- a/src/Kestrel.Tls/TlsConnectionAdapterOptions.cs +++ b/src/Kestrel.Tls/TlsConnectionAdapterOptions.cs @@ -9,7 +9,7 @@ public class TlsConnectionAdapterOptions { public string CertificatePath { get; set; } = string.Empty; - public string PrivateKeyPath { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; public HttpProtocols Protocols { get; set; } } diff --git a/src/Kestrel.Tls/TlsStream.cs b/src/Kestrel.Tls/TlsStream.cs index 0b1b58316..9a8f51dca 100644 --- a/src/Kestrel.Tls/TlsStream.cs +++ b/src/Kestrel.Tls/TlsStream.cs @@ -36,7 +36,7 @@ static TlsStream() OpenSsl.OpenSSL_add_all_algorithms(); } - public TlsStream(Stream innerStream, string certificatePath, string privateKeyPath, IEnumerable protocols) + public TlsStream(Stream innerStream, string certificatePath, string password, IEnumerable protocols) { _innerStream = innerStream; _protocols = ToWireFormat(protocols); @@ -49,6 +49,8 @@ public TlsStream(Stream innerStream, string certificatePath, string privateKeyPa throw new Exception("Unable to create SSL context."); } + OpenSsl.SSL_CTX_Set_Pfx(_ctx, certificatePath, password); + OpenSsl.SSL_CTX_set_ecdh_auto(_ctx, 1); if (OpenSsl.SSL_CTX_use_certificate_file(_ctx, certificatePath, 1) != 1) From 0e3a55e62760407163fc3639119ac9b92c9fd0a0 Mon Sep 17 00:00:00 2001 From: drawaes Date: Tue, 7 Nov 2017 21:41:39 +0000 Subject: [PATCH 2/2] Missed files --- src/Kestrel.Tls/ListenOptionsTlsExtensions.cs | 2 +- src/Kestrel.Tls/TlsConnectionAdapter.cs | 6 +++--- src/Kestrel.Tls/TlsStream.cs | 15 ++++----------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/Kestrel.Tls/ListenOptionsTlsExtensions.cs b/src/Kestrel.Tls/ListenOptionsTlsExtensions.cs index ab491d255..695297eb5 100644 --- a/src/Kestrel.Tls/ListenOptionsTlsExtensions.cs +++ b/src/Kestrel.Tls/ListenOptionsTlsExtensions.cs @@ -15,7 +15,7 @@ public static ListenOptions UseTls(this ListenOptions listenOptions, string cert return listenOptions.UseTls(new TlsConnectionAdapterOptions { CertificatePath = certificatePath, - PrivateKeyPath = privateKeyPath, + Password = password, Protocols = listenOptions.Protocols }); } diff --git a/src/Kestrel.Tls/TlsConnectionAdapter.cs b/src/Kestrel.Tls/TlsConnectionAdapter.cs index 539c8404f..8dee80eb6 100644 --- a/src/Kestrel.Tls/TlsConnectionAdapter.cs +++ b/src/Kestrel.Tls/TlsConnectionAdapter.cs @@ -40,9 +40,9 @@ public TlsConnectionAdapter(TlsConnectionAdapterOptions options, ILoggerFactory throw new ArgumentException("Certificate path must be non-null.", nameof(options)); } - if (options.PrivateKeyPath == null) + if (options.Password == null) { - throw new ArgumentException("Private key path must be non-null.", nameof(options)); + throw new ArgumentException("Password must be non-null.", nameof(options)); } _options = options; @@ -70,7 +70,7 @@ public Task OnConnectionAsync(ConnectionAdapterContext conte private async Task InnerOnConnectionAsync(ConnectionAdapterContext context) { - var tlsStream = new TlsStream(context.ConnectionStream, _options.CertificatePath, _options.PrivateKeyPath, _serverProtocols); + var tlsStream = new TlsStream(context.ConnectionStream, _options.CertificatePath, _options.Password, _serverProtocols); try { diff --git a/src/Kestrel.Tls/TlsStream.cs b/src/Kestrel.Tls/TlsStream.cs index 9a8f51dca..af45dcbe3 100644 --- a/src/Kestrel.Tls/TlsStream.cs +++ b/src/Kestrel.Tls/TlsStream.cs @@ -49,20 +49,13 @@ public TlsStream(Stream innerStream, string certificatePath, string password, IE throw new Exception("Unable to create SSL context."); } - OpenSsl.SSL_CTX_Set_Pfx(_ctx, certificatePath, password); - - OpenSsl.SSL_CTX_set_ecdh_auto(_ctx, 1); - - if (OpenSsl.SSL_CTX_use_certificate_file(_ctx, certificatePath, 1) != 1) + if(OpenSsl.SSL_CTX_Set_Pfx(_ctx, certificatePath, password) != 1) { - throw new Exception("Unable to load certificate file."); - } - - if (OpenSsl.SSL_CTX_use_PrivateKey_file(_ctx, privateKeyPath, 1) != 1) - { - throw new Exception("Unable to load private key file."); + throw new InvalidOperationException("Unable to load PFX"); } + OpenSsl.SSL_CTX_set_ecdh_auto(_ctx, 1); + OpenSsl.SSL_CTX_set_alpn_select_cb(_ctx, _alpnSelectCallback, GCHandle.ToIntPtr(_protocolsHandle)); _ssl = OpenSsl.SSL_new(_ctx);