Skip to content

Commit 59114b8

Browse files
committed
Force strong TLS cipher suites in rustup-init.sh
Force curl and wget to use strong TLS cipher suites if supported by local tools. If RUSTUP_TLS_CIPHERSUITES variable is set by user then use it. Closes #2284. curl and wget TLS backends supported for strong TLS cipher suites: GnuTLS, OpenSSL, LibreSSL and BoringSSL. Other backends (NSS, WolfSSL, etc.) fall back to prior behavior but can also handle user-specified cipher suites in any syntax required (syntax is not checked by script). curl and wget (if support is detected) will use the same strong TLS 1.2-1.3 cipher suite as Firefox 68 ESR with all weak cipher suites disabled using about:config. Sequence of all 9 cipher suites for OpenSSL is identical to Firefox (slightly different for GnuTLS). DHE is excluded from TLS 1.2 because servers often use bad DH params (see RFC 7919). GnuTLS priority string produces: TLS_AES_128_GCM_SHA256 0x13, 0x01 TLS1.3 TLS_CHACHA20_POLY1305_SHA256 0x13, 0x03 TLS1.3 TLS_AES_256_GCM_SHA384 0x13, 0x02 TLS1.3 TLS_ECDHE_ECDSA_AES_128_GCM_SHA256 0xc0, 0x2b TLS1.2 TLS_ECDHE_ECDSA_CHACHA20_POLY1305 0xcc, 0xa9 TLS1.2 TLS_ECDHE_ECDSA_AES_256_GCM_SHA384 0xc0, 0x2c TLS1.2 TLS_ECDHE_RSA_AES_128_GCM_SHA256 0xc0, 0x2f TLS1.2 TLS_ECDHE_RSA_CHACHA20_POLY1305 0xcc, 0xa8 TLS1.2 TLS_ECDHE_RSA_AES_256_GCM_SHA384 0xc0, 0x30 TLS1.2 GnuTLS priority string could be hardened more but it isn't forgiving of unknown/unsupported values, so the bare minimum was specified.
1 parent 2138b7a commit 59114b8

File tree

1 file changed

+110
-8
lines changed

1 file changed

+110
-8
lines changed

rustup-init.sh

+110-8
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ ignore() {
376376
# use wget instead.
377377
downloader() {
378378
local _dld
379+
local _ciphersuites
379380
if check_cmd curl; then
380381
_dld=curl
381382
elif check_cmd wget; then
@@ -387,18 +388,32 @@ downloader() {
387388
if [ "$1" = --check ]; then
388389
need_cmd "$_dld"
389390
elif [ "$_dld" = curl ]; then
390-
if ! check_help_for "$3" curl --proto --tlsv1.2; then
391-
echo "Warning: Not forcing TLS v1.2, this is potentially less secure"
392-
curl --silent --show-error --fail --location "$1" --output "$2"
391+
get_ciphersuites_for_curl
392+
_ciphersuites="$RETVAL"
393+
if [ -n "$_ciphersuites" ]; then
394+
curl --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2"
393395
else
394-
curl --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2"
396+
echo "Warning: Not forcing strong cipher suites for TLS, this is potentially less secure"
397+
if ! check_help_for "$3" curl --proto --tlsv1.2; then
398+
echo "Warning: Not forcing TLS v1.2, this is potentially less secure"
399+
curl --silent --show-error --fail --location "$1" --output "$2"
400+
else
401+
curl --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2"
402+
fi
395403
fi
396404
elif [ "$_dld" = wget ]; then
397-
if ! check_help_for "$3" wget --https-only --secure-protocol; then
398-
echo "Warning: Not forcing TLS v1.2, this is potentially less secure"
399-
wget "$1" -O "$2"
405+
get_ciphersuites_for_wget
406+
_ciphersuites="$RETVAL"
407+
if [ -n "$_ciphersuites" ]; then
408+
wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2"
400409
else
401-
wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2"
410+
echo "Warning: Not forcing strong cipher suites for TLS, this is potentially less secure"
411+
if ! check_help_for "$3" wget --https-only --secure-protocol; then
412+
echo "Warning: Not forcing TLS v1.2, this is potentially less secure"
413+
wget "$1" -O "$2"
414+
else
415+
wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2"
416+
fi
402417
fi
403418
else
404419
err "Unknown downloader" # should not reach here
@@ -441,4 +456,91 @@ check_help_for() {
441456
test "$_ok" = "y"
442457
}
443458

459+
# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
460+
# if support by local tools is detected. Detection currently supports these curl backends:
461+
# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
462+
get_ciphersuites_for_curl() {
463+
if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
464+
# user specified custom cipher suites, assume they know what they're doing
465+
RETVAL="$RUSTUP_TLS_CIPHERSUITES"
466+
return
467+
fi
468+
469+
local _openssl_syntax="no"
470+
local _gnutls_syntax="no"
471+
local _backend_supported="yes"
472+
if curl -V | grep -q ' OpenSSL/'; then
473+
_openssl_syntax="yes"
474+
elif curl -V | grep -iq ' LibreSSL/'; then
475+
_openssl_syntax="yes"
476+
elif curl -V | grep -iq ' BoringSSL/'; then
477+
_openssl_syntax="yes"
478+
elif curl -V | grep -iq ' GnuTLS/'; then
479+
_gnutls_syntax="yes"
480+
else
481+
_backend_supported="no"
482+
fi
483+
484+
local _args_supported="no"
485+
if [ "$_backend_supported" = "yes" ]; then
486+
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
487+
if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then
488+
_args_supported="yes"
489+
fi
490+
fi
491+
492+
local _cs=""
493+
if [ "$_args_supported" = "yes" ]; then
494+
if [ "$_openssl_syntax" = "yes" ]; then
495+
_cs=$(get_strong_ciphersuites_for "openssl")
496+
elif [ "$_gnutls_syntax" = "yes" ]; then
497+
_cs=$(get_strong_ciphersuites_for "gnutls")
498+
fi
499+
fi
500+
501+
RETVAL="$_cs"
502+
}
503+
504+
# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
505+
# if support by local tools is detected. Detection currently supports these wget backends:
506+
# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
507+
get_ciphersuites_for_wget() {
508+
if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
509+
# user specified custom cipher suites, assume they know what they're doing
510+
RETVAL="$RUSTUP_TLS_CIPHERSUITES"
511+
return
512+
fi
513+
514+
local _cs=""
515+
if wget -V | grep -q '\-DHAVE_LIBSSL'; then
516+
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
517+
if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
518+
_cs=$(get_strong_ciphersuites_for "openssl")
519+
fi
520+
elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then
521+
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
522+
if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
523+
_cs=$(get_strong_ciphersuites_for "gnutls")
524+
fi
525+
fi
526+
527+
RETVAL="$_cs"
528+
}
529+
530+
# Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2
531+
# excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad
532+
# DH params often found on servers (see RFC 7919). Sequence matches or is
533+
# similar to Firefox 68 ESR with weak cipher suites disabled via about:config.
534+
# $1 must be openssl or gnutls.
535+
get_strong_ciphersuites_for() {
536+
if [ "$1" = "openssl" ]; then
537+
# OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet.
538+
echo "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
539+
elif [ "$1" = "gnutls" ]; then
540+
# GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't.
541+
# Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order.
542+
echo "SECURE128:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM"
543+
fi
544+
}
545+
444546
main "$@" || exit 1

0 commit comments

Comments
 (0)