Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Behavior change: v2.x raises SSLEOFError with Python3.10 where v2.x does not with Python3.8 #3100

Open
b-morgenthaler opened this issue Aug 1, 2023 · 20 comments · May be fixed by #3107
Open

Comments

@b-morgenthaler
Copy link

b-morgenthaler commented Aug 1, 2023

Subject

Setup: Using robotframework-requests library which in turn utilizes requests library to issue GET requests to a non-public web server over https. The web server is third-party.
The GET requests work fine using Python3.8, openssl [1.1.1f|3.0.2] and urllib3 2.x
The GET requests, however, raise following error when using the same context with only Python changed to 3.10:

SSLError: HTTPSConnectionPool(host='10.1.1.32', port=443): Max retries exceeded with url: /netio.json (Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1007)')))

Environment

Reproduced on Ubuntu 20.04 LTS and 22.04 LTS (openssl 1.1.1f and openssl 3.0.2)

Combination of libs that raise the error (Ubuntu 22.04 LTS):

OS Linux-5.4.0-131-generic-x86_64-with-glibc2.35
Python 3.10.12
OpenSSL 3.0.2 15 Mar 2022
urllib3 2.0.4

Combination of libs that do not raise the error (Ubuntu 22.04 LTS):

OS Linux-5.4.0-131-generic-x86_64-with-glibc2.35
Python 3.10.12
OpenSSL 3.0.2 15 Mar 2022
urllib3 1.26.15

Difference between the two combinations:
pip install --upgrade --force-reinstall urllib3==1.26.15

Combination of libs that do not raise the error as well (Ubuntu 20.04 LTS):

OS Linux-5.4.0-131-generic-x86_64-with-glibc2.29
Python 3.8.10
OpenSSL 1.1.1f  31 Mar 2020
urllib3 2.0.4

Steps to Reproduce

It's hard to reproduce publicly because the web server is not public.
But my findings lead to the SSL_OP_IGNORE_UNEXPECTED_EOF flag.

Expected Behavior

v2.x shall behave the same way with Python 3.10 as it does with Python 3.8 regarding the error described above (i. e. not raising any SSLEOFError)

Actual Behavior

v2.x in combination with Python 3.10 raises SSLEOFError
v2.x in combination with Python 3.8 does not raise SSLEOFError

@b-morgenthaler
Copy link
Author

maybe related to SSLEOFError in Python 3.10 not in Python 3.9

@pquentin
Copy link
Member

pquentin commented Aug 4, 2023

I knew that newer Python versions had issues with OpenSSL 3.0, but I'm surprised that just upgrading urllib3 to 2.0 makes a difference. I won't be able to help much without being able to reproduce, however.

Is there any chance that you could capture a pcap file using Wireshark?

@b-morgenthaler
Copy link
Author

