OpenSSL TLS 1.1 handshake fails internal error

Bug #1917625 reported by Christian Heimes
16
This bug affects 3 people
Affects Status Importance Assigned to Milestone
openssl (Ubuntu)
Incomplete
Undecided
Unassigned
Hirsute
Confirmed
Undecided
Unassigned

Bug Description

OpenSSL's SSL_do_handshake() method fails with TLSV1_ALERT_INTERNAL_ERROR when client side has TLS 1.0 to 1.2 enabled but server side has only TLS 1.0 and 1.1 enabled. The issue breaks Python's test suite for test_ssl. It looks like the problem is caused by an Ubuntu downstream patch. Vanilla OpenSSL, Debian, and Fedora are not affected.

A simple reproducer is:

import ssl
import socket
from test.test_ssl import testing_context, ThreadedEchoServer, HOST

client_context, server_context, hostname = testing_context()
# client 1.0 to 1.2, server 1.0 to 1.1
client_context.minimum_version = ssl.TLSVersion.TLSv1
client_context.maximum_version = ssl.TLSVersion.TLSv1_2
server_context.minimum_version = ssl.TLSVersion.TLSv1
server_context.maximum_version = ssl.TLSVersion.TLSv1_1

with ThreadedEchoServer(context=server_context) as server:
    with client_context.wrap_socket(socket.socket(),
                                    server_hostname=hostname) as s:
        s.connect((HOST, server.port))
        assert s.version() == 'TLSv1.1'

On Ubuntu 20.04 the code fails with:
Traceback (most recent call last):
  File "/internalerror.py", line 15, in <module>
    s.connect((HOST, server.port))
  File "/usr/lib/python3.8/ssl.py", line 1342, in connect
    self._real_connect(addr, False)
  File "/usr/lib/python3.8/ssl.py", line 1333, in _real_connect
    self.do_handshake()
  File "/usr/lib/python3.8/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: TLSV1_ALERT_INTERNAL_ERROR] tlsv1 alert internal error (_ssl.c:1123)

On Debian testing and Fedora 33 the same test passes with out:
 server: new connection from ('127.0.0.1', 52346)
 server: connection cipher is now ('ECDHE-RSA-AES256-SHA', 'TLSv1.0', 256)
 server: selected protocol is now None

You can find Dockerfiles with reproducers at https://github.com/tiran/distro-truststore/tree/main/tests/ubuntu-1899878

Also see:
* https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/1899878
* https://bugs.python.org/issue43382
* https://bugs.python.org/issue41561

Tags: focal fr-1204
Revision history for this message
Launchpad Janitor (janitor) wrote :

Status changed to 'Confirmed' because the bug affects multiple users.

Changed in openssl (Ubuntu):
status: New → Confirmed
tags: added: focal rls-ff-incoming
tags: added: fr-1204
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

I need to verify a few things, but I believe it is to do with chiphersuites, seclevel callback, and protocol versions.

When setting chiphersuite string ; or changing security level; or changing the security level callback; or setting min/mas protocol versions. All of those things are not checked against each other to ensure that as whole they are compatible with each.

Then at connection establishment time things are verified and security callback is called and things go "you request max version y, but security hook rejects things at y, no connection for you".

This does brings the existential/API question similar to the previous bug report. It is not known over the API that security level is 2 and that it rejects protocol versions.

I wonder, if setting min_version / max_version, that would be rejected by the current security level, if security level should be adjusted appropriately automatically. I.e. when trying to set min protocol version to TLS1.1 and the security level is at 2, if security level should be updated to 1 automatically. Or not.

tags: removed: rls-ff-incoming
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Please note that:

OpenSSL upstream security level 3 only allows TLS v1.1 and above
OpenSSL upstream security level 4 only allows TLS v1.2 and above, DTLS v1.2 and above

On Ubuntu, these restrictions are brought in earlier at security level 2.

Thus, if one builds upstream OpenSSL with security level set to 4 all of the above testsuite should be failing as well.

I feel there is lack of API documentation about this in OpenSSL.

Also, Python tests are incomplete and are not testing for, or setting appropriate security levels for the protocols they are attempting to use. Thus are not using the OpenSSL api correctly and making assumptions about the openssl library that are out of date with current standards and requirements.

Revision history for this message
Christian Heimes (heimes) wrote :

I didn't include a setter for security level on purpose, https://bugs.python.org/issue41195 . Most recent Python version only has a getter to query security level. I strongly believe that user application should not modify security level. Security level and TLS versions should be centrally managed by system administrators. Unfortunately Python's ssl module still has legacy support for TLS 1.0 and 1.1.

