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