I was trying to find a public server where I could reproduce the issue but had no luck.
Going to see if I can set up wireshark to capture traffic (it's a bit tricky since everything is executed within Docker containers from a sand-boxed network)

@b-morgenthaler
Copy link
Author

I used tcpdump to capture pcap files directly from within the Docker container which is connecting to the web server. Hope this helps identifying the difference.

  • Working context: Ubuntu 20.04 LTS

OS Linux-5.4.0-131-generic-x86_64-with-glibc2.29
Python 3.10.12
OpenSSL 1.1.1f 31 Mar 2020
urllib3 1.25.8

  • Non working context: no change to working context except pip install --upgrade --force-reinstall urllib3==2.0.0

For reference/comparison: working py38 urllib2 context

OS Linux-5.4.0-131-generic-x86_64-with-glibc2.29
Python 3.8.10
OpenSSL 1.1.1f 31 Mar 2020
urllib3 2.0.0

pcap.zip

@pquentin
Copy link
Member

pquentin commented Aug 8, 2023

Thanks! This is great. I still need to analyze things more to understand the EOF error, but the server is using the TLS_RSA_WITH_AES_256_CBC_SHA256 cipher suite (named AES256-SHA256 by OpenSSL) which is not in the OpenSSL default suite that we use in 2.0 (see #3060 (comment) for details). Can you please try the following script to see if things improve?

import ssl

from urllib3 import PoolManager
from urllib3.util import create_urllib3_context

ctx = create_urllib3_context()
ctx.load_default_certs()
ctx.set_ciphers("AES256-SHA256")

with PoolManager(ssl_context=ctx) as pool:
    pool.request("GET", "https://.../", retries=0)

Also, would you mind sharing a full trackeback instead of just the exception?

@b-morgenthaler
Copy link
Author

b-morgenthaler commented Aug 8, 2023

A little bit of background: the server is similar to this demo from its manufacturer: http://netio-4c.netio-products.com/
In our specific case, I am automating its JSON endpoint via SSL (self-signed). Could it be possible that the server is using the particular cipher suite because I chose to create the self-signed certificate as RSA SHA256?

I had to modify your script a bit because of the self-signed certificate (see below) but other than that, it is working. Unfortunately, I cannot control how my "frontend" (aka robotframework-requests) is utilizing Python's requests library which is utilizing urllib3 to make requests. I can only control whether to verify certificates (which I don't) and to ignore warnings.

import ssl

from urllib3 import PoolManager
from urllib3.util import create_urllib3_context
from urllib3 import ssl
from urllib3 import make_headers

ctx = create_urllib3_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ctx.load_default_certs()
ctx.set_ciphers("AES256-SHA256")

type = {'Content-Type': 'application/json'}
auth = make_headers(basic_auth=f'read:[read password]')
headers = { **type, **auth }

with PoolManager(ssl_context=ctx) as pool:
    resp = pool.request("GET", "https://[IP]/netio.json", retries=0, headers=headers)
    print(resp.data)

EDIT (another experiment):
When I comment out the ctx.set_ciphers("AES256-SHA256") line, I think I see the same error as with my original automation suite:

root@595a566742be:/# python3 test.py
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 467, in _make_request
    self._validate_conn(conn)
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 1092, in _validate_conn
    conn.connect()
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connection.py", line 635, in connect
    sock_and_verified = _ssl_wrap_socket_and_match_hostname(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connection.py", line 774, in _ssl_wrap_socket_and_match_hostname
    ssl_sock = ssl_wrap_socket(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/util/ssl_.py", line 459, in ssl_wrap_socket
    ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
  File "/usr/local/lib/python3.10/dist-packages/urllib3/util/ssl_.py", line 503, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
  File "/usr/lib/python3.10/ssl.py", line 513, in wrap_socket
    return self.sslsocket_class._create(
  File "/usr/lib/python3.10/ssl.py", line 1071, in _create
    self.do_handshake()
  File "/usr/lib/python3.10/ssl.py", line 1342, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:1007)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 790, in urlopen
    response = self._make_request(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 491, in _make_request
    raise new_e
urllib3.exceptions.SSLError: EOF occurred in violation of protocol (_ssl.c:1007)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "//test.py", line 19, in <module>
    resp = pool.request("GET", "https://[IP]/netio.json", retries=0, headers=headers)
  File "/usr/local/lib/python3.10/dist-packages/urllib3/_request_methods.py", line 110, in request
    return self.request_encode_url(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/_request_methods.py", line 143, in request_encode_url
    return self.urlopen(method, url, **extra_kw)
  File "/usr/local/lib/python3.10/dist-packages/urllib3/poolmanager.py", line 433, in urlopen
    response = conn.urlopen(method, u.request_uri, **kw)
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 844, in urlopen
    retries = retries.increment(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/util/retry.py", line 515, in increment
    raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='[IP]', port=443): Max retries exceeded with url: /netio.json (Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1007)')))

But when I execute the script that throws the exception above (with the commented line regarding the additional cipher) with Python 3.8 instead of Python 3.10, there's no exception and the script works.

EDIT again: here's the traceback from the original issue:

20230808 10:29:26.834 - FAIL - SSLError: HTTPSConnectionPool(host='10.1.1.32', port=443): Max retries exceeded with url: /netio.json (Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1007)')))
20230808 10:29:26.836 - DEBUG - Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 467, in _make_request
    self._validate_conn(conn)
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 1092, in _validate_conn
    conn.connect()
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connection.py", line 635, in connect
    sock_and_verified = _ssl_wrap_socket_and_match_hostname(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connection.py", line 774, in _ssl_wrap_socket_and_match_hostname
    ssl_sock = ssl_wrap_socket(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/util/ssl_.py", line 459, in ssl_wrap_socket
    ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
  File "/usr/local/lib/python3.10/dist-packages/urllib3/util/ssl_.py", line 503, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
  File "/usr/lib/python3.10/ssl.py", line 513, in wrap_socket
    return self.sslsocket_class._create(
  File "/usr/lib/python3.10/ssl.py", line 1071, in _create
    self.do_handshake()
  File "/usr/lib/python3.10/ssl.py", line 1342, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:1007)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 790, in urlopen
    response = self._make_request(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 491, in _make_request
    raise new_e
urllib3.exceptions.SSLError: EOF occurred in violation of protocol (_ssl.c:1007)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/requests/adapters.py", line 439, in send
    resp = conn.urlopen(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 874, in urlopen
    return self.urlopen(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 874, in urlopen
    return self.urlopen(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 874, in urlopen
    return self.urlopen(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 844, in urlopen
    retries = retries.increment(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/util/retry.py", line 515, in increment
    raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='10.1.1.32', port=443): Max retries exceeded with url: /netio.json (Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1007)')))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/RequestsLibrary/utils.py", line 154, in decorator
    return func(*args, **kwargs)
  File "/usr/local/lib/python3.10/dist-packages/RequestsLibrary/RequestsOnSessionKeywords.py", line 31, in get_on_session
    response = self._common_request("get", session, url,
  File "/usr/local/lib/python3.10/dist-packages/RequestsLibrary/RequestsKeywords.py", line 37, in _common_request
    resp = method_function(
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 548, in get
    return self.request('GET', url, **kwargs)
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 535, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 648, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python3/dist-packages/requests/adapters.py", line 514, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='10.1.1.32', port=443): Max retries exceeded with url: /netio.json (Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1007)')))

@sigmavirus24
Copy link
Contributor

A little bit of background: the server is similar to this demo from its manufacturer: http://netio-4c.netio-products.com/
Could it be possible that the server is using the particular cipher suite because I chose to create the self-signed certificate as RSA SHA256?

No. The key used for a certificate is orthogonal to the cipher suites supported by the server for TLS.

I would also expect any product you purchase to allow you to customize the supported cipher suites so that you could fix this there.

@b-morgenthaler
Copy link
Author

Thanks for the clarification @sigmavirus24

I would also expect any product you purchase to allow you to customize the supported cipher suites so that you could fix this there.

Unfortunately, this is out of scope for the product used. The only configuration that is available, is to enable/disable https (including custom ports) and an upload for a custom certificate incl. its private key.

Is the cipher AES256-SHA256 uncommon/weak/deprecated?

Nevertheless, with Python 3.8 urllib3v2 behaves differently than with Python 3.10 which is something that should be at least understood (if it's acceptable or not). My work-around currently is not using urllib3v2 at all.

@pquentin
Copy link
Member

pquentin commented Aug 8, 2023

Yes, we mentioned in the release notes that we would now be using the OpenSSL default cipher suite instead of the custom list in 1.26.x: see #2082. If you squint a bit, this is similar to a good cryptography practice: https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number. What was surprising here is that you did not report an SSL handshake error, but an SSLEOFError. (Which is why I'd like to see the full traceback.)

That said, you're the fourth user reporting us an issue with the OpenSSL cipher suite, so we will likely need to reevaluate it and add more ciphers to it. Other reports include:

@b-morgenthaler
Copy link
Author

@pquentin

What was surprising here is that you did not report an SSL handshake error, but an SSLEOFError. (Which is why I'd like to see the full traceback.)

Do you need more than the traceback I provided a few comments back?

@pquentin
Copy link
Member

pquentin commented Aug 8, 2023

I had indeed missed the edit, thanks this is what I needed! I'll tell you if I need more things as this exercise is very valuable.

@b-morgenthaler
Copy link
Author

My bad. I didn't want to spread the traces throughout the thread, so I edit'ed several times...

@pquentin
Copy link
Member

pquentin commented Aug 9, 2023

Is the cipher AES256-SHA256 uncommon/weak/deprecated?

Yes, it is weak because RSA does not support PFS and CBC mode is vulnerable to plaintext attacks. See https://ciphersuite.info/cs/TLS_RSA_WITH_AES_256_CBC_SHA256/ for more explanations. But it's included by default on Ubuntu or Fedora, so your operating system seems to be configured differently.

Indeed, when I make requests from my Fedora laptop, this cipher is included. And looking at https://ubuntu.com/server/docs/openssl, running openssl ciphers -s -v DEFAULT:@SECLEVEL=2 confirms that Ubuntu includes it too:

AES256-SHA256                  TLSv1.2 Kx=RSA      Au=RSA   Enc=AES(256)               Mac=SHA256

How is your OpenSSL configured? It seems to be stricter than that, and you'll need to fix it.

What was surprising here is that you did not report an SSL handshake error, but an SSLEOFError. (Which is why I'd like to see the full traceback.)

Looking more closely at the packet capture with Wireshark, I now understand why you got SSLEOFError. Looking at the relevant packets for one attempt:

No. Time Source Destination Protocol Length Info
1 0.000000 172.17.0.2 10.1.1.32 TCP 74 47572 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM TSval=12523148 TSecr=0 WS=128
2 0.000519 10.1.1.32 172.17.0.2 TCP 74 443 → 47572 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 SACK_PERM TSval=566170005 TSecr=12523148 WS=4
3 0.000543 172.17.0.2 10.1.1.32 TCP 66 47572 → 443 [ACK] Seq=1 Ack=1 Win=64256 Len=0 TSval=12523149 TSecr=566170005
4 0.001904 172.17.0.2 10.1.1.32 TLSv1 583 Client Hello
5 0.002399 10.1.1.32 172.17.0.2 TCP 66 443 → 47572 [ACK] Seq=1 Ack=518 Win=6864 Len=0 TSval=566170005 TSecr=12523150
6 0.002935 10.1.1.32 172.17.0.2 TCP 66 443 → 47572 [FIN, ACK] Seq=1 Ack=518 Win=6864 Len=0 TSval=566170005 TSecr=12523150
7 0.002986 172.17.0.2 10.1.1.32 TCP 66 47572 → 443 [FIN, ACK] Seq=518 Ack=2 Win=64256 Len=0 TSval=12523151 TSecr=566170005
9 0.003338 10.1.1.32 172.17.0.2 TCP 66 443 → 47572 [ACK] Seq=2 Ack=519 Win=6864 Len=0 TSval=566170005 TSecr=12523151

(I don't understand why Wireshark is reporting TLSv1 here, since urllib3 2.0 defaults to TLS 1.2 and the "Handshake Protocol Version" in Wireshark (not shown here) is TLS 1.2.)

Anyway, you can see that the client sends a Client Hello TLS frame in packet 4. While the server receives that packet, it then close the TCP connection in packet 6, which the client acknowledges. It's a violation of the protocol, instead an Alert should have been sent first, as seen in the Packet 6 below:

No. Time Source Destination Protocol Length Info
1 0.000000 192.168.1.33 104.154.89.105 TCP 74 43542 > 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM TSval=16293898 TSecr=0 WS=128
2 0.333284 104.154.89.105 192.168.1.33 TCP 74 443 > 43542 [SYN, ACK] Seq=0 Ack=1 Win=64768 Len=0 MSS=1420 SACK_PERM TSval=807097417 TSecr=16293898 WS=128
3 0.333397 192.168.1.33 104.154.89.105 TCP 66 43542 > 443 [ACK] Seq=1 Ack=1 Win=64256 Len=0 TSval=16294231 TSecr=807097417
4 0.334502 192.168.1.33 104.154.89.105 TLSv1.2 583 Client Hello
5 0.666928 104.154.89.105 192.168.1.33 TCP 66 443 > 43542 [ACK] Seq=1 Ack=518 Win=64256 Len=0 TSval=807097751 TSecr=16294233
6 0.667559 104.154.89.105 192.168.1.33 TLSv1.2 73 Alert (Level: Fatal, Description: Handshake Failure)
7 0.667575 192.168.1.33 104.154.89.105 TCP 66 43542 > 443 [ACK] Seq=518 Ack=8 Win=64256 Len=0 TSval=16294566 TSecr=807097751
8 0.667730 192.168.1.33 104.154.89.105 TCP 66 43542 > 443 [FIN, ACK] Seq=518 Ack=8 Win=64256 Len=0 TSval=16294566 TSecr=807097751
9 0.669476 104.154.89.105 192.168.1.33 TCP 66 443 > 43542 [FIN, ACK] Seq=8 Ack=518 Win=64256 Len=0 TSval=807097751 TSecr=16294233
10 0.669490 192.168.1.33 104.154.89.105 TCP 66 43542 > 443 [ACK] Seq=519 Ack=9 Win=64256 Len=0 TSval=16294568 TSecr=807097751
11 1.001678 104.154.89.105 192.168.1.33 TCP 66 443 > 43542 [ACK] Seq=9 Ack=519 Win=64256 Len=0 TSval=807098086 TSecr=16294566

@b-morgenthaler
Copy link
Author

How is your OpenSSL configured? It seems to be stricter than that, and you'll need to fix it.

To rule out any side effects between OpenSSL versions (1.1.1f and 3.0.2) I ran my experiments from above in a plain ubuntu:focal (openssl 1.1.1f) and ubuntu:jammy (openssl 3.0.2) Docker container - both with Python 3.8 and 3.10.

openssl/now 1.1.1f-1ubuntu2.19 amd64 [installed,local]
openssl/now 3.0.2-0ubuntu1.10 amd64 [installed,local]

I did not change any of openssl's default configuration bundled with the official Ubuntu Docker image. I only install Python and some Python libraries additionally.

I can confirm that the output from openssl ciphers -s -v DEFAULT:@SECLEVEL=2 for both versions includes

AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256

For what it's worth, here's the /etc/ssl/openssl.cnf from ubuntu:focal with openssl/now 1.1.1:

root@4a421eed719c:/# cat /etc/ssl/openssl.cnf
#
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
#

# Note that you can include other files from the main configuration
# file using the .include directive.
#.include filename

# This definition stops the following lines choking if HOME isn't
# defined.
HOME                    = .

# Extra OBJECT IDENTIFIER info:
#oid_file               = $ENV::HOME/.oid
oid_section             = new_oids

# To use this configuration file with the "-extfile" option of the
# "openssl x509" utility, name here the section containing the
# X.509v3 extensions to use:
# extensions            =
# (Alternatively, use a configuration file that has only
# X.509v3 extensions in its main [= default] section.)

[ new_oids ]

# We can add new OIDs in here for use by 'ca', 'req' and 'ts'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6

# Policies used by the TSA examples.
tsa_policy1 = 1.2.3.4.1
tsa_policy2 = 1.2.3.4.5.6
tsa_policy3 = 1.2.3.4.5.7

####################################################################
[ ca ]
default_ca      = CA_default            # The default ca section

####################################################################
[ CA_default ]

dir             = ./demoCA              # Where everything is kept
certs           = $dir/certs            # Where the issued certs are kept
crl_dir         = $dir/crl              # Where the issued crl are kept
database        = $dir/index.txt        # database index file.
#unique_subject = no                    # Set to 'no' to allow creation of
                                        # several certs with same subject.
new_certs_dir   = $dir/newcerts         # default place for new certs.

certificate     = $dir/cacert.pem       # The CA certificate
serial          = $dir/serial           # The current serial number
crlnumber       = $dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = $dir/crl.pem          # The current CRL
private_key     = $dir/private/cakey.pem# The private key

x509_extensions = usr_cert              # The extensions to add to the cert

# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

# Extension copying option: use with caution.
# copy_extensions = copy

# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions        = crl_ext

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = default               # use public key default MD
preserve        = no                    # keep passed DN ordering

# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy          = policy_match

# For the CA policy
[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

####################################################################
[ req ]
default_bits            = 2048
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions = v3_ca # The extensions to add to the self signed cert

# Passwords for private keys if not present they will be prompted for
# input_password = secret
# output_password = secret

# This sets a mask for permitted string types. There are several options.
# default: PrintableString, T61String, BMPString.
# pkix   : PrintableString, BMPString (PKIX recommendation before 2004)
# utf8only: only UTF8Strings (PKIX recommendation after 2004).
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
# MASK:XXXX a literal mask value.
# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
string_mask = utf8only

# req_extensions = v3_req # The extensions to add to a certificate request

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = AU
countryName_min                 = 2
countryName_max                 = 2

stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Some-State

localityName                    = Locality Name (eg, city)

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Internet Widgits Pty Ltd

# we can do this but it is not needed normally :-)
#1.organizationName             = Second Organization Name (eg, company)
#1.organizationName_default     = World Wide Web Pty Ltd

organizationalUnitName          = Organizational Unit Name (eg, section)
#organizationalUnitName_default =

commonName                      = Common Name (e.g. server FQDN or YOUR name)
commonName_max                  = 64

emailAddress                    = Email Address
emailAddress_max                = 64

# SET-ex3                       = SET extension number 3

[ req_attributes ]
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20

unstructuredName                = An optional company name

[ usr_cert ]

# These extensions are added when 'ca' signs a request.

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:FALSE

# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.

# This is OK for an SSL server.
# nsCertType                    = server

# For an object signing certificate this would be used.
# nsCertType = objsign

# For normal client use this is typical
# nsCertType = client, email

# and for everything including object signing:
# nsCertType = client, email, objsign

# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment

# This will be displayed in Netscape's comment listbox.
nsComment                       = "OpenSSL Generated Certificate"

# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move

# Copy subject details
# issuerAltName=issuer:copy

#nsCaRevocationUrl              = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName

# This is required for TSA certificates.
# extendedKeyUsage = critical,timeStamping

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]


# Extensions for a typical CA


# PKIX recommendation.

subjectKeyIdentifier=hash

authorityKeyIdentifier=keyid:always,issuer

basicConstraints = critical,CA:true

# Key usage: this is typical for a CA certificate. However since it will
# prevent it being used as an test self-signed certificate it is best
# left out by default.
# keyUsage = cRLSign, keyCertSign

# Some might want this also
# nsCertType = sslCA, emailCA

# Include email address in subject alt name: another PKIX recommendation
# subjectAltName=email:copy
# Copy issuer details
# issuerAltName=issuer:copy

# DER hex encoding of an extension: beware experts only!
# obj=DER:02:03
# Where 'obj' is a standard or added object
# You can even override a supported extension:
# basicConstraints= critical, DER:30:03:01:01:FF

[ crl_ext ]

# CRL extensions.
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.

# issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always

[ proxy_cert_ext ]
# These extensions should be added when creating a proxy certificate

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:FALSE

# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.

# This is OK for an SSL server.
# nsCertType                    = server

# For an object signing certificate this would be used.
# nsCertType = objsign

# For normal client use this is typical
# nsCertType = client, email

# and for everything including object signing:
# nsCertType = client, email, objsign

# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment

# This will be displayed in Netscape's comment listbox.
nsComment                       = "OpenSSL Generated Certificate"

# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move

# Copy subject details
# issuerAltName=issuer:copy

#nsCaRevocationUrl              = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName

# This really needs to be in place for it to be a proxy certificate.
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo

####################################################################
[ tsa ]

default_tsa = tsa_config1       # the default TSA section

[ tsa_config1 ]

# These are used by the TSA reply generation only.
dir             = ./demoCA              # TSA root directory
serial          = $dir/tsaserial        # The current serial number (mandatory)
crypto_device   = builtin               # OpenSSL engine to use for signing
signer_cert     = $dir/tsacert.pem      # The TSA signing certificate
                                        # (optional)
certs           = $dir/cacert.pem       # Certificate chain to include in reply
                                        # (optional)
signer_key      = $dir/private/tsakey.pem # The TSA private key (optional)
signer_digest  = sha256                 # Signing digest to use. (Optional)
default_policy  = tsa_policy1           # Policy if request did not specify it
                                        # (optional)
other_policies  = tsa_policy2, tsa_policy3      # acceptable policies (optional)
digests     = sha1, sha256, sha384, sha512  # Acceptable message digests (mandatory)
accuracy        = secs:1, millisecs:500, microsecs:100  # (optional)
clock_precision_digits  = 0     # number of digits after dot. (optional)
ordering                = yes   # Is ordering defined for timestamps?
                                # (optional, default: no)
tsa_name                = yes   # Must the TSA name be included in the reply?
                                # (optional, default: no)
ess_cert_id_chain       = no    # Must the ESS cert id chain be included?
                                # (optional, default: no)
ess_cert_id_alg         = sha1  # algorithm to compute certificate
                                # identifier (optional, default: sha1)

and the /etc/ssl/openssl.cnf from ubuntu:jammy with openssl/now 3.0.2:

root@b91f1fd25fd1:/# cat /etc/ssl/openssl.cnf
#
# OpenSSL example configuration file.
# See doc/man5/config.pod for more info.
#
# This is mostly being used for generation of certificate requests,
# but may be used for auto loading of providers

# Note that you can include other files from the main configuration
# file using the .include directive.
#.include filename

# This definition stops the following lines choking if HOME isn't
# defined.
HOME                    = .

 # Use this in order to automatically load providers.
openssl_conf = openssl_init

# Comment out the next line to ignore configuration errors
config_diagnostics = 1

# Extra OBJECT IDENTIFIER info:
# oid_file       = $ENV::HOME/.oid
oid_section = new_oids

# To use this configuration file with the "-extfile" option of the
# "openssl x509" utility, name here the section containing the
# X.509v3 extensions to use:
# extensions            =
# (Alternatively, use a configuration file that has only
# X.509v3 extensions in its main [= default] section.)

[ new_oids ]
# We can add new OIDs in here for use by 'ca', 'req' and 'ts'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6

# Policies used by the TSA examples.
tsa_policy1 = 1.2.3.4.1
tsa_policy2 = 1.2.3.4.5.6
tsa_policy3 = 1.2.3.4.5.7

# For FIPS
# Optionally include a file that is generated by the OpenSSL fipsinstall
# application. This file contains configuration data required by the OpenSSL
# fips provider. It contains a named section e.g. [fips_sect] which is
# referenced from the [provider_sect] below.
# Refer to the OpenSSL security policy for more information.
# .include fipsmodule.cnf

[openssl_init]
providers = provider_sect
ssl_conf = ssl_sect

# List of providers to load
[provider_sect]
default = default_sect
# The fips section name should match the section name inside the
# included fipsmodule.cnf.
# fips = fips_sect

# If no providers are activated explicitly, the default one is activated implicitly.
# See man 7 OSSL_PROVIDER-default for more details.
#
# If you add a section explicitly activating any other provider(s), you most
# probably need to explicitly activate the default provider, otherwise it
# becomes unavailable in openssl.  As a consequence applications depending on
# OpenSSL may not work correctly which could lead to significant system
# problems including inability to remotely access the system.
[default_sect]
# activate = 1


####################################################################
[ ca ]
default_ca      = CA_default            # The default ca section

####################################################################
[ CA_default ]

dir             = ./demoCA              # Where everything is kept
certs           = $dir/certs            # Where the issued certs are kept
crl_dir         = $dir/crl              # Where the issued crl are kept
database        = $dir/index.txt        # database index file.
#unique_subject = no                    # Set to 'no' to allow creation of
                                        # several certs with same subject.
new_certs_dir   = $dir/newcerts         # default place for new certs.

certificate     = $dir/cacert.pem       # The CA certificate
serial          = $dir/serial           # The current serial number
crlnumber       = $dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = $dir/crl.pem          # The current CRL
private_key     = $dir/private/cakey.pem# The private key

x509_extensions = usr_cert              # The extensions to add to the cert

# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

# Extension copying option: use with caution.
# copy_extensions = copy

# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions        = crl_ext

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = default               # use public key default MD
preserve        = no                    # keep passed DN ordering

# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy          = policy_match

# For the CA policy
[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

####################################################################
[ req ]
default_bits            = 2048
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions = v3_ca # The extensions to add to the self signed cert

# Passwords for private keys if not present they will be prompted for
# input_password = secret
# output_password = secret

# This sets a mask for permitted string types. There are several options.
# default: PrintableString, T61String, BMPString.
# pkix   : PrintableString, BMPString (PKIX recommendation before 2004)
# utf8only: only UTF8Strings (PKIX recommendation after 2004).
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
# MASK:XXXX a literal mask value.
# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
string_mask = utf8only

# req_extensions = v3_req # The extensions to add to a certificate request

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = AU
countryName_min                 = 2
countryName_max                 = 2

stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Some-State

localityName                    = Locality Name (eg, city)

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Internet Widgits Pty Ltd

# we can do this but it is not needed normally :-)
#1.organizationName             = Second Organization Name (eg, company)
#1.organizationName_default     = World Wide Web Pty Ltd

organizationalUnitName          = Organizational Unit Name (eg, section)
#organizationalUnitName_default =

commonName                      = Common Name (e.g. server FQDN or YOUR name)
commonName_max                  = 64

emailAddress                    = Email Address
emailAddress_max                = 64

# SET-ex3                       = SET extension number 3

[ req_attributes ]
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20

unstructuredName                = An optional company name

[ usr_cert ]

# These extensions are added when 'ca' signs a request.

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:FALSE

# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment

# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move

# Copy subject details
# issuerAltName=issuer:copy

# This is required for TSA certificates.
# extendedKeyUsage = critical,timeStamping

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]


# Extensions for a typical CA


# PKIX recommendation.

subjectKeyIdentifier=hash

authorityKeyIdentifier=keyid:always,issuer

basicConstraints = critical,CA:true

# Key usage: this is typical for a CA certificate. However since it will
# prevent it being used as an test self-signed certificate it is best
# left out by default.
# keyUsage = cRLSign, keyCertSign

# Include email address in subject alt name: another PKIX recommendation
# subjectAltName=email:copy
# Copy issuer details
# issuerAltName=issuer:copy

# DER hex encoding of an extension: beware experts only!
# obj=DER:02:03
# Where 'obj' is a standard or added object
# You can even override a supported extension:
# basicConstraints= critical, DER:30:03:01:01:FF

[ crl_ext ]

# CRL extensions.
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.

# issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always

[ proxy_cert_ext ]
# These extensions should be added when creating a proxy certificate

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:FALSE

# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment

# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move

# Copy subject details
# issuerAltName=issuer:copy

# This really needs to be in place for it to be a proxy certificate.
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo

####################################################################
[ tsa ]

default_tsa = tsa_config1       # the default TSA section

[ tsa_config1 ]

# These are used by the TSA reply generation only.
dir             = ./demoCA              # TSA root directory
serial          = $dir/tsaserial        # The current serial number (mandatory)
crypto_device   = builtin               # OpenSSL engine to use for signing
signer_cert     = $dir/tsacert.pem      # The TSA signing certificate
                                        # (optional)
certs           = $dir/cacert.pem       # Certificate chain to include in reply
                                        # (optional)
signer_key      = $dir/private/tsakey.pem # The TSA private key (optional)
signer_digest  = sha256                 # Signing digest to use. (Optional)
default_policy  = tsa_policy1           # Policy if request did not specify it
                                        # (optional)
other_policies  = tsa_policy2, tsa_policy3      # acceptable policies (optional)
digests     = sha1, sha256, sha384, sha512  # Acceptable message digests (mandatory)
accuracy        = secs:1, millisecs:500, microsecs:100  # (optional)
clock_precision_digits  = 0     # number of digits after dot. (optional)
ordering                = yes   # Is ordering defined for timestamps?
                                # (optional, default: no)
tsa_name                = yes   # Must the TSA name be included in the reply?
                                # (optional, default: no)
ess_cert_id_chain       = no    # Must the ESS cert id chain be included?
                                # (optional, default: no)
ess_cert_id_alg         = sha1  # algorithm to compute certificate
                                # identifier (optional, default: sha1)

[insta] # CMP using Insta Demo CA
# Message transfer
server = pki.certificate.fi:8700
# proxy = # set this as far as needed, e.g., http://192.168.1.1:8080
# tls_use = 0
path = pkix/

# Server authentication
recipient = "/C=FI/O=Insta Demo/CN=Insta Demo CA" # or set srvcert or issuer
ignore_keyusage = 1 # potentially needed quirk
unprotected_errors = 1 # potentially needed quirk
extracertsout = insta.extracerts.pem

# Client authentication
ref = 3078 # user identification
secret = pass:insta # can be used for both client and server side

# Generic message options
cmd = ir # default operation, can be overridden on cmd line with, e.g., kur

# Certificate enrollment
subject = "/CN=openssl-cmp-test"
newkey = insta.priv.pem
out_trusted = insta.ca.crt
certout = insta.cert.pem

[pbm] # Password-based protection for Insta CA
# Server and client authentication
ref = $insta::ref # 3078
secret = $insta::secret # pass:insta

[signature] # Signature-based protection for Insta CA
# Server authentication
trusted = insta.ca.crt # does not include keyUsage digitalSignature

# Client authentication
secret = # disable PBM
key = $insta::newkey # insta.priv.pem
cert = $insta::certout # insta.cert.pem

[ir]
cmd = ir

[cr]
cmd = cr

[kur]
# Certificate update
cmd = kur
oldcert = $insta::certout # insta.cert.pem

[rr]
# Certificate revocation
cmd = rr
oldcert = $insta::certout # insta.cert.pem

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
CipherString = DEFAULT:@SECLEVEL=2

@pquentin
Copy link
Member

pquentin commented Aug 9, 2023

Oh, wow, so using the following script on the Ubuntu Focal Docker image:

from urllib3.util import create_urllib3_context

ctx = create_urllib3_context()
for cipher in ctx.get_ciphers():
    print(cipher["description"])

I get the following output, with corresponds to your Wireshark ciphers:

TLS_AES_256_GCM_SHA384         TLSv1.3 Kx=any      Au=any   Enc=AESGCM(256)            Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256   TLSv1.3 Kx=any      Au=any   Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256         TLSv1.3 Kx=any      Au=any   Enc=AESGCM(128)            Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256)            Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2 Kx=ECDH     Au=RSA   Enc=AESGCM(256)            Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128)            Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256    TLSv1.2 Kx=ECDH     Au=RSA   Enc=AESGCM(128)            Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305    TLSv1.2 Kx=ECDH     Au=RSA   Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384      TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)               Mac=SHA384
ECDHE-RSA-AES256-SHA384        TLSv1.2 Kx=ECDH     Au=RSA   Enc=AES(256)               Mac=SHA384
ECDHE-ECDSA-AES128-SHA256      TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)               Mac=SHA256
ECDHE-RSA-AES128-SHA256        TLSv1.2 Kx=ECDH     Au=RSA   Enc=AES(128)               Mac=SHA256
DHE-RSA-AES256-GCM-SHA384      TLSv1.2 Kx=DH       Au=RSA   Enc=AESGCM(256)            Mac=AEAD
DHE-RSA-AES128-GCM-SHA256      TLSv1.2 Kx=DH       Au=RSA   Enc=AESGCM(128)            Mac=AEAD
DHE-RSA-AES256-SHA256          TLSv1.2 Kx=DH       Au=RSA   Enc=AES(256)               Mac=SHA256
DHE-RSA-AES128-SHA256          TLSv1.2 Kx=DH       Au=RSA   Enc=AES(128)               Mac=SHA256

But now, if I add ctx.set_ciphers("DEFAULT"), I get something totally different:

TLS_AES_256_GCM_SHA384         TLSv1.3 Kx=any      Au=any   Enc=AESGCM(256)            Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256   TLSv1.3 Kx=any      Au=any   Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256         TLSv1.3 Kx=any      Au=any   Enc=AESGCM(128)            Mac=AEAD  
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256)            Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2 Kx=ECDH     Au=RSA   Enc=AESGCM(256)            Mac=AEAD  
DHE-RSA-AES256-GCM-SHA384      TLSv1.2 Kx=DH       Au=RSA   Enc=AESGCM(256)            Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305    TLSv1.2 Kx=ECDH     Au=RSA   Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-RSA-CHACHA20-POLY1305      TLSv1.2 Kx=DH       Au=RSA   Enc=CHACHA20/POLY1305(256) Mac=AEAD  
ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128)            Mac=AEAD  
ECDHE-RSA-AES128-GCM-SHA256    TLSv1.2 Kx=ECDH     Au=RSA   Enc=AESGCM(128)            Mac=AEAD
DHE-RSA-AES128-GCM-SHA256      TLSv1.2 Kx=DH       Au=RSA   Enc=AESGCM(128)            Mac=AEAD
ECDHE-ECDSA-AES256-SHA384      TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)               Mac=SHA384
ECDHE-RSA-AES256-SHA384        TLSv1.2 Kx=ECDH     Au=RSA   Enc=AES(256)               Mac=SHA384
DHE-RSA-AES256-SHA256          TLSv1.2 Kx=DH       Au=RSA   Enc=AES(256)               Mac=SHA256
ECDHE-ECDSA-AES128-SHA256      TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)               Mac=SHA256                                                              
ECDHE-RSA-AES128-SHA256        TLSv1.2 Kx=ECDH     Au=RSA   Enc=AES(128)               Mac=SHA256                                                              
DHE-RSA-AES128-SHA256          TLSv1.2 Kx=DH       Au=RSA   Enc=AES(128)               Mac=SHA256
ECDHE-ECDSA-AES256-SHA         TLSv1   Kx=ECDH     Au=ECDSA Enc=AES(256)               Mac=SHA1                                                                
ECDHE-RSA-AES256-SHA           TLSv1   Kx=ECDH     Au=RSA   Enc=AES(256)               Mac=SHA1
DHE-RSA-AES256-SHA             SSLv3   Kx=DH       Au=RSA   Enc=AES(256)               Mac=SHA1
ECDHE-ECDSA-AES128-SHA         TLSv1   Kx=ECDH     Au=ECDSA Enc=AES(128)               Mac=SHA1
ECDHE-RSA-AES128-SHA           TLSv1   Kx=ECDH     Au=RSA   Enc=AES(128)               Mac=SHA1
DHE-RSA-AES128-SHA             SSLv3   Kx=DH       Au=RSA   Enc=AES(128)               Mac=SHA1
RSA-PSK-AES256-GCM-SHA384      TLSv1.2 Kx=RSAPSK   Au=RSA   Enc=AESGCM(256)            Mac=AEAD
DHE-PSK-AES256-GCM-SHA384      TLSv1.2 Kx=DHEPSK   Au=PSK   Enc=AESGCM(256)            Mac=AEAD
RSA-PSK-CHACHA20-POLY1305      TLSv1.2 Kx=RSAPSK   Au=RSA   Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-PSK-CHACHA20-POLY1305      TLSv1.2 Kx=DHEPSK   Au=PSK   Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-PSK-CHACHA20-POLY1305    TLSv1.2 Kx=ECDHEPSK Au=PSK   Enc=CHACHA20/POLY1305(256) Mac=AEAD  
AES256-GCM-SHA384              TLSv1.2 Kx=RSA      Au=RSA   Enc=AESGCM(256)            Mac=AEAD  
PSK-AES256-GCM-SHA384          TLSv1.2 Kx=PSK      Au=PSK   Enc=AESGCM(256)            Mac=AEAD  
PSK-CHACHA20-POLY1305          TLSv1.2 Kx=PSK      Au=PSK   Enc=CHACHA20/POLY1305(256) Mac=AEAD  
RSA-PSK-AES128-GCM-SHA256      TLSv1.2 Kx=RSAPSK   Au=RSA   Enc=AESGCM(128)            Mac=AEAD
DHE-PSK-AES128-GCM-SHA256      TLSv1.2 Kx=DHEPSK   Au=PSK   Enc=AESGCM(128)            Mac=AEAD
AES128-GCM-SHA256              TLSv1.2 Kx=RSA      Au=RSA   Enc=AESGCM(128)            Mac=AEAD  
PSK-AES128-GCM-SHA256          TLSv1.2 Kx=PSK      Au=PSK   Enc=AESGCM(128)            Mac=AEAD  
AES256-SHA256                  TLSv1.2 Kx=RSA      Au=RSA   Enc=AES(256)               Mac=SHA256                                                              
AES128-SHA256                  TLSv1.2 Kx=RSA      Au=RSA   Enc=AES(128)               Mac=SHA256
ECDHE-PSK-AES256-CBC-SHA384    TLSv1   Kx=ECDHEPSK Au=PSK   Enc=AES(256)               Mac=SHA384
ECDHE-PSK-AES256-CBC-SHA       TLSv1   Kx=ECDHEPSK Au=PSK   Enc=AES(256)               Mac=SHA1
SRP-RSA-AES-256-CBC-SHA        SSLv3   Kx=SRP      Au=RSA   Enc=AES(256)               Mac=SHA1
SRP-AES-256-CBC-SHA            SSLv3   Kx=SRP      Au=SRP   Enc=AES(256)               Mac=SHA1
RSA-PSK-AES256-CBC-SHA384      TLSv1   Kx=RSAPSK   Au=RSA   Enc=AES(256)               Mac=SHA384
DHE-PSK-AES256-CBC-SHA384      TLSv1   Kx=DHEPSK   Au=PSK   Enc=AES(256)               Mac=SHA384
RSA-PSK-AES256-CBC-SHA         SSLv3   Kx=RSAPSK   Au=RSA   Enc=AES(256)               Mac=SHA1
DHE-PSK-AES256-CBC-SHA         SSLv3   Kx=DHEPSK   Au=PSK   Enc=AES(256)               Mac=SHA1
AES256-SHA                     SSLv3   Kx=RSA      Au=RSA   Enc=AES(256)               Mac=SHA1
PSK-AES256-CBC-SHA384          TLSv1   Kx=PSK      Au=PSK   Enc=AES(256)               Mac=SHA384
PSK-AES256-CBC-SHA             SSLv3   Kx=PSK      Au=PSK   Enc=AES(256)               Mac=SHA1
ECDHE-PSK-AES128-CBC-SHA256    TLSv1   Kx=ECDHEPSK Au=PSK   Enc=AES(128)               Mac=SHA256
ECDHE-PSK-AES128-CBC-SHA       TLSv1   Kx=ECDHEPSK Au=PSK   Enc=AES(128)               Mac=SHA1  
SRP-RSA-AES-128-CBC-SHA        SSLv3   Kx=SRP      Au=RSA   Enc=AES(128)               Mac=SHA1  
SRP-AES-128-CBC-SHA            SSLv3   Kx=SRP      Au=SRP   Enc=AES(128)               Mac=SHA1  
RSA-PSK-AES128-CBC-SHA256      TLSv1   Kx=RSAPSK   Au=RSA   Enc=AES(128)               Mac=SHA256
DHE-PSK-AES128-CBC-SHA256      TLSv1   Kx=DHEPSK   Au=PSK   Enc=AES(128)               Mac=SHA256
RSA-PSK-AES128-CBC-SHA         SSLv3   Kx=RSAPSK   Au=RSA   Enc=AES(128)               Mac=SHA1
DHE-PSK-AES128-CBC-SHA         SSLv3   Kx=DHEPSK   Au=PSK   Enc=AES(128)               Mac=SHA1
AES128-SHA                     SSLv3   Kx=RSA      Au=RSA   Enc=AES(128)               Mac=SHA1
PSK-AES128-CBC-SHA256          TLSv1   Kx=PSK      Au=PSK   Enc=AES(128)               Mac=SHA256
PSK-AES128-CBC-SHA             SSLv3   Kx=PSK      Au=PSK   Enc=AES(128)               Mac=SHA1

Which includes the line of interest:

AES256-SHA256                  TLSv1.2 Kx=RSA      Au=RSA   Enc=AES(256)               Mac=SHA256                                                              

On my Fedora laptop, I also see a difference where DEFAULT adds some CBC ciphers and removes some CCM ciphers.

We can easily call set_ciphers("DEFAULT") here which would fix your immediate issue:

# Unless we're given ciphers defer to either system ciphers in
# the case of OpenSSL 1.1.1+ or use our own secure default ciphers.
if ciphers:
context.set_ciphers(ciphers)

But I'd have to understand what is the difference between not calling set_ciphers() and calling set_ciphers("DEFAULT").

Thanks for the responsiveness, it's very appreciated.

@pquentin
Copy link
Member

pquentin commented Aug 9, 2023

Aha, if we don't set a default, we get the default from CPython, defined in https://github.com/python/cpython/blob/65ce3652fa47a34acf715ee07bf0a2fae2e0da51/Modules/_ssl.c#L151-L186

And indeed, with ctx.set_ciphers("@SECLEVEL=2:ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES:DHE+AES:!aNULL:!eNULL:!aDSS:!SHA1:!AESCCM") I get the first block above, without AES256-SHA256. So calling set_ciphers("DEFAULT") explicitly makes sense.

@sethmlarson
Copy link
Member

@keepworking
Copy link

It looks related with python/cpython#25574 . when python 3.9 handshake did not provide SSLEOFErrors or OSError when handshaking but python 3.10 provide SSLEOFErrors. it also related python/cpython#115627 but, i think it may have another issue on python ssl handshake. i will try to check it.

@keepworking
Copy link

Based on the wireshark packet, it seems that if it fails, the server ends the connection without any response.

I reproduced the symptoms as follows.

test_server

I used the "nc" command to end with ctrl+c without needing any response.

nc -l -p 10000

test_code

import ssl
import socket

context = ssl.create_default_context()
with socket.create_connection(("localhost", 10000)) as sock :
    with context.wrap_socket(sock ,  server_hostname="localhost") as ssock:
        print(ssock.version())

I ran this on a version-by-version basis and when the contents were updated on nc, I just pressed ctrl+c to terminate the connection.

python:main

orange@32thread-server:~/project/python-contribute/keepworking/cpython/build$ ./python test.py
Traceback (most recent call last):
  File "/home/orange/project/python-contribute/keepworking/cpython/build/test.py", line 6, in <module>
    with context.wrap_socket(sock ,  server_hostname="localhost") as ssock:
         ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/orange/project/python-contribute/keepworking/cpython/Lib/ssl.py", line 455, in wrap_socket
    return self.sslsocket_class._create(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        sock=sock,
        ^^^^^^^^^^
    ...<5 lines>...
        session=session
        ^^^^^^^^^^^^^^^
    )
    ^
  File "/home/orange/project/python-contribute/keepworking/cpython/Lib/ssl.py", line 1077, in _create
    self.do_handshake()
    ~~~~~~~~~~~~~~~~~^^
  File "/home/orange/project/python-contribute/keepworking/cpython/Lib/ssl.py", line 1363, in do_handshake
    self._sslobj.do_handshake()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
ssl.SSLEOFError: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1023)

python 3.10

orange@32thread-server:~/project/python-contribute/keepworking/cpython/build$ python3.10 test.py
Traceback (most recent call last):
  File "/home/orange/project/python-contribute/keepworking/cpython/build/test.py", line 6, in <module>
    with context.wrap_socket(sock ,  server_hostname="localhost") as ssock:
  File "/usr/lib/python3.10/ssl.py", line 513, in wrap_socket
    return self.sslsocket_class._create(
  File "/usr/lib/python3.10/ssl.py", line 1100, in _create
    self.do_handshake()
  File "/usr/lib/python3.10/ssl.py", line 1371, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLEOFError: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1007)

python 3.9

orange@32thread-server:~/project/python-contribute/keepworking/cpython/build$ python3.9 test.py
Traceback (most recent call last):
  File "/home/orange/project/python-contribute/keepworking/cpython/build/test.py", line 6, in <module>
    with context.wrap_socket(sock ,  server_hostname="localhost") as ssock:
  File "/usr/local/lib/python3.9/ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "/usr/local/lib/python3.9/ssl.py", line 1040, in _create
    self.do_handshake()
  File "/usr/local/lib/python3.9/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: KRB5_S_TKT_NYV] unexpected eof while reading (_ssl.c:1123)

In my opinion, if the server terminates without responding to any warning, it is difficult for the client to display the correct information. as far as i know, providing information on negotiation failures is a non-essential recommendation in the TLS protocol because it can provide additional information to attackers. It is difficult to view EOF errors as a bug. urllib3 do not need any action for it.

@keepworking
Copy link

(I don't understand why Wireshark is reporting TLSv1 here, since urllib3 2.0 defaults to TLS 1.2 and the "Handshake Protocol Version" in Wireshark (not shown here) is TLS 1.2.)

The protocol version of ClientHello's record layer is 1.0. It seems to be marked 1.0 in wireshark because negotiations were not made because the server did not respond to this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants