classification
Title: Disabling SSLv3 support
Type: compile error Stage: resolved
Components: Build Versions: Python 3.5, Python 3.4, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: alex, benjamin.peterson, christian.heimes, doko, dstufft, giampaolo.rodola, haypo, janssen, kroeckx, larry, lemburg, ned.deily, pitrou, python-dev
Priority: release blocker Keywords: patch

Created on 2014-11-24 22:14 by kroeckx, last changed 2015-01-06 15:03 by berker.peksag. This issue is now closed.

Files
File name Uploaded Description Edit
python2.7-nossl3.patch kroeckx, 2014-11-24 22:14
get_server_certificate_sslv3.patch haypo, 2014-12-12 11:31 review
get_server_certificate_sslv23.patch haypo, 2014-12-12 11:56 review
Messages (30)
msg231624 - (view) Author: Kurt Roeckx (kroeckx) * Date: 2014-11-24 22:14
Hi,

The attached patch makes python work when openssl doesn't have SSLv3 support.  It also updates the documentation, which has already improved a lot since my original patch.

The current upstream openssl when compiled with no-ssl2 it defines OPENSSL_NO_SSL2, drops the SSLv2_* method and drops support for SSLv2 in the SSLv23_* methods.  When build with no-ssl3 it defines OPENSSL_NO_SSL3 and currently just drops supports for SSLv3 in the SSLv23_method, it does not yet drop the SSLv3_* methods.  It's still being argued whether no-ssl3 should drop those symbols or that a new option will be used instead.

So that means that with OPENSSL_NO_SSL3 defined it could be that the SSLv3_* methods still exist and that you can create a socket that only support SSLv3.

I made the SSLv3 methods go away in python if OPENSSL_NO_SSL3 is defined.  This at least makes things easier for the test suite so that you know you can test a combination like v3 with v23 or not.

This patch is for 2.7.  Please let me know if you need a patch for a different version.
msg231625 - (view) Author: Alex Gaynor (alex) * (Python committer) Date: 2014-11-24 22:15
FWIW, Debian expiremental appears to be using a different #define for this. Here's how we handled it in pyca/cryptography: https://github.com/pyca/cryptography/commit/04a3f1f2c4086c0d7162b6dd79b6332d9115b2c0
msg231626 - (view) Author: Kurt Roeckx (kroeckx) * Date: 2014-11-24 22:20
I know what I uploaded to Debian experimental.  And I can't promise that I'll keep that define.  I suggest you assume that NO_SSL3 will disable both.
msg231627 - (view) Author: Alex Gaynor (alex) * (Python committer) Date: 2014-11-24 22:21
Good to know, thanks.
msg231813 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2014-11-28 13:32
FYI LibreSSL also disabled SSLv2 and SSLv3.
msg231815 - (view) Author: Matthias Klose (doko) * (Python committer) Date: 2014-11-28 13:39
maybe it's time to generalise this one, still found on all branches:

# Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2
def skip_if_broken_ubuntu_ssl(func):
msg231911 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2014-11-30 23:31
Clearly we need to support openssl's without SSLv3 so I think some version of this needs to be applied to all branches (preferably in time for 2.7.9, Benjamin?).  Kurt, if you haven't already, could you sign the contributor agreement so we can use the patch (https://www.python.org/psf/contrib/contrib-form/)?  And I guess it would be nice to generalize the SSLv2 checks as doko suggests.
msg231942 - (view) Author: Kurt Roeckx (kroeckx) * Date: 2014-12-01 15:54
I've just signed the contributor agreement
msg232236 - (view) Author: Roundup Robot (python-dev) Date: 2014-12-06 03:11
New changeset 49d267a58cc2 by Benjamin Peterson in branch '2.7':
allow ssl module to compile if openssl doesn't support SSL 3 (closes #22935)
https://hg.python.org/cpython/rev/49d267a58cc2

New changeset 4077e0cd8d48 by Benjamin Peterson in branch '3.4':
allow ssl module to compile if openssl doesn't support SSL 3 (closes #22935)
https://hg.python.org/cpython/rev/4077e0cd8d48

New changeset fbf3747e721c by Benjamin Peterson in branch 'default':
merge 3.4 (#22935)
https://hg.python.org/cpython/rev/fbf3747e721c
msg232238 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2014-12-06 08:48
The documentation should be modified to explain that SSLv2 and SSLv3 are
not always available.
msg232315 - (view) Author: Kurt Roeckx (kroeckx) * Date: 2014-12-08 16:45
I did update the documentation to mention that, but it seems none of my documentation changes got applied.
msg232522 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2014-12-12 09:44
The changes for 3.4 are incomplete:  

>>> import ssl
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/py/dev/34/source/Lib/ssl.py", line 122, in <module>
    from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1
ImportError: cannot import name 'PROTOCOL_SSLv3'

For the default (3.5) branch, f776771ab0ee for Issue21068 changed ssl.py to handle missing SSLv3 support; 3.4 needs something similar.
msg232525 - (view) Author: Roundup Robot (python-dev) Date: 2014-12-12 11:25
New changeset 773e55c95703 by Victor Stinner in branch '3.4':
Issue #22935: Fix ssl module when SSLv3 protocol is not supported
https://hg.python.org/cpython/rev/773e55c95703

New changeset fb1ffd40d33e by Victor Stinner in branch 'default':
Issue #22935: Fix test_ssl when the SSLv3 protocol is not supported
https://hg.python.org/cpython/rev/fb1ffd40d33e
msg232526 - (view) Author: Roundup Robot (python-dev) Date: 2014-12-12 11:28
New changeset f0297263a1e8 by Victor Stinner in branch '3.4':
Issue #22935: Fix test_ssl when the SSLv3 protocol is not supported
https://hg.python.org/cpython/rev/f0297263a1e8
msg232527 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2014-12-12 11:31
> The changes for 3.4 are incomplete

Ok, I fixed most obvious issues. There is a major severe issue in Lib/ssl.py:

    def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None):
        ...


This line fails if PROTOCOL_SSLv3 name does not exist. I propose to use PROTOCOL_SSLv23 by default if PROTOCOL_SSLv3 does not exist, as done in Python 3.5. See attached patch.

A better option (more secure?) is to use PROTOCOL_SSLv23 by default.

What do you think? I prefer to switch to PROTOCOL_SSLv23 by default in Python 3.4.
msg232528 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2014-12-12 11:35
Oh, in Python 3.4, create_default_context() uses PROTOCOL_SSLv23, SSLSocket, wrap_socket() and _create_unverified_context() use PROTOCOL_SSLv23 by default.

In Python 3.5, get_server_certificate() now uses PROTOCOL_SSLv23 by default because test_ssl failed on the host svn.python.org: see issue #20896.

changeset:   90360:55f62fa5bebc
user:        Antoine Pitrou <solipsis@pitrou.net>
date:        Wed Apr 16 18:56:28 2014 +0200
files:       Doc/library/ssl.rst Lib/ssl.py Lib/test/test_ssl.py Misc/NEWS
description:
Issue #20896: ssl.get_server_certificate() now uses PROTOCOL_SSLv23, not PROTOCOL_SSLv3, for maximum compatibility.
msg232530 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2014-12-12 11:56
get_server_certificate_sslv23.patch: Patch to use PROTOCOL_SSLv23 by default in get_server_certificate(), as done in Python 2.7 and 3.5.
msg232542 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2014-12-12 12:47
Please always use PROTOCOL_SSLv23 since this is the only forward compatible way of telling OpenSSL to use the best protocol available.

Any of the other options such as PROTOCOL_TLSv1 will fix the protocol version to that one protocol version, whereas PROTOCOL_SSLv23 means to use any protocol starting with SSLv2. In the context options you can then disable SSLv2 and SSLv3 to e.g. have the connection use TLS 1.0 or later.
msg232543 - (view) Author: Kurt Roeckx (kroeckx) * Date: 2014-12-12 13:08
So this seems to be a function that just gets the certificate?  You need to be careful with this since a server could perfectly decide to send a different certificate depending on the client hello it receives.  Like if you support ECDSA it might decide to send you the ECDSA certificate instead of the RSA certificate.  Or maybe you're even connecting to a different IP address?

In any case, you should always use SSLv23, stop supporting anything else.
msg232545 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2014-12-12 13:16
> So this seems to be a function that just gets the certificate?  You need to be careful with this since a server could perfectly decide to send a different certificate depending on the client hello it receives. (...) In any case, you should always use SSLv23, stop supporting anything else.

I don't understand. You say that depending on the protocol, you may get a different certificate, and then that we should stop supporting multiple protocol. Does it mean that you ask to remove a Python feature?

Even if it is technically possible to return a different certificate, I don't think that much servers will return a different certificate if the client uses SSLv23 instead of SSLv3.
msg232546 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2014-12-12 13:23
> Any of the other options such as PROTOCOL_TLSv1 will fix the protocol version to that one protocol version, whereas PROTOCOL_SSLv23 means to use any protocol starting with SSLv2. In the context options you can then disable SSLv2 and SSLv3 to e.g. have the connection use TLS 1.0 or later.

get_server_certificate() uses _create_unverified_context() (In Python
2.7, 3.4 & 3.5) which explicitly disable SSLv2 and SSLv3. I still have
trouble to understand which protocol will be negociated. We use SSLv3
and disable SSLv3, so the server can only use SSLv23. Am I right?
https://docs.python.org/dev/library/ssl.html#ssl.wrap_socket
msg232547 - (view) Author: Kurt Roeckx (kroeckx) * Date: 2014-12-12 13:28
SSLv3 does not support the TLS extensions so it's going to send a totally different Client Hello.  It will for instance not indicate with elliptic curves it supports.  So yes the behavior for SSLv3 and SSLv23 can be totally different.  But even with both SSLv23 and a different cipher list you can get a different certificate.

So what I'm really saying is that if you have an API to get a certificate that creates a new connection and you can set the options for that connection too that you need to document that properly that you might get a different certificate.
msg232548 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2014-12-12 13:30
Do you have an example of server returning a different certificate depending on the protocol?
msg232551 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2014-12-12 14:48
> STINNER Victor added the comment:
> 
>> Any of the other options such as PROTOCOL_TLSv1 will fix the protocol version to that one protocol version, whereas PROTOCOL_SSLv23 means to use any protocol starting with SSLv2. In the context options you can then disable SSLv2 and SSLv3 to e.g. have the connection use TLS 1.0 or later.
> 
> get_server_certificate() uses _create_unverified_context() (In Python
> 2.7, 3.4 & 3.5) which explicitly disable SSLv2 and SSLv3. I still have
> trouble to understand which protocol will be negociated. We use SSLv3
> and disable SSLv3, so the server can only use SSLv23. Am I right?
> https://docs.python.org/dev/library/ssl.html#ssl.wrap_socket

I'm not sure what OpenSSL will do if you tell it to use protocol
SSLv3 and then disable this via the options again. This sounds like
it won't connect at all, since PROTOCOL_SSLv3 means: only support
SSLv3 :-)

