From 87ec603f2f6d1ec16cdf8c8d3a0253643b2f4c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Fri, 15 Nov 2024 23:39:16 +0100 Subject: [PATCH] Enable bindings for functions in LibreSSL (#15177) A lot of symbols that are available in LibreSSL are missing in the bindings when macro branches only checked for OpenSSL versions. I added the respective LibreSSL versions. --- .github/workflows/linux.yml | 1 + spec/std/openssl/pkcs5_spec.cr | 2 +- spec/std/openssl/ssl/context_spec.cr | 14 +++++++------- src/openssl/lib_crypto.cr | 13 +++++++------ src/openssl/lib_ssl.cr | 14 ++++++++------ 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 79c3f143d303..eb5874a2687a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -20,6 +20,7 @@ jobs: DOCKER_TEST_PREFIX: crystallang/crystal:${{ matrix.crystal_bootstrap_version }} runs-on: ubuntu-latest strategy: + fail-fast: false matrix: crystal_bootstrap_version: [1.7.3, 1.8.2, 1.9.2, 1.10.1, 1.11.2, 1.12.2, 1.13.3, 1.14.0] flags: [""] diff --git a/spec/std/openssl/pkcs5_spec.cr b/spec/std/openssl/pkcs5_spec.cr index 70fd351f0bbc..a8261d42c1f6 100644 --- a/spec/std/openssl/pkcs5_spec.cr +++ b/spec/std/openssl/pkcs5_spec.cr @@ -13,7 +13,7 @@ describe OpenSSL::PKCS5 do end end - {% if compare_versions(LibSSL::OPENSSL_VERSION, "1.0.0") >= 0 %} + {% if compare_versions(LibSSL::OPENSSL_VERSION, "1.0.0") >= 0 || LibSSL::LIBRESSL_VERSION != "0.0.0" %} {% if compare_versions(LibSSL::OPENSSL_VERSION, "3.0.0") < 0 %} [ {OpenSSL::Algorithm::MD4, 1, 16, "1857f69412150bca4542581d0f9e7fd1"}, diff --git a/spec/std/openssl/ssl/context_spec.cr b/spec/std/openssl/ssl/context_spec.cr index 74c79411c82a..c37055dcedec 100644 --- a/spec/std/openssl/ssl/context_spec.cr +++ b/spec/std/openssl/ssl/context_spec.cr @@ -32,7 +32,7 @@ describe OpenSSL::SSL::Context do (context.options & OpenSSL::SSL::Options::NO_SESSION_RESUMPTION_ON_RENEGOTIATION).should eq(OpenSSL::SSL::Options::NO_SESSION_RESUMPTION_ON_RENEGOTIATION) (context.options & OpenSSL::SSL::Options::SINGLE_ECDH_USE).should eq(OpenSSL::SSL::Options::SINGLE_ECDH_USE) (context.options & OpenSSL::SSL::Options::SINGLE_DH_USE).should eq(OpenSSL::SSL::Options::SINGLE_DH_USE) - {% if compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 %} + {% if LibSSL::Options.has_constant?(:NO_RENEGOTIATION) %} (context.options & OpenSSL::SSL::Options::NO_RENEGOTIATION).should eq(OpenSSL::SSL::Options::NO_RENEGOTIATION) {% end %} @@ -128,12 +128,12 @@ describe OpenSSL::SSL::Context do context = OpenSSL::SSL::Context::Client.new level = context.security_level context.security_level = level + 1 - # SSL_CTX_get_security_level is not supported by libressl - {% if LibSSL::OPENSSL_VERSION != "0.0.0" %} + + if LibSSL.responds_to?(:ssl_ctx_set_security_level) context.security_level.should eq(level + 1) - {% else %} + else context.security_level.should eq 0 - {% end %} + end end it "adds temporary ecdh curve (P-256)" do @@ -194,12 +194,12 @@ describe OpenSSL::SSL::Context do context.verify_mode.should eq(OpenSSL::SSL::VerifyMode::PEER) end - {% if compare_versions(LibSSL::OPENSSL_VERSION, "1.0.2") >= 0 %} + if LibSSL.responds_to?(:ssl_ctx_set_alpn_protos) it "alpn_protocol=" do context = OpenSSL::SSL::Context::Client.insecure context.alpn_protocol = "h2" end - {% end %} + end it "calls #finalize on insecure client context" do assert_finalizes("insecure_client_ctx") { OpenSSL::SSL::Context::Client.insecure } diff --git a/src/openssl/lib_crypto.cr b/src/openssl/lib_crypto.cr index bc7130351059..aa7eef54c5ab 100644 --- a/src/openssl/lib_crypto.cr +++ b/src/openssl/lib_crypto.cr @@ -109,7 +109,7 @@ lib LibCrypto alias BioMethodDestroy = Bio* -> Int alias BioMethodCallbackCtrl = (Bio*, Int, Void*) -> Long - {% if compare_versions(LibCrypto::OPENSSL_VERSION, "1.1.0") >= 0 %} + {% if compare_versions(LibCrypto::OPENSSL_VERSION, "1.1.0") >= 0 || compare_versions(LibCrypto::LIBRESSL_VERSION, "2.7.0") >= 0 %} type BioMethod = Void {% else %} struct BioMethod @@ -129,7 +129,7 @@ lib LibCrypto fun BIO_new(BioMethod*) : Bio* fun BIO_free(Bio*) : Int - {% if compare_versions(LibCrypto::OPENSSL_VERSION, "1.1.0") >= 0 %} + {% if compare_versions(LibCrypto::OPENSSL_VERSION, "1.1.0") >= 0 || compare_versions(LibCrypto::LIBRESSL_VERSION, "2.7.0") >= 0 %} fun BIO_set_data(Bio*, Void*) fun BIO_get_data(Bio*) : Void* fun BIO_set_init(Bio*, Int) @@ -145,6 +145,7 @@ lib LibCrypto fun BIO_meth_set_destroy(BioMethod*, BioMethodDestroy) fun BIO_meth_set_callback_ctrl(BioMethod*, BioMethodCallbackCtrl) {% end %} + # LibreSSL does not define these symbols {% if compare_versions(LibCrypto::OPENSSL_VERSION, "1.1.1") >= 0 %} fun BIO_meth_set_read_ex(BioMethod*, BioMethodRead) fun BIO_meth_set_write_ex(BioMethod*, BioMethodWrite) @@ -229,7 +230,7 @@ lib LibCrypto fun evp_digestfinal_ex = EVP_DigestFinal_ex(ctx : EVP_MD_CTX, md : UInt8*, size : UInt32*) : Int32 - {% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 %} + {% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 || compare_versions(LibCrypto::LIBRESSL_VERSION, "2.7.0") >= 0 %} fun evp_md_ctx_new = EVP_MD_CTX_new : EVP_MD_CTX fun evp_md_ctx_free = EVP_MD_CTX_free(ctx : EVP_MD_CTX) {% else %} @@ -306,7 +307,7 @@ lib LibCrypto fun md5 = MD5(data : UInt8*, length : LibC::SizeT, md : UInt8*) : UInt8* fun pkcs5_pbkdf2_hmac_sha1 = PKCS5_PBKDF2_HMAC_SHA1(pass : LibC::Char*, passlen : LibC::Int, salt : UInt8*, saltlen : LibC::Int, iter : LibC::Int, keylen : LibC::Int, out : UInt8*) : LibC::Int - {% if compare_versions(OPENSSL_VERSION, "1.0.0") >= 0 %} + {% if compare_versions(OPENSSL_VERSION, "1.0.0") >= 0 || LIBRESSL_VERSION != "0.0.0" %} fun pkcs5_pbkdf2_hmac = PKCS5_PBKDF2_HMAC(pass : LibC::Char*, passlen : LibC::Int, salt : UInt8*, saltlen : LibC::Int, iter : LibC::Int, digest : EVP_MD, keylen : LibC::Int, out : UInt8*) : LibC::Int {% end %} @@ -380,12 +381,12 @@ lib LibCrypto fun x509_store_add_cert = X509_STORE_add_cert(ctx : X509_STORE, x : X509) : Int - {% unless compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 %} + {% unless compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 || compare_versions(LibCrypto::LIBRESSL_VERSION, "3.0.0") >= 0 %} fun err_load_crypto_strings = ERR_load_crypto_strings fun openssl_add_all_algorithms = OPENSSL_add_all_algorithms_noconf {% end %} - {% if compare_versions(OPENSSL_VERSION, "1.0.2") >= 0 %} + {% if compare_versions(OPENSSL_VERSION, "1.0.2") >= 0 || LIBRESSL_VERSION != "0.0.0" %} type X509VerifyParam = Void* @[Flags] diff --git a/src/openssl/lib_ssl.cr b/src/openssl/lib_ssl.cr index 5a7c7ec76cd0..449f35dd0f72 100644 --- a/src/openssl/lib_ssl.cr +++ b/src/openssl/lib_ssl.cr @@ -145,7 +145,7 @@ lib LibSSL NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 0x40000000 CRYPTOPRO_TLSEXT_BUG = 0x80000000 - {% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 %} + {% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 || compare_versions(LIBRESSL_VERSION, "2.3.0") >= 0 %} MICROSOFT_SESS_ID_BUG = 0x00000000 NETSCAPE_CHALLENGE_BUG = 0x00000000 NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000000 @@ -243,6 +243,7 @@ lib LibSSL fun ssl_get_peer_certificate = SSL_get_peer_certificate(handle : SSL) : LibCrypto::X509 {% end %} + # In LibreSSL these functions are implemented as macros {% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 %} fun ssl_ctx_get_options = SSL_CTX_get_options(ctx : SSLContext) : ULong fun ssl_ctx_set_options = SSL_CTX_set_options(ctx : SSLContext, larg : ULong) : ULong @@ -257,12 +258,13 @@ lib LibSSL fun ssl_ctx_set_cert_verify_callback = SSL_CTX_set_cert_verify_callback(ctx : SSLContext, callback : CertVerifyCallback, arg : Void*) # control TLS 1.3 session ticket generation + # LibreSSL does not seem to implement these functions {% if compare_versions(OPENSSL_VERSION, "1.1.1") >= 0 %} fun ssl_ctx_set_num_tickets = SSL_CTX_set_num_tickets(ctx : SSLContext, larg : LibC::SizeT) : Int fun ssl_set_num_tickets = SSL_set_num_tickets(ctx : SSL, larg : LibC::SizeT) : Int {% end %} - {% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 %} + {% if compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 || compare_versions(LibSSL::LIBRESSL_VERSION, "2.3.0") >= 0 %} fun tls_method = TLS_method : SSLMethod {% else %} fun ssl_library_init = SSL_library_init @@ -270,7 +272,7 @@ lib LibSSL fun sslv23_method = SSLv23_method : SSLMethod {% end %} - {% if compare_versions(OPENSSL_VERSION, "1.0.2") >= 0 || compare_versions(LIBRESSL_VERSION, "2.5.0") >= 0 %} + {% if compare_versions(OPENSSL_VERSION, "1.0.2") >= 0 || compare_versions(LIBRESSL_VERSION, "2.1.0") >= 0 %} alias ALPNCallback = (SSL, Char**, Char*, Char*, Int, Void*) -> Int fun ssl_get0_alpn_selected = SSL_get0_alpn_selected(handle : SSL, data : Char**, len : LibC::UInt*) : Void @@ -278,7 +280,7 @@ lib LibSSL fun ssl_ctx_set_alpn_protos = SSL_CTX_set_alpn_protos(ctx : SSLContext, protos : Char*, protos_len : Int) : Int {% end %} - {% if compare_versions(OPENSSL_VERSION, "1.0.2") >= 0 %} + {% if compare_versions(OPENSSL_VERSION, "1.0.2") >= 0 || compare_versions(LIBRESSL_VERSION, "2.7.0") >= 0 %} alias X509VerifyParam = LibCrypto::X509VerifyParam fun dtls_method = DTLS_method : SSLMethod @@ -288,7 +290,7 @@ lib LibSSL fun ssl_ctx_set1_param = SSL_CTX_set1_param(ctx : SSLContext, param : X509VerifyParam) : Int {% end %} - {% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 %} + {% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 || compare_versions(LIBRESSL_VERSION, "3.6.0") >= 0 %} fun ssl_ctx_set_security_level = SSL_CTX_set_security_level(ctx : SSLContext, level : Int) : Void fun ssl_ctx_get_security_level = SSL_CTX_get_security_level(ctx : SSLContext) : Int {% end %} @@ -299,7 +301,7 @@ lib LibSSL {% end %} end -{% unless compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 %} +{% if LibSSL.has_method?(:ssl_library_init) %} LibSSL.ssl_library_init LibSSL.ssl_load_error_strings LibCrypto.openssl_add_all_algorithms