gh-146207: Add support for OpenSSL 4.0.0 alpha1#146217
gh-146207: Add support for OpenSSL 4.0.0 alpha1#146217vstinner wants to merge 8 commits intopython:mainfrom
Conversation
OpenSSL 4.0.0 alpha1 no longer defines the symbols: * SSLv3_method * TLSv1_method * TLSv1_1_method * TLSv1_2_method
|
I didn't test my own change on OpenSSL 4.0.0 alpha1, I only asked @heitbaum to test my change. |
|
@vstinner This patch (should, probably :) ) be enough to get you a test in CI, even if we don't want to merge it yet: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2fa2ab768dc..40feaef01ce 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -275,6 +275,7 @@ jobs:
- { name: openssl, version: 3.4.4 }
- { name: openssl, version: 3.5.5 }
- { name: openssl, version: 3.6.1 }
+ - { name: openssl, version: 4.0.0-alpha1 }
## AWS-LC
- { name: aws-lc, version: 1.68.0 }
env: |
|
I applied @zware's patch: Tests / Ubuntu SSL tests (ubuntu-24.04, openssl, 4.0.0-alpha1) job is currently running.
Yeah, I will revert this patch once we get the openssl, 4.0.0-alpha1 CI job result. |
|
Not as simple as hoped :(. I can reproduce the CI failure locally, though; there's a missing symlink (or With that, I get these failures: 2 tests failed:
test_ssl test_urllib2_localnet
43 tests OK.
0:00:23 load avg: 3.07 Re-running 2 failed tests in verbose mode in subprocesses
0:00:23 load avg: 3.07 Run 2 tests in parallel using 2 worker processes
0:00:24 load avg: 3.07 [1/2/1] test_ssl failed (1 failure)
Re-running test_ssl in verbose mode (matching: test_openssl_version)
test_ssl: testing with 'OpenSSL 4.0.0-alpha1 10 Mar 2026' (4, 0, 0, 0, 0)
under 'Linux-6.19.7-200.fc43.x86_64-x86_64-with-glibc2.42'
HAS_SNI = True
OP_ALL = 0x80000050
OP_NO_TLSv1_1 = 0x10000000
test_openssl_version (test.test_ssl.BasicSocketTests.test_openssl_version) ... FAIL
======================================================================
FAIL: test_openssl_version (test.test_ssl.BasicSocketTests.test_openssl_version)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/cpython/bump_multissl_awslc/Lib/test/test_ssl.py", line 590, in test_openssl_version
self.assertLess(n, 0x40000000)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
AssertionError: 1073741824 not less than 1073741824
----------------------------------------------------------------------
Ran 1 test in 0.007s
FAILED (failures=1)
test test_ssl failed
0:00:24 load avg: 3.07 [2/2/2] test_urllib2_localnet failed (2 errors)
Re-running test_urllib2_localnet in verbose mode (matching: test_https, test_https_sni)
test_https (test.test_urllib2_localnet.TestUrlopen.test_https) ... ERROR
stopping HTTPS server
joining HTTPS thread
test_https_sni (test.test_urllib2_localnet.TestUrlopen.test_https_sni) ... ERROR
stopping HTTPS server
joining HTTPS thread
======================================================================
ERROR: test_https (test.test_urllib2_localnet.TestUrlopen.test_https)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/cpython/bump_multissl_awslc/Lib/test/test_urllib2_localnet.py", line 569, in test_https
data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context)
File "/path/to/cpython/bump_multissl_awslc/Lib/test/test_urllib2_localnet.py", line 473, in urlopen
l.extend(f.readlines(200))
~~~~~~~~~~~^^^^^
File "/path/to/cpython/bump_multissl_awslc/Lib/http/client.py", line 714, in readline
result = self.fp.readline(limit)
File "/path/to/cpython/bump_multissl_awslc/Lib/socket.py", line 734, in readinto
return self._sock.recv_into(b)
~~~~~~~~~~~~~~~~~~~~^^^
File "/path/to/cpython/bump_multissl_awslc/Lib/ssl.py", line 1355, in recv_into
return self.read(nbytes, buffer)
~~~~~~~~~^^^^^^^^^^^^^^^^
File "/path/to/cpython/bump_multissl_awslc/Lib/ssl.py", line 1154, in read
return self._sslobj.read(len, buffer)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
ssl.SSLError: A failure in the SSL library occurred (_ssl.c:2977)
======================================================================
ERROR: test_https_sni (test.test_urllib2_localnet.TestUrlopen.test_https_sni)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/cpython/bump_multissl_awslc/Lib/test/test_urllib2_localnet.py", line 585, in test_https_sni
self.urlopen("https://localhost:%s" % handler.port, context=context)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/path/to/cpython/bump_multissl_awslc/Lib/test/test_urllib2_localnet.py", line 473, in urlopen
l.extend(f.readlines(200))
~~~~~~~~~~~^^^^^
File "/path/to/cpython/bump_multissl_awslc/Lib/http/client.py", line 714, in readline
result = self.fp.readline(limit)
File "/path/to/cpython/bump_multissl_awslc/Lib/socket.py", line 734, in readinto
return self._sock.recv_into(b)
~~~~~~~~~~~~~~~~~~~~^^^
File "/path/to/cpython/bump_multissl_awslc/Lib/ssl.py", line 1355, in recv_into
return self.read(nbytes, buffer)
~~~~~~~~~^^^^^^^^^^^^^^^^
File "/path/to/cpython/bump_multissl_awslc/Lib/ssl.py", line 1154, in read
return self._sslobj.read(len, buffer)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
ssl.SSLError: A failure in the SSL library occurred (_ssl.c:2977)
----------------------------------------------------------------------
Ran 2 tests in 0.122s
FAILED (errors=2)
test test_urllib2_localnet failed
2 tests failed again:
test_ssl test_urllib2_localnet |
|
I tested I fixed a few more issues, but |
I fixed that with a5152be. |
|
Tested results in #146207 (comment) |
This reverts commit 5f9bc31.
|
@picnixz @gpshead @zware: Would you mind to review this change? I reverted the change to run "Tests / Ubuntu SSL tests (ubuntu-24.04, openssl, 4.0.0-alpha1)" CI job. I don't think that we should test alpha versions in our CI. There are still two Also, I think that we should backport the change to Python 3.13 and 3.14 to also prepare these branches to OpenSSL 4. |
|
I am not very fond of adding support in stable branches for an alpha version for now as I do not know if/how the ABI could change. I do not mind having a presupport in 3.15 so that we can get feedback during our beta but I will take a look at what is planned in OpenSSL once I am at home. |
| #error Unsupported OpenSSL version | ||
| #endif | ||
|
|
||
| #if (OPENSSL_VERSION_NUMBER >= 0x40000000L) |
There was a problem hiding this comment.
Isn't it possible to retain those constants using the OpenSSL compatibility features or are these constants entirely gone?
There was a problem hiding this comment.
The 4 methods are gone but I cannot find OPENSSL_NO_ macro in the public header files:
$ nm multissl/openssl/4.0.0-alpha1/lib64/libssl.so.4 |grep SSLv3_method
$ nm multissl/openssl/4.0.0-alpha1/lib64/libssl.so.4 |grep TLSv1_method
$ nm multissl/openssl/4.0.0-alpha1/lib64/libssl.so.4 |grep TLSv1_1_method
$ nm multissl/openssl/4.0.0-alpha1/lib64/libssl.so.4 |grep TLSv1_2_method
$ grep OPENSSL_NO_SSL3 multissl/openssl/4.0.0-alpha1/include/openssl/ -R
$ grep OPENSSL_NO_TLS1 multissl/openssl/4.0.0-alpha1/include/openssl/ -R
$ grep OPENSSL_NO_TLS1_1 multissl/openssl/4.0.0-alpha1/include/openssl/ -R
$ grep OPENSSL_NO_TLS1_2 multissl/openssl/4.0.0-alpha1/include/openssl/ -R
There was a problem hiding this comment.
Now that I think more about it, I think those macros are defined by your build configuration and the generated headers. I never remember which macro is defined explicitly through other macros and which macros are defined dynamically after the configure step
| # define OPENSSL_NO_TLS1 | ||
| # define OPENSSL_NO_TLS1_1 | ||
| # define OPENSSL_NO_TLS1_2 | ||
| #endif |
There was a problem hiding this comment.
I cannot comment on the lines above this block but we need to check if mnemonics changed in 4.0 as well and generate dedicated data. I would still generate dedicated data just because the major version was bumped.
There was a problem hiding this comment.
I expect that OpenSSL will still change before the OpenSSL 4.0 final release. Can we wait for the final release before generating the "ssl data" header file?
| def _post_install(self): | ||
| if self.version.startswith("3."): | ||
| if self.version.startswith(("3.", "4.")): | ||
| self._post_install_3xx() |
There was a problem hiding this comment.
For the future, it is better to have two methods for post install, one for 3.x and one for 4.x
There was a problem hiding this comment.
Currently, the script does the same operations on OpenSSL 3 and OpenSSL 4. Is it worth it to have two methods which do the same operations?
There was a problem hiding this comment.
I would say yes as we do not know what will be needed with 4.x (I do not mind having the 4xx call the 3xx with a comment saying that for now it is identical).
I will give you an answer about it once I looked at the OpenSSL roadmap so ok for leaving it that way for now.
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
vstinner
left a comment
There was a problem hiding this comment.
I updated the PR to define also the _METHOD macros:
+# define OPENSSL_NO_SSL3_METHOD
+# define OPENSSL_NO_TLS1_METHOD
+# define OPENSSL_NO_TLS1_1_METHOD
+# define OPENSSL_NO_TLS1_2_METHOD| #error Unsupported OpenSSL version | ||
| #endif | ||
|
|
||
| #if (OPENSSL_VERSION_NUMBER >= 0x40000000L) |
There was a problem hiding this comment.
The 4 methods are gone but I cannot find OPENSSL_NO_ macro in the public header files:
$ nm multissl/openssl/4.0.0-alpha1/lib64/libssl.so.4 |grep SSLv3_method
$ nm multissl/openssl/4.0.0-alpha1/lib64/libssl.so.4 |grep TLSv1_method
$ nm multissl/openssl/4.0.0-alpha1/lib64/libssl.so.4 |grep TLSv1_1_method
$ nm multissl/openssl/4.0.0-alpha1/lib64/libssl.so.4 |grep TLSv1_2_method
$ grep OPENSSL_NO_SSL3 multissl/openssl/4.0.0-alpha1/include/openssl/ -R
$ grep OPENSSL_NO_TLS1 multissl/openssl/4.0.0-alpha1/include/openssl/ -R
$ grep OPENSSL_NO_TLS1_1 multissl/openssl/4.0.0-alpha1/include/openssl/ -R
$ grep OPENSSL_NO_TLS1_2 multissl/openssl/4.0.0-alpha1/include/openssl/ -R
| # define OPENSSL_NO_TLS1 | ||
| # define OPENSSL_NO_TLS1_1 | ||
| # define OPENSSL_NO_TLS1_2 | ||
| #endif |
There was a problem hiding this comment.
I expect that OpenSSL will still change before the OpenSSL 4.0 final release. Can we wait for the final release before generating the "ssl data" header file?
| def _post_install(self): | ||
| if self.version.startswith("3."): | ||
| if self.version.startswith(("3.", "4.")): | ||
| self._post_install_3xx() |
There was a problem hiding this comment.
Currently, the script does the same operations on OpenSSL 3 and OpenSSL 4. Is it worth it to have two methods which do the same operations?
|
According to the manpage, for the OPENSSL_sk_set_thunks(), the function is public by necessity but is actually an internal function and should not be used. |
OpenSSL 4.0.0 alpha1 no longer defines the symbols: