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

[2.1.x and 2.2.x] ext/openssl/extconf.rb: require OpenSSL version >= 1.0.1, < 3 #458

Merged
merged 3 commits into from
Sep 27, 2021
Merged
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
7 changes: 4 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,11 @@ jobs:
- openssl-1.0.1u # EOL
- openssl-1.0.2u # EOL
- openssl-1.1.0l # EOL
- openssl-1.1.1j
- openssl-1.1.1l
- libressl-2.5.5 # EOL
- libressl-3.1.5
- libressl-3.2.0
- libressl-3.1.5 # EOL
- libressl-3.2.6
- libressl-3.3.4
steps:
- name: repo checkout
uses: actions/checkout@v2
Expand Down
43 changes: 25 additions & 18 deletions ext/openssl/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@
have_library("ws2_32")
end

Logging::message "=== Checking for required stuff... ===\n"
result = pkg_config("openssl") && have_header("openssl/ssl.h")

def find_openssl_library
if $mswin || $mingw
# required for static OpenSSL libraries
Expand Down Expand Up @@ -90,19 +87,33 @@ def find_openssl_library
return false
end

unless result
unless find_openssl_library
Logging::message "=== Checking for required stuff failed. ===\n"
Logging::message "Makefile wasn't created. Fix the errors above.\n"
raise "OpenSSL library could not be found. You might want to use " \
"--with-openssl-dir=<dir> option to specify the prefix where OpenSSL " \
"is installed."
end
Logging::message "=== Checking for required stuff... ===\n"
pkg_config_found = pkg_config("openssl") && have_header("openssl/ssl.h")

if !pkg_config_found && !find_openssl_library
Logging::message "=== Checking for required stuff failed. ===\n"
Logging::message "Makefile wasn't created. Fix the errors above.\n"
raise "OpenSSL library could not be found. You might want to use " \
"--with-openssl-dir=<dir> option to specify the prefix where OpenSSL " \
"is installed."
end

unless checking_for("OpenSSL version is 1.0.1 or later") {
try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10001000L", "openssl/opensslv.h") }
raise "OpenSSL >= 1.0.1 or LibreSSL is required"
version_ok = if have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h")
is_libressl = true
checking_for("LibreSSL version >= 2.5.0") {
try_static_assert("LIBRESSL_VERSION_NUMBER >= 0x20500000L", "openssl/opensslv.h") }
else
checking_for("OpenSSL version >= 1.0.1 and < 3.0.0") {
try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10001000L", "openssl/opensslv.h") &&
!try_static_assert("OPENSSL_VERSION_MAJOR >= 3", "openssl/opensslv.h") }
end
unless version_ok
raise "OpenSSL >= 1.0.1, < 3.0.0 or LibreSSL >= 2.5.0 is required"
end

# Prevent wincrypt.h from being included, which defines conflicting macro with openssl/x509.h
if is_libressl && ($mswin || $mingw)
$defs.push("-DNOCRYPT")
end

Logging::message "=== Checking for OpenSSL features... ===\n"
Expand All @@ -114,10 +125,6 @@ def find_openssl_library
OpenSSL.check_func_or_macro("ENGINE_load_#{name}", "openssl/engine.h")
}

if ($mswin || $mingw) && have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h")
$defs.push("-DNOCRYPT")
end

# added in 1.0.2
have_func("EC_curve_nist2nid")
have_func("X509_REVOKED_dup")
Expand Down
6 changes: 6 additions & 0 deletions ext/openssl/ossl_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@

#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))

#if !defined(TLS1_3_VERSION) && \
defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER >= 0x3020000fL
# define TLS1_3_VERSION 0x0304
#endif

#ifdef _WIN32
# define TO_SOCKET(s) _get_osfhandle(s)
#else
Expand Down
47 changes: 36 additions & 11 deletions test/test_ssl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@ def test_client_auth_failure

def test_client_auth_success
vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
start_server(verify_mode: vflag) { |port|
start_server(verify_mode: vflag,
ctx_proc: proc { |ctx|
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
}) { |port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = @cli_key
ctx.cert = @cli_cert
Expand Down Expand Up @@ -253,6 +256,8 @@ def test_client_auth_public_key
end

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

ctx_proc = Proc.new do |ctx|
ctx.client_ca = [@ca_cert]
end
Expand Down Expand Up @@ -793,11 +798,13 @@ def test_servername_cb_raises_an_exception_on_unknown_objects

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)
exts = [
["keyUsage", "keyEncipherment,digitalSignature", true],
["subjectAltName", "DNS:a.example.com,DNS:*.b.example.com," \
"DNS:c*.example.com,DNS:d.*.example.com"],
["subjectAltName", san],
]

ctx.cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key)
ctx.key = @svr_key
}
Expand All @@ -818,6 +825,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)
begin
sock = TCPSocket.new("127.0.0.1", port)
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
Expand Down Expand Up @@ -1501,12 +1509,13 @@ def test_tmp_ecdh_callback
end
end

def test_ecdh_curves
def test_ecdh_curves_tls12
pend "EC is disabled" unless defined?(OpenSSL::PKey::EC)

ctx_proc = -> ctx {
# Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3
ctx.ciphers = "DEFAULT:!kRSA:!kEDH"
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
ctx.ciphers = "kEECDH"
ctx.ecdh_curves = "P-384:P-521"
}
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
Expand All @@ -1515,13 +1524,9 @@ def test_ecdh_curves

server_connect(port, ctx) { |ssl|
cs = ssl.cipher[0]
if /\ATLS/ =~ cs # Is TLS 1.3 is used?
assert_match (/\AECDH/), cs
if ssl.respond_to?(:tmp_key)
assert_equal "secp384r1", ssl.tmp_key.group.curve_name
else
assert_match (/\AECDH/), cs
if ssl.respond_to?(:tmp_key)
assert_equal "secp384r1", ssl.tmp_key.group.curve_name
end
end
ssl.puts "abc"; assert_equal "abc\n", ssl.gets
}
Expand All @@ -1545,6 +1550,26 @@ def test_ecdh_curves
end
end

def test_ecdh_curves_tls13
pend "EC is disabled" unless defined?(OpenSSL::PKey::EC)
pend "TLS 1.3 not supported" unless tls13_supported?

ctx_proc = -> ctx {
# Assume TLS 1.3 is enabled and chosen by default
ctx.ecdh_curves = "P-384:P-521"
}
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.ecdh_curves = "P-256:P-384" # disable P-521

server_connect(port, ctx) { |ssl|
assert_equal "TLSv1.3", ssl.ssl_version
assert_equal "secp384r1", ssl.tmp_key.group.curve_name
ssl.puts "abc"; assert_equal "abc\n", ssl.gets
}
end
end

def test_security_level
ctx = OpenSSL::SSL::SSLContext.new
begin
Expand Down
1 change: 1 addition & 0 deletions test/test_ssl_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,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)
}
start_server(ctx_proc: ctx_proc) do |port|
sess1 = server_connect_with_session(port, nil, nil) { |ssl|
Expand Down
8 changes: 8 additions & 0 deletions test/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,14 @@ def tls12_supported?
rescue
end

def tls13_supported?
return false unless defined?(OpenSSL::SSL::TLS1_3_VERSION)
ctx = OpenSSL::SSL::SSLContext.new
ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION
true
rescue
end

def readwrite_loop(ctx, ssl)
while line = ssl.gets
ssl.write(line)
Expand Down