Even a check for seclevel == 2 or modification of the security level wouldn't address Python's test failures on Ubuntu. After all Ubuntu uses a custom policy that deviates from the seclevel 2 definition
at https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_get_security_level.html

Do you suggest that Python should check for Ubuntu in the test suite, so we can special case Ubuntu's custom policy?

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

I feel that openssl upstream needs to add:

server_context.verify_consistent()

Because in the above example, even before trying to establish the connection between the two context, the server context is already internally inconsistent.

And upstream has changed the meaning of security levels in the past, and will do so again in the future. Ditto distro customization which brought the preview of such change earlier.

It does feel that until such API arrives upstream, one needs to do something to the effect of:

1) if openssl version 3.x, and security level is greater than 0, assume no TLS1.1 is available
2) if openssl version 1.1.1+, and security level is greater than 1, assume no TLS1.1 is available
3) if ctx.get_min_proto_level returns TLS1.2 assume no TLS1.1 is available
4) else try setting min_proto_level and run tests
5) if min_proto_lvel is not available the build is against openssl 1.0.2x series, TLS1.1 is probably available.

Above logic should cover the next upstream openssl version; the current deployments of ubuntu derivatives; the debian derivatives; and fedora/rhel derivatives.

I think....

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

ideally it would be nice if we could access sec_cb and call it with the protocol versions to check the versions there.

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Oooh,

can we add bindings for:

s->cert->sec_cb() and then call it with SSL_SECOP_VERSION operation with nbits set to TLS1.1 version? then it will return and tell us if it is acceptable or not, by the security level.

Revision history for this message
Christian Heimes (heimes) wrote :

> I feel that openssl upstream needs to add: server_context.verify_consistent()

Yeah, I agree with you. :) The idea came up three years ago when I filed issue https://github.com/openssl/openssl/issues/5127

> 1) if openssl version 3.x, and security level is greater than 0, assume no TLS1.1 is available

Thank you, I'll consider this fact when I implement OpenSSL 3.0.0 support

> 2) if openssl version 1.1.1+, and security level is greater than 1, assume no TLS1.1 is available

TLS 1.1 connections work fine on seclevel 2 with default upstream OpenSSL 1.1.1 and with Fedora's OpenSSL 1.1.1 using crypto-policy "DEFAULT". I'm using

    server_context.set_ciphers("@SECLEVEL=2:ALL")

to change the security level. Here Ubuntu deviates from standard OpenSSL 1.1.1 policies. So I ask again: Should we detect and special case the deviation and document it?

> 3) if ctx.get_min_proto_level returns TLS1.2 assume no TLS1.1 is available

That's the original problem, https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/1899878 . On Ubuntu SSL_CTX_get_min_proto_version() returns 0 (lowest available version) and TLS1_VERSION is available.

> 4) else try setting min_proto_level and run tests

The setter SSL_CTX_set_min_proto_version() does not return an error indication.

Revision history for this message
Christian Heimes (heimes) wrote :

> s->cert->sec_cb() and then call it with SSL_SECOP_VERSION operation with nbits set to TLS1.1 version? then it will return and tell us if it is acceptable or not, by the security level.

Nice!
Could you hook up the check to SSL_CTX_set_min_proto_version() and return an error code when level and security policy don't match? It's a modern setter, so it can return 0 on error.

    int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version);

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

> Could you hook up the check to SSL_CTX_set_min_proto_version() and return an error code when level and security policy don't match? It's a modern setter, so it can return 0 on error.

That is interesting proposal.

However, need to be careful as to potentially not break configs, i.e. if they specify min_protocol_level first, then lower the security level.

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

> to change the security level. Here Ubuntu deviates from standard OpenSSL 1.1.1 policies. So I ask again: Should we detect and special case the deviation and document it?

I am reluctant to say yes here. But also want to ask how would you detect that it's an Ubuntu, or ubuntu derived openssl. I don't think we export anything in openssl APIs to be definitive about it.

Revision history for this message
Dimitri John Ledkov (xnox) wrote :
Revision history for this message
Adrien Nader (adrien-n) wrote :

Hi Christian, I'd like to move forward with this ticket and I think that will mean closing it. But first, have things changed on your side?

Also, like Dimitri I am reluctant to commit there but I don't see things changing until the next openssl LTS release as I've said in https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/1899878/comments/21 . I haven't spotted an easy way to detect the system is Ubuntu (and which version) but maybe you can do that at python configure-time if it's needed.

Adrien Nader (adrien-n)
Changed in openssl (Ubuntu):
status: Confirmed → Incomplete
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.