New submission from Alan Huang <alan.hu...@utdallas.edu>:

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.

----------
assignee: docs@python
components: Documentation, SSL, Tests
messages: 320703
nosy: Alan.Huang, alex, christian.heimes, docs@python, dstufft, janssen
priority: normal
severity: normal
status: open
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
versions: Python 3.7

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue33995>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to