classification
Title: test_min_max_version in test_ssl.py fails when Python is built against LibreSSL; {min,max}imum_version behavior differs from OpenSSL
Type: behavior Stage: resolved
Components: SSL, Tests Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: duplicate
Dependencies: Superseder: test_min_max_version (test.test_ssl.ContextTests) fails on Fedora 29+ and openssl 1.1.1
View: 35045
Assigned To: docs@python Nosy List: Alan.Huang, alex, christian.heimes, docs@python, dstufft, janssen, vstinner
Priority: normal Keywords: patch

Created on 2018-06-29 05:32 by Alan.Huang, last changed 2019-01-18 15:21 by vstinner. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 8050 closed Alan.Huang, 2018-07-02 14:51
Messages (3)
msg320703 - (view) Author: Alan Huang (Alan.Huang) * Date: 2018-06-29 05:32
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`.

1. Skip `test_min_max_version`.
2. 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_SUPPORTED
AssertionError: <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.
msg320890 - (view) Author: Alan Huang (Alan.Huang) * Date: 2018-07-02 15:10
PR 8050 implements option 2a (use PY_PROTO_{MIN,MAX}IMUM_AVAILABLE).
msg333977 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-01-18 15:21
Oh, this issue looks like bpo-35045 which has been fixed.
History
Date User Action Args
2019-01-18 15:21:55vstinnersetstatus: open -> closed

superseder: test_min_max_version (test.test_ssl.ContextTests) fails on Fedora 29+ and openssl 1.1.1

nosy: + vstinner
messages: + msg333977
resolution: duplicate
stage: patch review -> resolved
2018-07-02 15:10:31Alan.Huangsetmessages: + msg320890
2018-07-02 14:51:00Alan.Huangsetkeywords: + patch
stage: patch review
pull_requests: + pull_request7658
2018-07-01 22:23:04Alan.Huangsetcomponents: - Documentation
versions: + Python 3.8
2018-06-29 05:32:25Alan.Huangcreate