Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require LibreSSL 3.9 or later (Drop support for 3.1-3.8) #836

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,8 @@ jobs:
- openssl-3.4.0 # Supported until 2026-10-22
- openssl-master
# http://www.libressl.org/releases.html
- libressl-3.1.5 # EOL
- libressl-3.2.7 # EOL
- libressl-3.3.6 # EOL
- libressl-3.4.3 # EOL
- libressl-3.5.3 # EOL
- libressl-3.6.3 # EOL
- libressl-3.7.3 # EOL
- libressl-3.8.4 # EOL 2024-10-16
- libressl-3.9.2 # Supported until 2025-04-05
- libressl-4.0.0
- libressl-4.0.0 # Supported until 2025-10-08
include:
- { name-extra: 'with fips provider', openssl: openssl-3.0.15, fips-enabled: true }
- { name-extra: 'with fips provider', openssl: openssl-3.1.7, fips-enabled: true }
Expand Down
22 changes: 11 additions & 11 deletions ext/openssl/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,15 @@ def find_openssl_library

version_ok = if have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h")
is_libressl = true
checking_for("LibreSSL version >= 3.1.0") {
try_static_assert("LIBRESSL_VERSION_NUMBER >= 0x30100000L", "openssl/opensslv.h") }
checking_for("LibreSSL version >= 3.9.0") {
try_static_assert("LIBRESSL_VERSION_NUMBER >= 0x30900000L", "openssl/opensslv.h") }
else
is_openssl = true
checking_for("OpenSSL version >= 1.0.2") {
try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10002000L", "openssl/opensslv.h") }
end
unless version_ok
raise "OpenSSL >= 1.0.2 or LibreSSL >= 3.1.0 is required"
raise "OpenSSL >= 1.0.2 or LibreSSL >= 3.9.0 is required"
end

# Prevent wincrypt.h from being included, which defines conflicting macro with openssl/x509.h
Expand All @@ -143,14 +144,13 @@ def find_openssl_library

# compile options
have_func("RAND_egd()", "openssl/rand.h")
engines = %w{dynamic 4758cca aep atalla chil
cswift nuron sureware ubsec padlock capi gmp gost cryptodev}
engines.each { |name|
have_func("ENGINE_load_#{name}()", "openssl/engine.h")
}

# missing in libressl < 3.5
have_func("i2d_re_X509_tbs(NULL, NULL)", x509_h)
if is_openssl
engines = %w{dynamic 4758cca aep atalla chil
cswift nuron sureware ubsec padlock capi gmp gost cryptodev}
engines.each { |name|
have_func("ENGINE_load_#{name}()", "openssl/engine.h")
}
end

# added in 1.1.0
if !have_struct_member("SSL", "ctx", "openssl/ssl.h") || is_libressl
Expand Down
4 changes: 2 additions & 2 deletions ext/openssl/ossl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,7 @@ Init_openssl(void)
/*
* Init all digests, ciphers
*/
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
if (!OPENSSL_init_ssl(0, NULL))
rb_raise(rb_eRuntimeError, "OPENSSL_init_ssl");
#else
Expand All @@ -1075,7 +1075,7 @@ Init_openssl(void)
/*
* Version of OpenSSL the ruby OpenSSL extension is running with
*/
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
#else
rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
Expand Down
4 changes: 2 additions & 2 deletions ext/openssl/ossl_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static VALUE eEngineError;
/*
* Private
*/
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
#if OSSL_OPENSSL_PREREQ(1, 1, 0)
#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \
do{\
if(!strcmp(#engine_name, RSTRING_PTR(name))){\
Expand Down Expand Up @@ -163,7 +163,7 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
static VALUE
ossl_engine_s_cleanup(VALUE self)
{
#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000
#if !OSSL_OPENSSL_PREREQ(1, 1, 0)
ENGINE_cleanup();
#endif
return Qnil;
Expand Down
6 changes: 3 additions & 3 deletions ext/openssl/ossl_kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors
*/
#include "ossl.h"
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 6, 0)
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
# include <openssl/kdf.h>
#endif

Expand Down Expand Up @@ -141,7 +141,7 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
}
#endif

#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 6, 0)
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
/*
* call-seq:
* KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String
Expand Down Expand Up @@ -305,7 +305,7 @@ Init_ossl_kdf(void)
#if defined(HAVE_EVP_PBE_SCRYPT)
rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
#endif
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 6, 0)
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1);
#endif
}
6 changes: 3 additions & 3 deletions ext/openssl/ossl_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
}
}
else {
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 5, 0)
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
ossl_pem_passwd_cb,
(void *)pass)) {
Expand Down Expand Up @@ -1116,7 +1116,7 @@ ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
rb_jump_tag(state);
}
}
#if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0)
#if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_IS_LIBRESSL
if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),
RSTRING_LEN(data)) < 1) {
EVP_MD_CTX_free(ctx);
Expand Down Expand Up @@ -1221,7 +1221,7 @@ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
rb_jump_tag(state);
}
}
#if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0)
#if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_IS_LIBRESSL
ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),
RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),
RSTRING_LEN(data));
Expand Down
5 changes: 0 additions & 5 deletions ext/openssl/ossl_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@
# define OSSL_USE_NEXTPROTONEG
#endif

#if !defined(TLS1_3_VERSION) && \
OSSL_LIBRESSL_PREREQ(3, 2, 0) && !OSSL_LIBRESSL_PREREQ(3, 4, 0)
# define TLS1_3_VERSION 0x0304
#endif

#ifdef _WIN32
# define TO_SOCKET(s) _get_osfhandle(s)
#else
Expand Down
4 changes: 0 additions & 4 deletions ext/openssl/ossl_x509cert.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,6 @@ ossl_x509_eq(VALUE self, VALUE other)
return !X509_cmp(a, b) ? Qtrue : Qfalse;
}

#ifdef HAVE_I2D_RE_X509_TBS
/*
* call-seq:
* cert.tbs_bytes => string
Expand Down Expand Up @@ -741,7 +740,6 @@ ossl_x509_tbs_bytes(VALUE self)

return str;
}
#endif

struct load_chained_certificates_arguments {
VALUE certificates;
Expand Down Expand Up @@ -1035,7 +1033,5 @@ Init_ossl_x509cert(void)
rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
rb_define_method(cX509Cert, "==", ossl_x509_eq, 1);
#ifdef HAVE_I2D_RE_X509_TBS
rb_define_method(cX509Cert, "tbs_bytes", ossl_x509_tbs_bytes, 0);
#endif
}
4 changes: 2 additions & 2 deletions ext/openssl/ossl_x509store.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,12 +365,12 @@ ossl_x509store_add_file(VALUE self, VALUE file)
ossl_raise(eX509StoreError, "X509_STORE_add_lookup");
if (X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1)
ossl_raise(eX509StoreError, "X509_LOOKUP_load_file");
#if OPENSSL_VERSION_NUMBER < 0x10101000 || defined(LIBRESSL_VERSION_NUMBER)
#if !OSSL_OPENSSL_PREREQ(1, 1, 1) && !OSSL_IS_LIBRESSL
/*
* X509_load_cert_crl_file() which is called from X509_LOOKUP_load_file()
* did not check the return value of X509_STORE_add_{cert,crl}(), leaking
* "cert already in hash table" errors on the error queue, if duplicate
* certificates are found. This will be fixed by OpenSSL 1.1.1.
* certificates are found. Fixed by OpenSSL 1.1.1 and LibreSSL 3.5.0.
*/
ossl_clear_error();
#endif
Expand Down
11 changes: 5 additions & 6 deletions test/openssl/test_pkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def test_generic_oid_inspect_rsa
end

def test_generic_oid_inspect_x25519
omit "X25519 not supported" unless openssl?(1, 1, 0) || libressl?(3, 7, 0)
omit "X25519 not supported" if openssl? && !openssl?(1, 1, 0)
omit_on_fips

# X25519 private key
Expand Down Expand Up @@ -85,8 +85,7 @@ def test_hmac_sign_verify
def test_ed25519
# Ed25519 is not FIPS-approved.
omit_on_fips
# See EVP_PKEY_sign in Changelog for 3.7.0: https://github.com/libressl/portable/blob/master/ChangeLog
omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 7, 0)
omit "Ed25519 not supported" if openssl? && !openssl?(1, 1, 1)

# Test vector from RFC 8032 Section 7.1 TEST 2
priv_pem = <<~EOF
Expand Down Expand Up @@ -137,7 +136,7 @@ def test_ed25519
end

def test_x25519
omit "X25519 not supported" unless openssl?(1, 1, 0) || libressl?(3, 7, 0)
omit "X25519 not supported" if openssl? && !openssl?(1, 1, 0)
omit_on_fips

# Test vector from RFC 7748 Section 6.1
Expand All @@ -160,7 +159,7 @@ def test_x25519
assert_equal bob_pem, bob.public_to_pem
assert_equal [shared_secret].pack("H*"), alice.derive(bob)

unless openssl?(1, 1, 1) || libressl?(3, 7, 0)
if openssl? && !openssl?(1, 1, 1)
omit "running OpenSSL version does not have raw public key support"
end
alice_private = OpenSSL::PKey.new_raw_private_key("X25519", alice.raw_private_key)
Expand All @@ -176,7 +175,7 @@ def test_x25519
end

def test_raw_initialize_errors
omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 7, 0)
omit "Ed25519 not supported" if openssl? && !openssl?(1, 1, 1)

assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("foo123", "xxx") }
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("ED25519", "xxx") }
Expand Down
23 changes: 8 additions & 15 deletions test/openssl/test_ssl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,8 @@ def test_client_auth_success
vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
start_server(verify_mode: vflag,
ctx_proc: proc { |ctx|
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
# LibreSSL doesn't support client_cert_cb in TLS 1.3
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?
}) { |port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = @cli_key
Expand Down Expand Up @@ -437,7 +438,7 @@ def test_client_cert_cb_ignore_error
end

def test_client_ca
pend "LibreSSL 3.2 has broken client CA support" if libressl?(3, 2, 0)
pend "LibreSSL doesn't support certificate_authorities" if libressl?

ctx_proc = Proc.new do |ctx|
ctx.client_ca = [@ca_cert]
Expand Down Expand Up @@ -609,12 +610,9 @@ def test_finished_messages
start_server(accept_proc: proc { |server|
server_finished = server.finished_message
server_peer_finished = server.peer_finished_message
}, ctx_proc: proc { |ctx|
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
}) { |port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
ctx.max_version = :TLS1_2 if libressl?(3, 2, 0) && !libressl?(3, 3, 0)
server_connect(port, ctx) { |ssl|
ssl.puts "abc"; ssl.gets

Expand Down Expand Up @@ -798,7 +796,7 @@ def test_post_connection_check_wildcard_san

# LibreSSL 3.5.0+ doesn't support other wildcard certificates
# (it isn't required to, as RFC states MAY, not MUST)
return if libressl?(3, 5, 0)
return if libressl?

assert_equal(true, OpenSSL::SSL.verify_certificate_identity(
create_cert_with_san('DNS:*baz.example.com'), 'foobaz.example.com'))
Expand Down Expand Up @@ -1078,7 +1076,7 @@ def test_accept_errors_include_peeraddr
def test_verify_hostname_on_connect
ctx_proc = proc { |ctx|
san = "DNS:a.example.com,DNS:*.b.example.com"
san += ",DNS:c*.example.com,DNS:d.*.example.com" unless libressl?(3, 2, 2)
san += ",DNS:c*.example.com,DNS:d.*.example.com" unless libressl?
exts = [
["keyUsage", "keyEncipherment,digitalSignature", true],
["subjectAltName", san],
Expand All @@ -1105,7 +1103,7 @@ def test_verify_hostname_on_connect
["cx.example.com", true],
["d.x.example.com", false],
].each do |name, expected_ok|
next if name.start_with?('cx') if libressl?(3, 2, 2)
next if name.start_with?('cx') if libressl?
begin
sock = TCPSocket.new("127.0.0.1", port)
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
Expand Down Expand Up @@ -1388,8 +1386,7 @@ def test_options_disable_versions
supported = check_supported_protocol_versions
if !defined?(OpenSSL::SSL::TLS1_3_VERSION) ||
!supported.include?(OpenSSL::SSL::TLS1_2_VERSION) ||
!supported.include?(OpenSSL::SSL::TLS1_3_VERSION) ||
!defined?(OpenSSL::SSL::OP_NO_TLSv1_3) # LibreSSL < 3.4
!supported.include?(OpenSSL::SSL::TLS1_3_VERSION)
pend "this test case requires both TLS 1.2 and TLS 1.3 to be supported " \
"and enabled by default"
end
Expand Down Expand Up @@ -1743,11 +1740,7 @@ def test_ciphersuites_method_tls_connection

server_connect(port, cli_ctx) do |ssl|
assert_equal('TLSv1.3', ssl.ssl_version)
if libressl?(3, 4, 0) && !libressl?(3, 5, 0)
assert_equal("AEAD-AES128-GCM-SHA256", ssl.cipher[0])
else
assert_equal(csuite[0], ssl.cipher[0])
end
assert_equal(csuite[0], ssl.cipher[0])
ssl.puts('abc'); assert_equal("abc\n", ssl.gets)
end
end
Expand Down
2 changes: 1 addition & 1 deletion test/openssl/test_ssl_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def test_resumption
ctx.options &= ~OpenSSL::SSL::OP_NO_TICKET
# Disable server-side session cache which is enabled by default
ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?
}
start_server(ctx_proc: ctx_proc) do |port|
sess1 = server_connect_with_session(port, nil, nil) { |ssl|
Expand Down
5 changes: 1 addition & 4 deletions test/openssl/test_x509cert.rb
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,7 @@ def test_sign_and_verify_dsa_md5
def test_sign_and_verify_ed25519
# Ed25519 is not FIPS-approved.
omit_on_fips
# See ASN1_item_sign_ctx in ChangeLog for 3.8.1: https://github.com/libressl/portable/blob/master/ChangeLog
omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 8, 1)
omit "Ed25519 not supported" if openssl? && !openssl?(1, 1, 1)
ed25519 = OpenSSL::PKey::generate_key("ED25519")
cert = issue_cert(@ca, ed25519, 1, [], nil, nil, digest: nil)
assert_equal(true, cert.verify(ed25519))
Expand Down Expand Up @@ -421,8 +420,6 @@ def test_load_file_fullchain_garbage
end

def test_tbs_precert_bytes
pend "LibreSSL < 3.5 does not have i2d_re_X509_tbs" if libressl? && !libressl?(3, 5, 0)

cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
seq = OpenSSL::ASN1.decode(cert.tbs_bytes)

Expand Down
3 changes: 1 addition & 2 deletions test/openssl/test_x509crl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,7 @@ def test_sign_and_verify
def test_sign_and_verify_ed25519
# Ed25519 is not FIPS-approved.
omit_on_fips
# See ASN1_item_sign_ctx in ChangeLog for 3.8.1: https://github.com/libressl/portable/blob/master/ChangeLog
omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 8, 1)
omit "Ed25519 not supported" if openssl? && !openssl?(1, 1, 1)
ed25519 = OpenSSL::PKey::generate_key("ED25519")
cert = issue_cert(@ca, ed25519, 1, [], nil, nil, digest: nil)
crl = issue_crl([], 1, Time.now, Time.now+1600, [],
Expand Down
3 changes: 1 addition & 2 deletions test/openssl/test_x509req.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@ def test_sign_and_verify_dsa_md5
def test_sign_and_verify_ed25519
# Ed25519 is not FIPS-approved.
omit_on_fips
# See ASN1_item_sign_ctx in ChangeLog for 3.8.1: https://github.com/libressl/portable/blob/master/ChangeLog
omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 8, 1)
omit "Ed25519 not supported" if openssl? && !openssl?(1, 1, 1)
ed25519 = OpenSSL::PKey::generate_key("ED25519")
req = issue_csr(0, @dn, ed25519, nil)
assert_equal(false, request_error_returns_false { req.verify(@rsa1024) })
Expand Down
2 changes: 1 addition & 1 deletion test/openssl/test_x509store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ def test_verify_with_crl
def test_add_cert_duplicate
# Up until OpenSSL 1.1.0, X509_STORE_add_{cert,crl}() returned an error
# if the given certificate is already in the X509_STORE
return if openssl?(1, 1, 0) || libressl?
return unless openssl? && !openssl?(1, 1, 0)
ca1 = OpenSSL::X509::Name.parse_rfc2253("CN=Root CA")
ca1_key = Fixtures.pkey("rsa-1")
ca1_cert = issue_cert(ca1, ca1_key, 1, [], nil, nil)
Expand Down
Loading