You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test_min_max_version in test_ssl.py fails when Python is built against LibreSSL; {min,max}imum_version behavior differs from OpenSSL #78176
bpo-35045: test_min_max_version (test.test_ssl.ContextTests) fails on Fedora 29+ and openssl 1.1.1
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=<Date2019-01-18.15:21:55.523>created_at=<Date2018-06-29.05:32:25.722>labels= ['3.7', 'expert-SSL', '3.8', 'type-bug', 'tests']
title='test_min_max_version in test_ssl.py fails when Python is built against LibreSSL; {min,max}imum_version behavior differs from OpenSSL'updated_at=<Date2019-01-18.15:21:55.518>user='https://github.com/alanhuang122'
LibreSSL's implementation of the function used to get the minimum and maximum SSL versions supported differs from OpenSSL's.
In short, the issue is in the implementations of SSL_CTX_new - OpenSSL initializes variables ret->{min,max}_proto_version to 0, while LibreSSL initializes corresponding variables to those of the SSL_METHOD given.
As such, when Python is built with LibreSSL, the default values for an instance of ssl.SSLContext are, in the case of ssl.SSLContext(), ctx.minimum_version = <TLSVersion.TLSv1: 769>; ctx.maximum_version = <TLSVersion.TLSv1_2: 771>.
This is NOT what test_ssl.py expects; it expects OpenSSL's behavior of initializing the version variables to zero, which _ssl.c then translates to PY_PROTO_{MIN,MAX}IMUM_SUPPORTED -> ssl.TLSVersion.{MIN,MAX}IMUM_SUPPORTED.
Additionally, LibreSSL, when SSL_CTX_set_{min,max}_proto_version is called with version equal to zero, explicitly sets the minimum / maximum values equal to the minimum / maximum values for the SSL_METHOD it was called with (namely, 769/770/771, in the case of TLS_method()), not the minimum / maximum values supported by the library.
I have sent an email to the LibreSSL mailing list asking for clarification on this point, namely, if this is intended behavior. If it is, there are two ways that come to mind to work around this behavior. Both ways would only be necessary if IS_LIBRESSL.
Skip test_min_max_version.
Instead of testing that ctx is equal to the extremes after it's been set to one of the extremes, test that it's equal to the actual constants.
There are two ways this could be accomplished as well:
a. Use PY_PROTO_{MIN,MAX}IMUM_AVAILABLE, defined in _ssl.c (this may require the addition of another call to PyModule_AddIntConstant to provide access to the constant from ssl). The downside to this approach is that it assumes that TLS_method(), or whatever SSL_METHOD test_ssl.py uses has lower and upper bounds equal to PY_PROTO{MIN,MAX}IMUM_AVAILABLE, which may not always be the case.
b. Access and store the values for ctx.{min,max}imum_value on creation, then reference them after setting.
Either of these approaches would likely also have the benefit of removing the need for self.assertIn(ctx.minimum_version, {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}).
The test that failed was:
======================================================================
FAIL: test_min_max_version (test.test_ssl.ContextTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/alan/src/cpython/Lib/test/test_ssl.py", line 1066, in test_min_max_version
ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTEDAssertionError: <TLSVersion.TLSv1: 769> != <TLSVersion.MINIMUM_SUPPORTED: -2>
Addendum:
I found the documentation for ssl.TLSVersion.{MAX,MIN}IMUM_SUPPORTED confusing at first - it took me quite a while to realize what the purpose of the constants were; I would have expected them to contain the maximum and minimum protocol versions supported by the library; I see why it was phrased that way, after having boned up on ssl.py, _ssl.c, and OpenSSL/LibreSSL, but think it could could be made clearer.
Activity
alanhuang122 commentedon Jun 29, 2018
LibreSSL's implementation of the function used to get the minimum and maximum SSL versions supported differs from OpenSSL's.
In short, the issue is in the implementations of
SSL_CTX_new- OpenSSL initializes variablesret->{min,max}_proto_versionto 0, while LibreSSL initializes corresponding variables to those of theSSL_METHODgiven.As such, when Python is built with LibreSSL, the default values for an instance of ssl.SSLContext are, in the case of ssl.SSLContext(), ctx.minimum_version = <TLSVersion.TLSv1: 769>; ctx.maximum_version = <TLSVersion.TLSv1_2: 771>.
This is NOT what test_ssl.py expects; it expects OpenSSL's behavior of initializing the version variables to zero, which _ssl.c then translates to PY_PROTO_{MIN,MAX}IMUM_SUPPORTED -> ssl.TLSVersion.{MIN,MAX}IMUM_SUPPORTED.
Additionally, LibreSSL, when
SSL_CTX_set_{min,max}_proto_versionis called withversionequal to zero, explicitly sets the minimum / maximum values equal to the minimum / maximum values for theSSL_METHODit was called with (namely, 769/770/771, in the case ofTLS_method()), not the minimum / maximum values supported by the library.I have sent an email to the LibreSSL mailing list asking for clarification on this point, namely, if this is intended behavior. If it is, there are two ways that come to mind to work around this behavior. Both ways would only be necessary if
IS_LIBRESSL.test_min_max_version.There are two ways this could be accomplished as well:
a. Use PY_PROTO_{MIN,MAX}IMUM_AVAILABLE, defined in _ssl.c (this may require the addition of another call to
PyModule_AddIntConstantto provide access to the constant from ssl). The downside to this approach is that it assumes thatTLS_method(), or whateverSSL_METHODtest_ssl.py uses has lower and upper bounds equal to PY_PROTO{MIN,MAX}IMUM_AVAILABLE, which may not always be the case.b. Access and store the values for ctx.{min,max}imum_value on creation, then reference them after setting.
Either of these approaches would likely also have the benefit of removing the need for
self.assertIn(ctx.minimum_version, {ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}).The test that failed was:
======================================================================
FAIL: test_min_max_version (test.test_ssl.ContextTests)
----------------------------------------------------------------------
Addendum:
I found the documentation for ssl.TLSVersion.{MAX,MIN}IMUM_SUPPORTED confusing at first - it took me quite a while to realize what the purpose of the constants were; I would have expected them to contain the maximum and minimum protocol versions supported by the library; I see why it was phrased that way, after having boned up on ssl.py, _ssl.c, and OpenSSL/LibreSSL, but think it could could be made clearer.
alanhuang122 commentedon Jul 2, 2018
PR 8050 implements option 2a (use PY_PROTO_{MIN,MAX}IMUM_AVAILABLE).
vstinner commentedon Jan 18, 2019
Oh, this issue looks like bpo-35045 which has been fixed.