Package: curl
Version: 1.1.1a-1
Severity: important

Hi,

I discovered that during test with curl, that curl in Debian doesn't support 
TLSv1.3.

$ dpkg -l libssl1.1:amd64 | grep ^i
ii  libssl1.1:amd64 1.1.1a-1     amd64        Secure Sockets Layer toolkit - 
shared libraries
$ dpkg -l curl | grep ^i
ii  curl           7.61.0-1     amd64        command line tool for transferring 
data with URL syntax
$

curl links against libssl.so.1.1 here

$ ldd `which curl` | grep ssl
    libssl.so.1.1 => /lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007f4b61807000)
$ ldd `which openssl` | grep ssl
    libssl.so.1.1 => /lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007fbe574fc000)
$


$ curl --tlsv1.3 -v https://www.cloudflare.com/
*   Trying 198.41.214.162...
* TCP_NODELAY set
* Connected to www.cloudflare.com (198.41.214.162) port 443 (#0)
* OpenSSL was built without TLS 1.3 support
* Closing connection 0
curl: (4) OpenSSL was built without TLS 1.3 support
$
$ curl --tls-max 1.3 -v https://www.cloudflare.com/
*   Trying 198.41.214.162...
* TCP_NODELAY set
* Connected to www.cloudflare.com (198.41.214.162) port 443 (#0)
* OpenSSL was built without TLS 1.3 support
* Closing connection 0
curl: (4) OpenSSL was built without TLS 1.3 support
$


$ openssl version
OpenSSL 1.1.1a  20 Nov 2018
$



$ openssl s_client -tls1_3 www.cloudflare.com:443
CONNECTED(00000003)
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High 
Assurance EV Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 
Extended Validation Server CA
verify return:1
depth=0 businessCategory = Private Organization, jurisdictionC = US, 
jurisdictionST = Delaware, serialNumber = 4710875, C = US, ST = California, L = 
San Francisco, O = "Cloudflare, Inc.", CN = cloudflare.com
verify return:1
---
Certificate chain
 0 s:businessCategory = Private Organization, jurisdictionC = US, 
jurisdictionST = Delaware, serialNumber = 4710875, C = US, ST = California, L = 
San Francisco, O = "Cloudflare, Inc.", CN = cloudflare.com
   i:C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 
Extended Validation Server CA
 1 s:C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 
Extended Validation Server CA
   i:C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High 
Assurance EV Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIHUzCCBjugAwIBAgIQA33kBvlAKyQzxZW8HLqPiDANBgkqhkiG9w0BAQsFADB1
<cut>
MFXwvTAcfgVdQpdSALgo/VdC3KWNFNFBBi/0Kx/wxcHJsHmmRT6wiyVT0H1l+7hu
yUcvQcYmUw==
-----END CERTIFICATE-----
subject=businessCategory = Private Organization, jurisdictionC = US, 
jurisdictionST = Delaware, serialNumber = 4710875, C = US, ST = California, L = 
San Francisco, O = "Cloudflare, Inc.", CN = cloudflare.com

issuer=C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 
Extended Validation Server CA

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 3584 bytes and written 322 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: DD0AA308DEA397DACDA55BA926C2D1EE6FEBFFA52AF9D802B80261EC7C55131D
    Session-ID-ctx: 
    Resumption PSK: 
B03F1EDD4972188E44C3DEDFB8C610991DE6A309CDB198C7D90A27D67CC263C295ECC4EA16A995F0E334990368B4FC4D
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 172800 (seconds)
    TLS session ticket:
    0000 - 30 ee 0c 4d d3 16 de 1f-1e d6 50 eb 69 1e a0 44   0..M......P.i..D
<cut>
    00c0 - 96 d3 2f 27 93 60 e7 02-4b 17 d7 ec eb 35 68 3d   ../'.`..K....5h=

    Start Time: 1543431295
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 14336
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: 25F08DC191E37AF3BB5F26CFE246C6C3F8EEDF46701130E22B0A29C4165F7B4D
    Session-ID-ctx: 
    Resumption PSK: 
CCF4A9294184421DFF28387E22082DA3781290A2CBA562D36153655C8A6E2272F6353FF95B6E04F24309019F591ACFB7
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 172800 (seconds)
    TLS session ticket:
    0000 - 30 ee 0c 4d d3 16 de 1f-1e d6 50 eb 69 1e a0 44   0..M......P.i..D
<cut>
    00c0 - ac ab f0 99 28 c5 bd 19-63 e0 18 64 0d c0 e0 e4   ....(...c..d....

    Start Time: 1543431295
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 14336
---
read R BLOCK


<WAITING>
...
^C
$





The problem with curl / libcurl, is that is uses this block of code

as seen in https://salsa.debian.org/debian/curl/raw/master/lib/vtls/openssl.c


static CURLcode
set_ssl_version_min_max(long *ctx_options, struct connectdata *conn,
                        int sockindex)
{
#if (OPENSSL_VERSION_NUMBER < 0x1000100FL) || !defined(TLS1_3_VERSION)
  /* convoluted #if condition just to avoid compiler warnings on unused
     variable */
  struct Curl_easy *data = conn->data;
#endif
  long ssl_version = SSL_CONN_CONFIG(version);
  long ssl_version_max = SSL_CONN_CONFIG(version_max);

  switch(ssl_version) {
    case CURL_SSLVERSION_TLSv1_3:
#ifdef TLS1_3_VERSION
    {
      struct ssl_connect_data *connssl = &conn->ssl[sockindex];
      SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION);
      *ctx_options |= SSL_OP_NO_TLSv1_2;
    }
#else
      (void)sockindex;
      failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
      return CURLE_NOT_BUILT_IN;
#endif
      /* FALLTHROUGH */
    case CURL_SSLVERSION_TLSv1_2:
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
      *ctx_options |= SSL_OP_NO_TLSv1_1;
#else
      failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
      return CURLE_NOT_BUILT_IN;
#endif
      /* FALLTHROUGH */
    case CURL_SSLVERSION_TLSv1_1:
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
      *ctx_options |= SSL_OP_NO_TLSv1;
#else
      failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
      return CURLE_NOT_BUILT_IN;
#endif
      /* FALLTHROUGH */
    case CURL_SSLVERSION_TLSv1_0:
    case CURL_SSLVERSION_TLSv1:
      break;
  }

  switch(ssl_version_max) {
    case CURL_SSLVERSION_MAX_TLSv1_0:
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
      *ctx_options |= SSL_OP_NO_TLSv1_1;
#endif
      /* FALLTHROUGH */
    case CURL_SSLVERSION_MAX_TLSv1_1:
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
      *ctx_options |= SSL_OP_NO_TLSv1_2;
#endif
      /* FALLTHROUGH */
    case CURL_SSLVERSION_MAX_TLSv1_2:
#ifdef TLS1_3_VERSION
      *ctx_options |= SSL_OP_NO_TLSv1_3;
#endif
      break;
    case CURL_SSLVERSION_MAX_TLSv1_3:
#ifdef TLS1_3_VERSION
      break;
#else
      failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
      return CURLE_NOT_BUILT_IN;
#endif
  }
  return CURLE_OK;
}



Where TLS_1_3_VERSION macro is comming from openssl (libssl-dev:1.1.1a-1 
package):


$ grep TLS1_3 /usr/include/openssl/tls1.h
# define TLS1_3_VERSION                  0x0304
# define TLS_MAX_VERSION                 TLS1_3_VERSION
$



So the main problem is that it was compiled with previous header files
probably from 1.1.0something.

Obviously, it can't be fixed otherwise, because

statement like

      SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION);


will not compile correctly in previous versions of openssl without the
version being defined.

On the other hand if compiled with new libssl, but using old openssl, the
code will work fine probably (openssl claims full ABI compatibility, but
probably only if the openssl is newer, not reverse). I am not quite sure
of that tho, so adding proper (updated) "Depends" on curl / libcurl
package could be required.


I would also strongly advice to change the wording in the error message

Because

curl: (4) OpenSSL was built without TLS 1.3 support

suggests that openssl library I am using doesn't support TLS 1.3, which is not 
true!


Thanks,
Witold








-- System Information:
Debian Release: buster/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.18.0-2-amd64 (SMP w/32 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Reply via email to