curl / Mailing Lists / curl-users / Single Mail
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

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
---
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