From 72ce28fdb508ea3203cc674b1f785c122eb91fb6 Mon Sep 17 00:00:00 2001 From: Ata Kuyumcu Date: Fri, 13 Apr 2018 03:09:35 -0400 Subject: [PATCH] Fixed OpenSSL bindings to recognize LibreSSL (#5676) * Fixed OpenSSL bindings to recognize LibreSSL * Fixed OpenSSL header parsing macros to work with OS X * Fixed OpenSSL linking on OS X * Added ALPN support for LibreSSL >= 2.5.0 * Added a compilation flag to NOT use OpenSSL libs supplied by homebrew * Added a compilation flag to use homebrew's LibreSSL instead of OpenSSL * Replaced homebrew specific hacks with pkg-config --- bin/ci | 3 ++- src/openssl/lib_crypto.cr | 18 +++++++++++++++--- src/openssl/lib_ssl.cr | 15 ++++++++++----- src/openssl/ssl/context.cr | 6 +++++- src/openssl/ssl/socket.cr | 2 +- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/bin/ci b/bin/ci index 0d4f15f9db41..d160699803e6 100755 --- a/bin/ci +++ b/bin/ci @@ -84,7 +84,7 @@ prepare_build() { on_linux docker pull "jhass/crystal-build-$ARCH" - on_osx brew install crystal-lang + on_osx brew install crystal-lang pkg-config # Make sure binaries from llvm are available in PATH on_osx brew install jq @@ -123,6 +123,7 @@ with_build_env() { on_osx sudo systemsetup -settimezone $TZ on_osx PATH="/usr/local/opt/llvm/bin:\$PATH" \ CRYSTAL_CACHE_DIR="/tmp/crystal" \ + PKG_CONFIG_PATH="$(brew --prefix)/opt/openssl/lib/pkgconfig:$PKG_CONFIG_PATH" \ /bin/sh -c "'$command'" } diff --git a/src/openssl/lib_crypto.cr b/src/openssl/lib_crypto.cr index 9c1011f19c51..7e426040212a 100644 --- a/src/openssl/lib_crypto.cr +++ b/src/openssl/lib_crypto.cr @@ -1,11 +1,23 @@ {% begin %} lib LibCrypto - OPENSSL_110 = {{ `command -v pkg-config > /dev/null && pkg-config --atleast-version=1.1.0 libcrypto || printf %s false`.stringify != "false" }} - OPENSSL_102 = {{ `command -v pkg-config > /dev/null && pkg-config --atleast-version=1.0.2 libcrypto || printf %s false`.stringify != "false" }} + # An extra zero is appended to the output of LIBRESSL_VERSION to make it 0 when LibreSSL does not exist on the system. + # Any comparisons to it should be affixed with an extra zero as well e.g. `(LIBRESSL_VERSION_NUMBER >= 0x2050500F0)`. + LIBRESSL_VERSION = {{ system("echo \"#include \nLIBRESSL_VERSION_NUMBER\" | " + + (env("CC") || "cc") + " " + `pkg-config --cflags --silence-errors libssl || true`.chomp.stringify + " -E -").chomp.split('\n').last.split('L').first.id + "0" }} + OPENSSL_VERSION = {{ system("echo \"#include \nOPENSSL_VERSION_NUMBER\" | " + + (env("CC") || "cc") + " " + `pkg-config --cflags --silence-errors libssl || true`.chomp.stringify + " -E -").chomp.split('\n').last.split('L').first.id }} end {% end %} -@[Link(ldflags: "`command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s '-lcrypto'`")] +{% begin %} + lib LibCrypto + OPENSSL_110 = {{ (LibCrypto::LIBRESSL_VERSION == 0) && (LibCrypto::OPENSSL_VERSION >= 0x10101000) }} + OPENSSL_102 = {{ (LibCrypto::LIBRESSL_VERSION == 0) && (LibCrypto::OPENSSL_VERSION >= 0x10002000) }} + LIBRESSL_250 = {{ LibCrypto::LIBRESSL_VERSION >= 0x205000000 }} + end +{% end %} + +@[Link(ldflags: "`command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s ' -lcrypto'`")] lib LibCrypto alias Char = LibC::Char alias Int = LibC::Int diff --git a/src/openssl/lib_ssl.cr b/src/openssl/lib_ssl.cr index 6d5c25e298b2..b8786b8e250b 100644 --- a/src/openssl/lib_ssl.cr +++ b/src/openssl/lib_ssl.cr @@ -2,8 +2,9 @@ require "./lib_crypto" {% begin %} lib LibSSL - OPENSSL_110 = {{ `command -v pkg-config > /dev/null && pkg-config --atleast-version=1.1.0 libssl || printf %s false`.stringify != "false" }} - OPENSSL_102 = {{ `command -v pkg-config > /dev/null && pkg-config --atleast-version=1.0.2 libssl || printf %s false`.stringify != "false" }} + OPENSSL_110 = {{ LibCrypto::OPENSSL_110 }} + OPENSSL_102 = {{ LibCrypto::OPENSSL_102 }} + LIBRESSL_250 = {{ LibCrypto::LIBRESSL_250 }} end {% end %} @@ -198,13 +199,17 @@ lib LibSSL fun sslv23_method = SSLv23_method : SSLMethod {% end %} - {% if OPENSSL_102 %} + {% if OPENSSL_102 || LIBRESSL_250 %} alias ALPNCallback = (SSL, Char**, Char*, Char*, Int, Void*) -> Int - alias X509VerifyParam = LibCrypto::X509VerifyParam - fun ssl_get0_param = SSL_get0_param(handle : SSL) : X509VerifyParam fun ssl_get0_alpn_selected = SSL_get0_alpn_selected(handle : SSL, data : Char**, len : LibC::UInt*) : Void fun ssl_ctx_set_alpn_select_cb = SSL_CTX_set_alpn_select_cb(ctx : SSLContext, cb : ALPNCallback, arg : Void*) : Void + {% end %} + + {% if OPENSSL_102 %} + alias X509VerifyParam = LibCrypto::X509VerifyParam + + fun ssl_get0_param = SSL_get0_param(handle : SSL) : X509VerifyParam fun ssl_ctx_get0_param = SSL_CTX_get0_param(ctx : SSLContext) : X509VerifyParam fun ssl_ctx_set1_param = SSL_CTX_set1_param(ctx : SSLContext, param : X509VerifyParam) : Int {% end %} diff --git a/src/openssl/ssl/context.cr b/src/openssl/ssl/context.cr index b8bd3aeccbf7..fd41edcedcec 100644 --- a/src/openssl/ssl/context.cr +++ b/src/openssl/ssl/context.cr @@ -305,7 +305,7 @@ abstract class OpenSSL::SSL::Context LibSSL.ssl_ctx_set_verify(@handle, mode, nil) end - {% if LibSSL::OPENSSL_102 %} + {% if LibSSL::OPENSSL_102 || LibSSL::LIBRESSL_250 %} @alpn_protocol : Pointer(Void)? @@ -338,6 +338,10 @@ abstract class OpenSSL::SSL::Context LibSSL.ssl_ctx_set_alpn_select_cb(@handle, alpn_cb, alpn_protocol) end + {% end %} + + {% if LibSSL::OPENSSL_102 %} + # Set this context verify param to the default one of the given name. # # Depending on the OpenSSL version, the available defaults are diff --git a/src/openssl/ssl/socket.cr b/src/openssl/ssl/socket.cr index 10fc100966d4..14c3c165760b 100644 --- a/src/openssl/ssl/socket.cr +++ b/src/openssl/ssl/socket.cr @@ -119,7 +119,7 @@ abstract class OpenSSL::SSL::Socket < IO @bio.io.flush end - {% if LibSSL::OPENSSL_102 %} + {% if LibSSL::OPENSSL_102 || LibSSL::LIBRESSL_250 %} # Returns the negotiated ALPN protocol (eg: `"h2"`) of `nil` if no protocol was # negotiated. def alpn_protocol