Commit graph

190 commits

Author SHA1 Message Date
Kazuki Yamaguchi
0a8a641d0a [ruby/openssl] ssl: fix SSLSocket#syswrite with String-convertible objects
Correctly pass the new object assigned by StringValue() to
ossl_ssl_write_internal_safe().

This is a follow-up to commit 0d8c17aa85 (Reduce
OpenSSL::Buffering#do_write overhead, 2024-12-21).

3ff096196a
2025-04-16 15:16:50 +00:00
Kazuki Yamaguchi
a6da77c9e9 [ruby/openssl] ssl: fix tests using TLS 1.1 or older
Commit aa7f03e18f broke test_minmax_version and test_fallback_scsv
on systems using OpenSSL 1.1.1 with a system-wide configuration file
that specifies MinProtocol=TLSv1.2.

20250228T003003Z.fail.html.gz
20250228T003003Z.fail.html.gz

These test cases were already broken before the commit, but they were
being skipped because check_supported_protocol_versions failed to detect
TLS 1.1 support. To avoid affected by the configuration file, explicitly
reset SSLContext#min_version when TLS 1.1 or older is required.

The test cases are also broken with OpenSSL 3.0 or later, but this is
not currently visible because it still fails to detect TLS 1.1 support.
This is caused by the default SSLContext#security_level value, as
OpenSSL 3.0 changed TLS 1.1 to be disabled at level 1.

6d0ea81b5e
2025-02-28 04:33:43 +00:00
Kazuki Yamaguchi
d4b8da66ca [ruby/openssl] ssl: refactor check_supported_protocol_versions
As reported in <https://github.com/ruby/ruby/pull/12823>,
check_supported_protocol_versions is unstable and occasionally fails
with Errno::ECONNABORTED during SSLSocket#connect on Windows.

When the server-side SSLContext specifies an unsupported SSL/TLS
protocol version, start_server accepts a TCP connection but closes it
without reading ClientHello, as SSLSocket#accept immediately raises an
exception. With Winsock, this can cause the client-side
SSLSocket#connect to raise Errno::ECONNABORTED.

While the simplest fix is to add rescue Errno::ECONNABORTED, this method
can be simplified. Instead, let's set up a server that accepts all
protocol versions and test client connections with different settings.

aa7f03e18f
2025-02-27 17:18:02 +00:00
Kazuki Yamaguchi
9994a95790 [ruby/openssl] ssl: manually craft invalid SAN extensions in tests
Starting with LibreSSL 3.5, OpenSSL::X509::ExtensionFactory refuses to
create SAN extensions that are not valid according to RFC 6125. While
this behavior makes sense, we need such invalid extensions to test our
own validation routine. Let's construct SAN extensions manually instead.

b420d6d739
2025-02-27 17:04:16 +00:00
Samuel Chiang
7a15ba48b5 [ruby/openssl] ssl: account for slight behavioral differences in AWS-LC
There are a few SSL discrepencies in AWS-LC when compared to OpenSSL.

1. AWS-LC has slightly different error messages (in all-caps).
2. AWS-LC has no support for DHE ciphersuites.
3. There are no concepts of SSL security levels within AWS-LC.
4. Similar to LibreSSL, there is no support for OPENSSL_CONF.

a60d050342
2025-02-22 15:11:40 +00:00
Kazuki Yamaguchi
c515da3d74 [ruby/openssl] ssl: remove cert_store from start_server test helper
OpenSSL::SSL::SSLContext#cert_store= uses SSL_CTX_set_cert_store(). The
store is used for verifying peer certificates and for building
certificate chains to be sent to the peer if there is no chain
explicitly provided by SSLContext#extra_chain_cert=.

Do not specify it in the common test helper start_server, as most
callers do not require either function. Instead, update individual test
cases that use client certificates to explicitly specify it in ctx_proc.
A more direct test case is added to verify the latter function.

9daecee615
2025-02-19 17:08:16 +00:00
Kazuki Yamaguchi
7d10c22a86 [ruby/openssl] Revert "Skip a new test when old OpenSSL"
This reverts commit 8c96a69b0d.

This is no longer necessary since we do not support OpenSSL 1.1.0
anymore.

4987688cb4
2025-02-09 10:26:07 +00:00
Kazuki Yamaguchi
581dbcec79 [ruby/openssl] ssl: prefer SSLContext#max_version= in tests
Avoid using the deprecated OpenSSL::SSL::SSLContext#ssl_version= outside
the tests specifically written for it.

93a564dec2
2025-02-09 10:26:07 +00:00
Kazuki Yamaguchi
64a98decf2 [ruby/openssl] ssl: fix misuse of assert_handshake_error in tests
assert_handshake_error is useful for checking handshake failures
triggered by the peer, as the underlying socket may be closed
prematurely, leading to different exceptions depending on the platform
and timing.

However, when the local end aborts a handshake, the only possible
exception is OpenSSL::SSL::SSLError. Use stricter assertions in such
cases.

637ba65818
2025-02-09 10:26:07 +00:00
Kazuki Yamaguchi
5791c93f8e [ruby/openssl] ssl: refactor test case test_verify_mode_server_cert
Minimize the amount of code inside the assert_raise block to avoid
accidentally catching a wrong exception.

5089b2d311
2025-02-09 10:26:06 +00:00
Kazuki Yamaguchi
a8b36314ec [ruby/openssl] ssl: fix test case test_npn_advertised_protocol_too_long
The list of NPN protocols is validated in SSLContext#setup.

The assert_handshake_error is misleading. The client is unable to start
a handshake at all because the server is not running.

e8db6ffd9e
2025-02-09 10:26:06 +00:00
Kazuki Yamaguchi
1f4fc2e608 [ruby/openssl] ssl: remove start_server_version from tests
Use start_server instead of start_server_version.

start_server_version is a wrapper around start_server that forces the
server to a specific protocol version using the now-deprecated method
SSLSocket#ssl_version=, but it does more than that. The slightly
different method signature and default values are confusing. Let's
use start_server directly.

22ed31d77e
2025-02-09 10:26:06 +00:00
Jun Aruga
adbf9c5b36 [ruby/openssl] test_ssl.rb: Test respecting system default min.
7de5ff583a
2025-02-06 14:10:34 +00:00
Kazuki Yamaguchi
5a14f53695 [ruby/openssl] ssl: separate SSLContext#min_version= and #max_version=
Make these methods simple wrappers around
SSL_CTX_set_{min,max}_proto_version().

When we introduced these methods in commit 18603949d3 [1], which went
to v2.1.0, we added a private method to SSLContext that set both the
minimum and maximum protocol versions at the same time. This was to
allow emulating the behavior using SSL options on older OpenSSL versions
that lack SSL_CTX_set_{min,max}_proto_version(). Since we no longer
support OpenSSL 1.0.2, the related code has already been removed.

In OpenSSL 1.1.1 or later, setting the minimum or maximum version to 0
is not equivalent to leaving it unset. Similar to SSL options, which we
avoid overwriting as of commit 00bec0d905 and commit 77c3db2d65 [2],
a system-wide configuration file may define a default protocol version
bounds. Setting the minimum version should not unset the maximum
version, and vice versa.

[1] https://github.com/ruby/openssl/pull/142
[2] https://github.com/ruby/openssl/pull/767

5766386321
2025-02-03 09:46:03 +00:00
Kazuki Yamaguchi
72480389d1 [ruby/openssl] ssl: fix SSLSocket#sysread leaking locktmp String on timeout
Commit 3bbf5178a9 made blocking methods on SSLSocket follow the
IO#timeout= value. The commit changed io_wait_readable() to potentially
raise an exception without unlocking the String.

The String is currently locked for the entire duration of a #sysread
method call. This does not seem to be necessary, as SSL_read() does not
require that the same buffer is specified when retrying. Locking the
String during each SSL_read() call should be sufficient.

8f791d73f5
2025-01-22 16:45:19 +00:00
Kazuki Yamaguchi
43c48e3030 [ruby/openssl] Require OpenSSL 1.1.1 or later
Drop support for OpenSSL 1.1.0. OpenSSL 1.1.0 was a non-LTS release and
it has reached upstream EOL in 2019-12 along with OpenSSL 1.0.2.
Distributions that shipped with OpenSSL 1.1.0 include:

 - Debian 9 (EOL 2022-06)
 - Ubuntu 18.04 LTS (EOL 2023-04)

ba83abe920
2025-01-21 18:14:14 +00:00
Kazuki Yamaguchi
1b515d1c37 [ruby/openssl] ssl: update test_verify_hostname_on_connect for LibreSSL
This reverts the change made to this test case in commit a0e98d48c9
(Enhance TLS 1.3 support on LibreSSL 3.2/3.3, 2020-12-03).

Part of the test case was skipped on LibreSSL because LibreSSL 3.2.2
introduced a stricter check during creation of the extension. The check
was then relaxed in LibreSSL 3.4.0.

187b176ecd
2025-01-14 12:38:17 +00:00
Kazuki Yamaguchi
0fb64bda9b [ruby/openssl] Require LibreSSL 3.9 or later
Drop support for LibreSSL 3.1-3.8. LibreSSL 3.8 has reached its EOL in
2024-10.

f33d611f9f
2025-01-14 12:38:16 +00:00
Kazuki Yamaguchi
c9bbf7e3eb [ruby/openssl] ssl: do not clear existing SSL options in SSLContext#set_params
Apply SSL options set in DEFAULT_PARAMS without clearing existing
options.

It currently clears options in order to avoid setting one of the
options included in OpenSSL::SSL::OP_ALL unless explicitly specified,
namely OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS. Now that
OpenSSL::SSL::OP_ALL has been removed from SSLContext#initialize, it is
no longer necessary.

77c3db2d65
2024-12-07 08:15:08 +00:00
Kazuki Yamaguchi
510c190739 [ruby/openssl] ssl: do not enable OpenSSL::SSL::OP_ALL by default
Respect the SSL options set by default by SSL_CTX() and by the
system-wide OpenSSL configuration file.

OpenSSL::SSL::SSLContext#initialize currently adds OpenSSL::SSL::OP_ALL
on top of the default SSL options. Let's stop doing it.

OpenSSL::SSL::OP_ALL is a set of options that changes OpenSSL's behavior
to workaround various TLS implementation bugs. Using it is considered
usually safe, but is not completely harmless.

00bec0d905
2024-12-07 08:15:08 +00:00
Grant Gardner
4d4ac00123 [ruby/openssl] Add SSLSocket#readbyte
Companion to getbyte but raise EOFError
Similar to https://github.com/ruby/openssl/pull/438

c40f70711a
2024-07-03 08:54:18 +00:00
Peter Zhu
e0949c3f7c [ruby/openssl] Remove trailing space in test_ssl.rb
911a31335f
2024-04-30 15:23:15 +00:00
Samuel Williams
1699772ac4 [ruby/openssl] Introduce basic support for close_read and close_write.
c99d24cee9
2024-04-30 14:51:58 +00:00
Hiroshi SHIBATA
7630a89a4b Use www.rfc-editor.org for RFC text.
We use the following site for that now:

* https://tools.ietf.org/ or http
* https://datatracker.ietf.org or http

Today, IETF said the official site of RFC is www.rfc-editor.org.

FYI: https://authors.ietf.org/en/references-in-rfcxml

I replaced them to www.rfc-editor.org.
2024-03-28 11:44:45 +09:00
Samuel Williams
4f634d3c85 [ruby/openssl] Add support for IO#timeout.
(https://github.com/ruby/openssl/pull/714)

* Add support for IO#timeout.

3bbf5178a9
2024-01-17 17:09:03 +00:00
Kazuki Yamaguchi
01d368e7b0 [ruby/openssl] ssl: raise SSLError if loading ca_file or ca_path fails
When compiled with OpenSSL <= 1.1.1, OpenSSL::SSL::SSLContext#setup
does not raise an exception on an error return from
SSL_CTX_load_verify_locations(), but instead only prints a verbose-mode
warning. This is not helpful since it very likely indicates an actual
error, such as the specified file not being readable.

Also, OpenSSL's error queue is not correctly cleared:

	$ ruby -w -ropenssl -e'OpenSSL.debug=true; ctx=OpenSSL::SSL::SSLContext.new; ctx.ca_file="bad-path"; ctx.setup; pp OpenSSL.errors'
	-e:1: warning: can't set verify locations
	["error:02001002:system library:fopen:No such file or directory",
	 "error:2006D080:BIO routines:BIO_new_file:no such file",
	 "error:0B084002:x509 certificate routines:X509_load_cert_crl_file: system lib"]

The behavior is currently different when compiled with OpenSSL >= 3.0:
SSLError is raised if SSL_CTX_load_verify_file() or
SSL_CTX_load_verify_dir() fails.

This inconsistency was unintentionally introduced by commit 5375a55ffc
("ssl: use SSL_CTX_load_verify_{file,dir}() if available", 2020-02-22).
However, raising SSLError seems more appropriate in this situation.
Let's adjust the OpenSSL <= 1.1.1 code so that it behaves the same way
as the OpenSSL >= 3.0 code currently does.

Fixes: https://github.com/ruby/openssl/issues/649

7eb10f7b75
2023-08-16 14:48:41 +09:00
Kazuki Yamaguchi
4465941e68 [ruby/openssl] Revert "Relax error message check for OpenSSL 3.1"
This reverts commit fc4629d246.

The test case "test_connect_certificate_verify_failed_exception_message"
does want to check the reason behind a certificate verification failure
to be included in the exception message.

c309745eb8
2023-08-16 14:48:39 +09:00
Nobuyoshi Nakada
0b303c6830 [ruby/openssl] Relax error message check for OpenSSL 3.1
A tentative measures fo https://github.com/ruby/openssl/issues/606.

With OpenSSL 3.1.0, the error message at connection using "self-signed
certificate" seems to return `SSL_R_TLSV1_ALERT_UNKNOWN_CA` instead of
`SSL_R_CERTIFICATE_VERIFY_FAILED`.

fc4629d246
2023-03-16 17:17:46 +09:00
Kazuki Yamaguchi
a4b4997c69 [ruby/openssl] test/openssl/test_ssl.rb: do not run SSL tests if not available
a3d230d4e0
2022-12-23 09:39:15 +09:00
Kazuki Yamaguchi
dd6f3276e0 [ruby/openssl] ssl: disable NPN support on LibreSSL
As noted in commit a2ed156cc9 ("test/test_ssl: do not run NPN tests
for LibreSSL >= 2.6.1", 2017-08-13), NPN is known not to work properly
on LibreSSL.

Disable NPN support on LibreSSL, whether OPENSSL_NO_NEXTPROTONEG is
defined or not.

NPN is less relevant today anyway. Let's also silence test suite when
it's not available.

289f6e0e1f
2022-12-23 09:39:15 +09:00
Christophe De La Fuente
17998ad3bb [ruby/openssl] Add support to SSL_CTX_set_keylog_callback
- This callback is invoked when TLS key material is generated or
  received, in order to allow applications to store this keying material
  for debugging purposes.
- It is invoked with an `SSLSocket` and a string containing the key
  material in the format used by NSS for its SSLKEYLOGFILE debugging
  output.
- This commit adds the Ruby binding `keylog_cb` and the related tests
- It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements
  `SSL_CTX_set_keylog_callback()` from v3.4.2, it does nothing (see
  648d39f0f0)

3b63232cf1
2022-10-17 16:35:35 +09:00
madblobfish
79543b9a53 [ruby/openssl] ssl: enable generating keying material from SSL sessions
Add OpenSSL::SSL::SSLSocket#export_keying_material to support RFC 5705

65530b887e
2022-10-17 16:35:35 +09:00
Nobuyoshi Nakada
949c3afb48 [ruby/openssl] Skip a new test when old OpenSSL
It does not raise an error when setting an invalid value to SSLContext
ciphers on Ubuntu 18.04.

8c96a69b0d
2022-07-09 15:26:32 +09:00
Nobuyoshi Nakada
d77ebe8eea
[ruby/openssl] Strip trailing spaces [ci skip]
862d92de93
2022-07-09 00:39:18 +09:00
Jeremy Evans
def445303a [ruby/openssl] Fix test of cipher name to pass in LibreSSL 3.4
LibreSSL 3.5 switched the cipher naming to match OpenSSL.

bf198278bd
2022-07-08 23:18:18 +09:00
twkmd12
09daf78fb5 [ruby/openssl] Add 'ciphersuites=' method to allow setting of TLSv1.3 cipher suites along with some unit tests (https://github.com/ruby/openssl/pull/493)
Add OpenSSL::SSL::SSLContext#ciphersuites= method along with unit tests.

12250c7cef
2022-07-08 23:18:11 +09:00
Jeremy Evans
01025a0055 [ruby/openssl] Skip optional wildcard SAN tests on LibreSSL 3.5.0+
RFC 6066 states how some wildcard SAN entries MAY be handled, but
it does not say they MUST be handled.  LibreSSL 3.5.0 only handles
suffix wildcard SANs, not prefix wildcard SANs, or interior
wildcard SANs, so return early from the wildcard SAN tests on
LibreSSL 3.5.0.

Fixes #471

717d7009d6
2022-07-08 23:18:07 +09:00
Kazuki Yamaguchi
2df917ed4f [ruby/openssl] ssl: update test_options_disable_versions
Use the combination of TLS 1.2 and TLS 1.3 instead of TLS 1.1 and TLS
1.2 so that will the test case will be run on latest platforms.

e168df0f35
2021-12-20 23:42:04 +09:00
Kazuki Yamaguchi
15eefd30ad [ruby/openssl] ssl: update test_accept_errors_include_peeraddr test case
Use a different invalid data example to prevent SSLSocket#accept from
reaching EOF.

2e089c1916
2021-12-20 23:42:03 +09:00
Kazuki Yamaguchi
cd51bf61a2 test/openssl/test_ssl: adjust certificate expiry date
test_connect_certificate_verify_failed_exception_message occasionally
fails. Is it possible that OpenSSL sees a different clock from Ruby by
more than 10 seconds?

http://ci.rvm.jp/logfiles/brlog.trunk-random0.20211111-072828

Let's give more time after the certificate expiration date to see if
this fixes the flakiness. We had similar occasional failures in
test_x509store.rb before, which disappeared after ruby/ruby commit
7930a352a5 and ruby/openssl commit fb2fcbb13734.
2021-11-11 17:59:22 +09:00
Kazuki Yamaguchi
1ac7f23bb8 [ruby/openssl] ssl: disallow reading/writing to unstarted SSL socket
OpenSSL::SSL::SSLSocket allowed #read and #write to be called before an
SSL/TLS handshake is completed. They passed unencrypted data to the
underlying socket.

This behavior is very odd to have in this library. A verbose mode
warning "SSL session is not started yet" was emitted whenever this
happened. It also didn't behave well with OpenSSL::Buffering. Let's
just get rid of it.

Fixes: https://github.com/ruby/openssl/issues/9

bf780748b3
2021-11-01 17:48:02 +09:00
Kazuki Yamaguchi
cda8bc3657 [ruby/openssl] test/openssl/test_ssl: use assert_raise in test_bad_socket
The Ruby tree disallows assert_raises.

9b4f761e74
2021-10-23 13:38:40 +09:00
Aaron Patterson
35b9d8d393 [ruby/openssl] Raise an exception if the IO object passed to SSLSocket isn't a file
SSLSocket#connect eventually calls `GetOpenFile` in order to get the
underlying file descriptor for the IO object passed in on
initialization.  `GetOpenFile` assumes that the Ruby object passed in is
a T_FILE object and just casts it to a T_FILE without any checks.  If
you pass an object that *isn't* a T_FILE to that function, the program
will segv.

Since we assume the IO object is a file in the `connect` method, this
commit adds a `CheckType` in the initialize method to ensure that the IO
object is actually a T_FILE.  If the object *isn't* a T_FILE, this class
will segv on `connect`, so I think this is a backwards compatible
change.

919fa44ec2
2021-10-23 13:38:40 +09:00
Kazuki Yamaguchi
d67fe1e9de [ruby/openssl] test/openssl/test_ssl: fix illegal SAN extension
A certificate can only have one SubjectAltName extension. OpenSSL 3.0
performs a stricter validation and certificates containing multiple SANs
will be rejected.

558cfbe5f5
2021-10-23 13:38:38 +09:00
Kazuki Yamaguchi
d26e64e0eb [ruby/openssl] test/openssl/test_ssl: relax regex to match OpenSSL's error message
OpenSSL 3.0 slightly changed the error message for a certificate
verification failure when an untrusted self-signed certificate is found
in the chain.

b5a0a19850
2021-10-23 13:38:38 +09:00
Kazuki Yamaguchi
5a8e1c520a [ruby/openssl] test/openssl/test_ssl: assume ECC support
Disabling ECC support of OpenSSL is impractical nowadays.

We still try to have the C extension compile on no-ec builds (as well
as no-dh or no-engine, etc.) as long as we can, but keeping test cases
for such an extreme scenario is not worth the effort.

2cd01d4676
2021-10-23 13:38:37 +09:00
Kazuki Yamaguchi
0e805e73ce [ruby/openssl] test/openssl/test_ssl: assume TLS 1.2 support
Current versions of OpenSSL and LibreSSL all support TLS 1.2, so there
is no need for checking the availability.

a175a41529
2021-10-23 13:38:36 +09:00
Kazuki Yamaguchi
e36906f9ab [ruby/openssl] test/openssl/test_ssl: use TLS 1.2 for finished_messages on LibreSSL
LibreSSL 2.2.x has a bug in the Finished message handling with TLS 1.3.
This is fixed by LibreSSL 3.3.2.

0bea59d245
2021-10-16 18:34:35 +09:00
Kazuki Yamaguchi
6105ef7629 [ruby/openssl] ssl: add SSLContext#tmp_dh=
Provide a wrapper of SSL_set0_tmp_dh_pkey()/SSL_CTX_set_tmp_dh(), which
sets the DH parameters used for ephemeral DH key exchange.

SSLContext#tmp_dh_callback= already exists for this purpose, as a
wrapper around SSL_CTX_set_tmp_dh_callback(), but it is considered
obsolete and the OpenSSL API is deprecated for future removal. There is
no practical use case where an application needs to use different DH
parameters nowadays. This was originally introduced to support export
grade ciphers.

RDoc for #tmp_dh_callback= is updated to recommend the new #tmp_dh=.

Note that current versions of OpenSSL support automatic ECDHE curve
selection which is enabled by default. SSLContext#tmp_dh= should only be
necessary if you must allow ancient clients which don't support ECDHE.

aa43da4f04
2021-10-16 18:19:52 +09:00
Vinicius Stock
4f7c3f631a [ruby/openssl] Include peer socket IP address in errors
8a1e3f5085
2021-07-18 17:45:03 +09:00