Buy commercial curl support from WolfSSL. We help you work
out your issues, debug your libcurl applications, use the API, port to new
platforms, add new features and more. With a team lead by the curl founder
himself.
curl with openssl not honoring MaxProtocol in openssl conf
- Contemporary messages sorted: [ by date ] [ by thread ] [ by subject ] [ by author ] [ by messages with attachments ]
From: Andreas Hasenack via curl-users <curl-users_at_lists.haxx.se>
Date: Tue, 3 Jan 2023 12:01:18 -0300
Hi,
I'm checking how to restrict crypto algorithms and suites in different
applications linked with openssl, by tweaking the openssl
configuration file. I understand that applications can still override
those settings, but at least I would expect them to follow the
defaults from the openssl config when nothing else is chosen.
Tl;DR: it looks like curl isn't respecting openssl's MaxProtocol[1]. I
tried all versions of Ubuntu from Bionic to Lunar, and it only worked
as expected in Bionic, where it failed to connect to the TLSv1.3-only
server when I had MaxProtocol=TLSv1.2.
Here are the versions:
curl | 7.58.0-2ubuntu3.21 | bionic-security | source
curl | 7.68.0-1ubuntu2.14 | focal-security | source
curl | 7.81.0-1ubuntu1.6 | jammy-security | source
curl | 7.85.0-1ubuntu0.1 | kinetic-security | source
curl | 7.86.0-2 | lunar | source
Build options used are at the end of the email.
In my test scenario, I setup a server (ubuntu Jammy in this case) in
one machine running:
openssl s_server -cert j-server.pem -key j-server.key -tls1_3
Then from another machine, I configure openssl with "MaxProtocol =
TLSv1.2" and attempt to connect to this server. I'm trying with
openssl's native s_client command, then curl, then wget. While
s_client and wget fail correctly, curl always succeeds.
In these tests, the openssl config is at /etc/ssl/openssl.cnf, and I
have the relevant parts like this on the *client* I'm testing:
openssl_conf = openssl_init
[openssl_init]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
CipherString = DEFAULT:@SECLEVEL=2
MaxProtocol = TLSv1.2
a) s_client
$ openssl s_client -connect j-server.lxd:4433;echo $?
CONNECTED(00000003)
40777708747F0000:error:0A00042E:SSL routines:ssl3_read_bytes:tlsv1
alert protocol version:../ssl/record/rec_layer_s3.c:1588:SSL alert
number 70
Date: Tue, 3 Jan 2023 12:01:18 -0300
Hi,
I'm checking how to restrict crypto algorithms and suites in different
applications linked with openssl, by tweaking the openssl
configuration file. I understand that applications can still override
those settings, but at least I would expect them to follow the
defaults from the openssl config when nothing else is chosen.
Tl;DR: it looks like curl isn't respecting openssl's MaxProtocol[1]. I
tried all versions of Ubuntu from Bionic to Lunar, and it only worked
as expected in Bionic, where it failed to connect to the TLSv1.3-only
server when I had MaxProtocol=TLSv1.2.
Here are the versions:
curl | 7.58.0-2ubuntu3.21 | bionic-security | source
curl | 7.68.0-1ubuntu2.14 | focal-security | source
curl | 7.81.0-1ubuntu1.6 | jammy-security | source
curl | 7.85.0-1ubuntu0.1 | kinetic-security | source
curl | 7.86.0-2 | lunar | source
Build options used are at the end of the email.
In my test scenario, I setup a server (ubuntu Jammy in this case) in
one machine running:
openssl s_server -cert j-server.pem -key j-server.key -tls1_3
Then from another machine, I configure openssl with "MaxProtocol =
TLSv1.2" and attempt to connect to this server. I'm trying with
openssl's native s_client command, then curl, then wget. While
s_client and wget fail correctly, curl always succeeds.
In these tests, the openssl config is at /etc/ssl/openssl.cnf, and I
have the relevant parts like this on the *client* I'm testing:
openssl_conf = openssl_init
[openssl_init]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
CipherString = DEFAULT:@SECLEVEL=2
MaxProtocol = TLSv1.2
a) s_client
$ openssl s_client -connect j-server.lxd:4433;echo $?
CONNECTED(00000003)
40777708747F0000:error:0A00042E:SSL routines:ssl3_read_bytes:tlsv1
alert protocol version:../ssl/record/rec_layer_s3.c:1588:SSL alert
number 70
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 209 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1672756788
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
---
1
And on the server:
4037782EA77F0000:error:0A000102:SSL
routines:tls_early_post_process_client_hello:unsupported
protocol:../ssl/statem/statem_srvr.c:1657:
b) wget
$ wget -O /dev/null https://j-server.lxd:4433
--2023-01-03 14:42:18-- https://j-server.lxd:4433/
Resolving j-server.lxd (j-server.lxd)... 10.0.100.87
Connecting to j-server.lxd (j-server.lxd)|10.0.100.87|:4433... connected.
OpenSSL: error:0A00042E:SSL routines::tlsv1 alert protocol version
Unable to establish SSL connection.
Server errors with the same message as when using s_client.
c) curl
$ curl -V
curl 7.86.0 (x86_64-pc-linux-gnu) libcurl/7.86.0 OpenSSL/3.0.5
zlib/1.2.11 brotli/1.0.9 zstd/1.5.2 libidn2/2.3.3 libpsl/0.21.0
(+libidn2/2.3.2) libssh/0.10.4/openssl/zlib nghttp2/1.50.0 librtmp/2.3
Release-Date: 2022-10-26
Protocols: dict file ftp ftps gopher gophers http https imap imaps
ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps
telnet tftp
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN
IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL threadsafe
TLS-SRP UnixSockets zstd
$ curl -o /dev/null https://j-server.lxd:4433
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:04 --:--:-- 0^C
And the server logs that TLSv1.3 was used:
$ openssl s_server -cert j-server.pem -key j-server.key -tls1_3
Using default temp DH parameters
ACCEPT
(...)
CIPHER is TLS_AES_256_GCM_SHA384
Secure Renegotiation IS supported
GET / HTTP/1.1
Host: j-server.lxd:4433
User-Agent: curl/7.86.0
Accept: */*
That's a TLSv1.3 ciphersuite, but just to be sure, tshark (tcpdump)
confirms tls v1.3 was used:
1 0.000000000 10.0.100.41 → 10.0.100.87 TCP 76 40102 → 4433
[SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=1771368713
TSecr=0 WS=128
2 0.000009574 10.0.100.87 → 10.0.100.41 TCP 76 4433 → 40102
[SYN, ACK] Seq=0 Ack=1 Win=65160 Len=0 MSS=1460 SACK_PERM=1
TSval=2052315130 TSecr=1771368713 WS=128
3 0.000018983 10.0.100.41 → 10.0.100.87 TCP 68 40102 → 4433
[ACK] Seq=1 Ack=1 Win=64256 Len=0 TSval=1771368713 TSecr=2052315130
4 0.025030013 10.0.100.41 → 10.0.100.87 TLSv1 585 Client Hello
5 0.025043788 10.0.100.87 → 10.0.100.41 TCP 68 4433 → 40102
[ACK] Seq=1 Ack=518 Win=64768 Len=0 TSval=2052315155 TSecr=1771368738
6 0.027072337 10.0.100.87 → 10.0.100.41 TLSv1.3 3023 Server
Hello, Change Cipher Spec, Application Data, Application Data,
Application Data, Application Data
7 0.027098322 10.0.100.41 → 10.0.100.87 TCP 68 40102 → 4433
[ACK] Seq=518 Ack=2956 Win=63488 Len=0 TSval=1771368740
TSecr=2052315157
8 0.028267604 10.0.100.41 → 10.0.100.87 TLSv1.3 148 Change
Cipher Spec, Application Data
9 0.028368488 10.0.100.41 → 10.0.100.87 TLSv1.3 171 Application Data
10 0.028473787 10.0.100.87 → 10.0.100.41 TLSv1.3 323 Application Data
11 0.028550592 10.0.100.87 → 10.0.100.41 TLSv1.3 323 Application Data
12 0.028630400 10.0.100.41 → 10.0.100.87 TCP 68 40102 → 4433
[ACK] Seq=701 Ack=3466 Win=64128 Len=0 TSval=1771368741
TSecr=2052315158
curl -v shows an odd mix of TLSv1.2 and TLSv1.3 that I don't
understand, but eventually settles on "* SSL connection using TLSv1.3
/ TLS_AES_256_GCM_SHA384":
$ curl -o /dev/null https://j-server.lxd:4433 -s -v
* Trying 10.0.100.87:4433...
* Connected to j-server.lxd (10.0.100.87) port 4433 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.2 (IN), TLS header, Certificate Status (22):
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.2 (IN), TLS header, Finished (20):
{ [5 bytes data]
* TLSv1.2 (IN), TLS header, Supplemental data (23):
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [6 bytes data]
* TLSv1.2 (IN), TLS header, Supplemental data (23):
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [2412 bytes data]
* TLSv1.2 (IN), TLS header, Supplemental data (23):
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.2 (IN), TLS header, Supplemental data (23):
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.2 (OUT), TLS header, Finished (20):
} [5 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
* subject: O=Example Company; CN=j-server.lxd
* start date: Jan 3 12:31:18 2023 GMT
* expire date: Jan 3 12:31:18 2024 GMT
* common name: j-server.lxd (matched)
* issuer: CN=Example Company
* SSL certificate verify ok.
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
} [5 bytes data]
> GET / HTTP/1.1
> Host: j-server.lxd:4433
> User-Agent: curl/7.86.0
> Accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [233 bytes data]
* TLSv1.2 (IN), TLS header, Supplemental data (23):
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [233 bytes data]
* old SSL session ID is stale, removing
I've seen this old bug report[2] which looks similar, and suggests
it's some quirk in openssl or TLS itself, but given it works as
expected in s_client and wget, maybe there is something else that curl
is doing?
Below I'm showing the summary of the curl build options for bionic
(where it works as expected) and lunar (where it uses TLSv1.3 even
when MaxProtocol is TLSv1.2).
Bionic curl build summary:
curl version: 7.58.0
Host setup: x86_64-pc-linux-gnu
Install prefix: /usr
Compiler: gcc
SSL support: enabled (OpenSSL)
SSH support: no (--with-libssh2)
zlib support: enabled
brotli support: no (--with-brotli)
GSS-API support: enabled (MIT Kerberos/Heimdal)
TLS-SRP support: enabled
resolver: POSIX threaded
IPv6 support: enabled
Unix sockets support: enabled
IDN support: enabled (libidn2)
Build libcurl: Shared=yes, Static=yes
Built-in manual: enabled
--libcurl option: enabled (--disable-libcurl-option)
Verbose errors: enabled (--disable-verbose)
SSPI support: no (--enable-sspi)
ca cert bundle: /etc/ssl/certs/ca-certificates.crt
ca cert path: /etc/ssl/certs
ca fallback: no
LDAP support: enabled (OpenLDAP)
LDAPS support: enabled
RTSP support: enabled
RTMP support: enabled (librtmp)
metalink support: no (--with-libmetalink)
PSL support: yes
HTTP2 support: enabled (nghttp2)
Protocols: DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS
LDAP LDAPS POP3 POP3S RTMP RTSP SMB SMBS SMTP SMTPS TELNET TFTP
Lunar build summary:
Host setup: x86_64-pc-linux-gnu
Install prefix: /usr
Compiler: gcc
CFLAGS: -g -O2 -ffile-prefix-map=/<<PKGBUILDDIR>>=.
-flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects
-fstack-protector-strong -Wformat -Werror=format-security
-Werror-implicit-function-declaration -Wno-system-headers
CPPFLAGS: -Wdate-time -D_FORTIFY_SOURCE=2 -isystem
/usr/include/mit-krb5 -DOPENSSL_SUPPRESS_DEPRECATED
LDFLAGS: -Wl,-Bsymbolic-functions -flto=auto
-ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now
LIBS: -lnghttp2 -lidn2 -lrtmp -lssh -lssh -lpsl -lssl
-lcrypto -lssl -lcrypto -L/usr/lib/x86_64-linux-gnu/mit-krb5
-lgssapi_krb5 -llber -lldap -llber -lzstd -lbrotlidec -lz
curl version: 7.86.0
SSL: enabled (OpenSSL v3+)
SSH: enabled (libSSH)
zlib: enabled
brotli: enabled (libbrotlidec)
zstd: enabled (libzstd)
GSS-API: enabled (MIT Kerberos/Heimdal)
GSASL: no (libgsasl not found)
TLS-SRP: enabled
resolver: POSIX threaded
IPv6: enabled
Unix sockets: enabled
IDN: enabled (libidn2)
Build libcurl: Shared=yes, Static=yes
Built-in manual: enabled
--libcurl option: enabled (--disable-libcurl-option)
Verbose errors: enabled (--disable-verbose)
Code coverage: disabled
SSPI: no (--enable-sspi)
ca cert bundle: /etc/ssl/certs/ca-certificates.crt
ca cert path: /etc/ssl/certs
ca fallback: no
LDAP: enabled (OpenLDAP)
LDAPS: enabled
RTSP: enabled
RTMP: enabled (librtmp)
PSL: enabled
Alt-svc: enabled (--disable-alt-svc)
Headers API: enabled (--disable-headers-api)
HSTS: enabled (--disable-hsts)
HTTP1: enabled (internal)
HTTP2: enabled (nghttp2)
HTTP3: no (--with-ngtcp2, --with-quiche --with-msh3)
ECH: no (--enable-ech)
WebSockets: no (--enable-websockets)
Protocols: DICT FILE FTP FTPS GOPHER GOPHERS HTTP HTTPS IMAP
IMAPS LDAP LDAPS MQTT POP3 POP3S RTMP RTSP SCP SFTP SMB SMBS SMTP
SMTPS TELNET TFTP
Features: AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6
Kerberos Largefile NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets
alt-svc brotli libz threadsafe zstd
This could all still be a build problem, as the package in Ubuntu and
Debian builds in a quite complex way, with 3 different builds and
packaging split to accommodate that. It would perhaps be helpful if
others could try to replicate my simple test.
Thanks, and sorry for the long email.
1. https://www.openssl.org/docs/man3.0/man3/SSL_CONF_cmd.html#MaxProtocol
2. https://github.com/curl/curl/issues/5356
--
Unsubscribe: https://lists.haxx.se/listinfo/curl-users
Etiquette: https://curl.se/mail/etiquette.html
Received on 2023-01-03