The logic used for protocol selection in OpenSSL is, well, weird.
You have the choice between fixing one single protocol version or
selecting a range and then disabling certain protocol versions
when configuring the context options.

FWIW: The ssl_version parameter in _create_unverified_context()
already uses the correct default; IMO, exposing the parameter
in get_server_certificate() is fairly useless, unless you want
to (ab)use the function to test supported protocol versions :-)
msg232552 - (view) Author: Kurt Roeckx (kroeckx) * Date: 2014-12-12 14:53
Most such sites actually seem to have dropped support for SSLv3.

One site where it depends on the cipher string is bugs.cdburnerxp.se
msg233447 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2015-01-05 08:49
Setting to release blocker since this needs to be resolved for 3.4.3.  FYI, the OS X x86 Tiger 3.4 buildbot has been updated to use a local copy of OpenSSL 1.0.1j with SSLv3 disabled and multiple tests now fail (2.7 and default do not fail, as expected).

http://buildbot.python.org/all/builders/x86%20Tiger%203.4
msg233448 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-01-05 08:51
I'm going to commit get_server_certificate_sslv23.patch into Python 3.4, so Python 3.4 will just behave like Python 2.7 and 3.5, except if someone complains :-)
msg233522 - (view) Author: Roundup Robot (python-dev) Date: 2015-01-06 11:24
New changeset a8c4925e2359 by Victor Stinner in branch '3.4':
Issue #20896, #22935: The ssl.get_server_certificate() function now uses the
https://hg.python.org/cpython/rev/a8c4925e2359
msg233523 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-01-06 11:24
Ok, I commited my change to Python 3.4. I'm now waiting for the following buildbot before closing the issue:
http://buildbot.python.org/all/builders/x86%20Tiger%203.4
msg233533 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-01-06 12:41
> I'm now waiting for the following buildbot before closing the issue:
> http://buildbot.python.org/all/builders/x86%20Tiger%203.4

Before my change, test_ssl because with "NameError: name 'PROTOCOL_SSLv3' is not defined". With my change, test_ssl now pass. I close the issue.

Python 2.7, 3.4 and 3.5 all now have the same behaviour.
History
Date User Action Args
2015-01-06 15:03:50berker.peksagsetstage: needs patch -> resolved
2015-01-06 12:41:26hayposetstatus: open -> closed
resolution: fixed
messages: + msg233533
2015-01-06 11:24:59hayposetmessages: + msg233523
2015-01-06 11:24:05python-devsetmessages: + msg233522
2015-01-05 08:51:37hayposetmessages: + msg233448
2015-01-05 08:49:20ned.deilysetpriority: high -> release blocker
nosy: + larry
messages: + msg233447

2014-12-12 14:53:07kroeckxsetmessages: + msg232552
2014-12-12 14:48:03lemburgsetmessages: + msg232551
2014-12-12 13:30:17hayposetmessages: + msg232548
2014-12-12 13:28:54kroeckxsetmessages: + msg232547
2014-12-12 13:23:26hayposetmessages: + msg232546
2014-12-12 13:16:39hayposetmessages: + msg232545
2014-12-12 13:08:01kroeckxsetmessages: + msg232543
2014-12-12 12:47:55lemburgsetnosy: + lemburg
messages: + msg232542
2014-12-12 11:56:20hayposetfiles: + get_server_certificate_sslv23.patch

messages: + msg232530
2014-12-12 11:35:39hayposetmessages: + msg232528
2014-12-12 11:31:40hayposetfiles: + get_server_certificate_sslv3.patch

messages: + msg232527
2014-12-12 11:28:04python-devsetmessages: + msg232526
2014-12-12 11:25:49python-devsetmessages: + msg232525
2014-12-12 09:44:34ned.deilysetstatus: closed -> open
resolution: fixed -> (no value)
messages: + msg232522

stage: resolved -> needs patch
2014-12-08 16:45:28kroeckxsetmessages: + msg232315
2014-12-06 08:48:47hayposetmessages: + msg232238
2014-12-06 03:11:46python-devsetstatus: open -> closed

nosy: + python-dev
messages: + msg232236

resolution: fixed
stage: patch review -> resolved
2014-12-01 15:54:58kroeckxsetmessages: + msg231942
2014-11-30 23:31:22ned.deilysetpriority: normal -> high

nosy: + benjamin.peterson, ned.deily
messages: + msg231911

components: + Build
2014-11-28 13:39:53dokosetnosy: + doko
messages: + msg231815
2014-11-28 13:32:13hayposetnosy: + haypo
messages: + msg231813
2014-11-24 22:37:25pitrousetstage: patch review
type: compile error
versions: + Python 2.7, Python 3.4, Python 3.5
2014-11-24 22:21:37alexsetmessages: + msg231627
2014-11-24 22:20:47kroeckxsetmessages: + msg231626
2014-11-24 22:15:46alexsetnosy: + janssen, pitrou, giampaolo.rodola, christian.heimes, alex, dstufft
messages: + msg231625
2014-11-24 22:14:20kroeckxcreate