Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force strong TLS cipher suite in rustup-init.sh for curl and wget if support is detected #2287

Merged
merged 1 commit into from
Apr 22, 2020

Conversation

x448
Copy link
Contributor

@x448 x448 commented Apr 17, 2020

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 is identical for OpenSSL (to Firefox) and slightly different for GnuTLS.

(click to expand) 📷 SSL Client Test for Firefox with Strong TLS 1.2-1.3 Cipher Suites

image

Status

  • test dl from server with only strong cipher suites
  • test dl from server with only weak cipher suites
  • test dl from server preferring weak cipher suites before strong cipher suites
  • commit tested changes to rustup-init.sh
  • make it automatic based on local tools rather than based on flag per feedback from @kinnison
    • detect if curl TLS backend is OpenSSL-compatible version and supports TLS 1.2
      • OpenSSL (Fedora, OpenSUSE)
      • GnuTLS (implemented but not tested with curl)
      • LibreSSL (macOS 10.14)
      • BoringSSL (implemented but not tested with curl)
    • detect if wget TLS backend is OpenSSL version that supports TLS 1.2
      • OpenSSL (OpenSUSE)
      • GnuTLS (Fedora)
      • LibreSSL (implemented but not tested with wget)
      • BoringSSL (implemented but not tested with wget)
    • undo -s, --strong-tls flag to make it automatic if local tools support it
  • allow user to specify RUSTUP_TLS_CIPHERSUITES (empty by default), force strong TLS if empty and supported by local tools. This replaces RUSTUP_STRONG_TLS_CS variable.
  • limited testing on Fedora and OpenSUSE client to nginx server
  • fix unbound var error on Centos 6, then retest on Fedora and OpenSUSE
  • wget+GnuTLS compatibility with old systems appear good enough (tested on Fedora 30 and doesn't break CI tests on other platforms)

Detection of local tools other than OpenSSL or GnuTLS is out of scope due to time required for all possible combinations (NSS, Schannel, WolfSSL, etc.).

Special thanks to @kinnison for his excellent feedback and suggestions.

Details

Tests used nginx server configured for TLS 1.2.

If local tools support it, make curl and wget require TLS 1.3 + TLS 1.2 with strong cipher suites specified in RUSTUP_STRONG_TLS_CS.

RUSTUP_STRONG_TLS_CS can be overridden by the user if they need to specify syntax other than OpenSSL/LibreSSL/BoringSSL such as NSS, Schannel, WolfSSL, etc.

(click to expand) More details

Strong cipher suite list defaults to:

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

The first 3 cipher suites are TLS 1.3. The remaining are TLS 1.2
cipher suites limited to ECDHE key exchange + AEAD cipher.

DHE is disabled for TLS 1.2 due to frequent misconfiguration on
servers such as not specifying 2048-bit or stronger DH group with
safe primes (see RFC 7919).

The OpenSSL syntax was chosen for cipher suites because:

  • most Linux distros and *BSD use OpenSSL, LibreSSL, or BoringSSL.
  • official curl binary for Windows uses OpenSSL 1.1.1f static linked.
  • homebrew and macports provide curl+OpenSSL for Mac.

RUSTUP_TLS_CIPHERSUITES can be specified by user with any syntax.

@x448
Copy link
Contributor Author

x448 commented Apr 18, 2020

Hi @kinnison, the MR has been updated to incorporate your last comment on #2284 . Please let me know if you have additional feedback or suggestions.

Your last comment on #2284 was helpful and much appreciated.

@x448 x448 changed the title Add strong TLS ciphers option to rustup-init.sh Force strong TLS cipher suite in rustup-init.sh for curl and wget if support is detected Apr 18, 2020
@x448
Copy link
Contributor Author

x448 commented Apr 19, 2020

If we get rid of the new variable RUSTUP_STRONG_TLS_CS and make it a private string, then I can more easily add support for GnuTLS, in addition to OpenSSL/LibreSSL/BoringSSL.

For wget (untested example):

get_wget_cipher_suites() {
    local _cs
    local _openssl_cs="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"
    local _gnutls_cs="TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_AES_128_GCM_SHA256:TLS_ECDHE_RSA_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_CHACHA20_POLY1305:TLS_ECDHE_RSA_CHACHA20_POLY1305:TLS_ECDHE_ECDSA_AES_256_GCM_SHA384:TLS_ECDHE_RSA_AES_256_GCM_SHA384"

    if wget -V | grep -q '\-DHAVE_LIBSSL'; then
        # "unspecified" is for arch, we allow for possibility of users on old OS using macports, homebrew, etc.
        if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
            _cs="$_openssl_cs"
        fi
    elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then
        # "unspecified" is for arch, we allow for possibility of users on old OS using macports, homebrew, etc.
        if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
            _cs="$_gnutls_cs"
        fi
    fi

    RETVAL="$_cs"
}

The strong cipher suites match what is used by Firefox 68 ESR with all weak cipher suites disabled using about:config.

(click to expand) 📷 SSL Client Test for Firefox with Strong TLS 1.2-1.3 Cipher Suites

image

@kinnison
Copy link
Contributor

What I'd suggest is that the default for the variable should be the empty string. If the user sets it non-empty then we use that, otherwise we attempt to detect the correct set by looking for gnutls vs. openssl.

@x448
Copy link
Contributor Author

x448 commented Apr 19, 2020

I need to redo the GnuTLS cipher suite string (aka priority string).

@x448
Copy link
Contributor Author

x448 commented Apr 20, 2020

Unlike OpenSSL, GnuTLS doesn't seem as forgiving of unknown values in the cipher suites list. So I didn't bother with removing/adding SIGN or GROUP categories.

This GnuTLS priority string isn't exactly in the same sequence as OpenSSL's cipher suite but it's close enough:

Cipher suites for SECURE128:-VERS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+VERS-TLS1.3:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM
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

Protocols: VERS-TLS1.3, VERS-TLS1.2
Ciphers: AES-128-GCM, CHACHA20-POLY1305, AES-256-GCM
MACs: AEAD
Key Exchange Algorithms: ECDHE-ECDSA, ECDHE-RSA
Groups: GROUP-SECP256R1, GROUP-SECP384R1, GROUP-SECP521R1, GROUP-X25519, GROUP-FFDHE2048, GROUP-FFDHE3072, GROUP-FFDHE4096, GROUP-FFDHE6144, GROUP-FFDHE8192
PK-signatures: SIGN-RSA-SHA256, SIGN-RSA-PSS-SHA256, SIGN-RSA-PSS-RSAE-SHA256, SIGN-ECDSA-SHA256, SIGN-ECDSA-SECP256R1-SHA256, SIGN-EdDSA-Ed25519, SIGN-RSA-SHA384, SIGN-RSA-PSS-SHA384, SIGN-RSA-PSS-RSAE-SHA384, SIGN-ECDSA-SHA384, SIGN-ECDSA-SECP384R1-SHA384, SIGN-RSA-SHA512, SIGN-RSA-PSS-SHA512, SIGN-RSA-PSS-RSAE-SHA512, SIGN-ECDSA-SHA512, SIGN-ECDSA-SECP521R1-SHA512

@x448
Copy link
Contributor Author

x448 commented Apr 20, 2020

@kinnison the MR was updated to incorporate your suggestion. Please let me know if it works for you. I tested on Fedora 30 and OpenSUSE Leap 15.1 clients with an nginx server logging which cipher suite was used for download.

Also, I updated GnuTLS priority string to enable TLS 1.3 (if supported) without explicitly specifying it. This may improve potential compatibility issues on older systems using wget+gnutls. The resulting cipher suites and TLS versions remain the same. The ordering is slightly different from OpenSSL but not bad enough to devote more time.

Cipher suites for 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
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

Protocols: VERS-TLS1.3, VERS-TLS1.2
Ciphers: AES-128-GCM, CHACHA20-POLY1305, AES-256-GCM
MACs: AEAD
Key Exchange Algorithms: ECDHE-ECDSA, ECDHE-RSA
...

Copy link
Contributor

@kinnison kinnison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks excellent thank you for your efforts.

I've been through the checks and they look good. My only concern is that macos builders seem to be skipping strong cipher suites.

If you expected this then that's fine, otherwise it may be worth popping some debugging into it and looking at the macos builder behaviour. Sadly I do not have a mac so cannot help you determine if this is expected on our builder or not.

Once you let me know your intent with the macos side of things, if it's to wait and see, I'll merge.

@x448
Copy link
Contributor Author

x448 commented Apr 21, 2020

Great catch on the macOS! I'll investigate on macOS 10.14 and let you know what I find within 2 days (hopefully sooner).

@x448
Copy link
Contributor Author

x448 commented Apr 21, 2020

@kinnison good news, strong cipher suites are detected and used on macOS 10.14 with /usr/bin/curl (Sep 20, 2019 timestamp and LibreSSL).

Thanks again for your excellent suggestions and feedback.

Please squash+merge if you'd like. Proposed squashed commit msg:

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.

@kinnison
Copy link
Contributor

Could you please do the squash etc, so that I'm merging your commit? I'm not in a position to do that right now because I'm at work, but I can push buttons on github :D

@x448
Copy link
Contributor Author

x448 commented Apr 21, 2020

@kinnison yes, I'll be happy to use git to squash tonight if needed.

I was limiting my GitHub activities to a browser, but my concerns about git vs browser privacy were mostly addressed (a 3rd-party's language about GitHub activity data collection caused confusion).

BTW, GitHub added a repository setting to provide "Squash & Merge" button you can use from a web browser by clicking on the down arrow portion of the normal "Merge" button.

https://help.github.com/en/github/administering-a-repository/configuring-commit-squashing-for-pull-requests

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 rust-lang#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.
@x448
Copy link
Contributor Author

x448 commented Apr 21, 2020

@kinnison MR is squashed and ready to merge, no other changes to the script. 🎉

b2sum of new rustup-init.sh:

726ff184dc8358847d6bc145a489fd2aea029cda6876e1ea87bf840f4d73d0665974c3891b74cd4ee13c6814e8705e7604ce02381a0685338dac3b5e0d61fbcf

@kinnison kinnison added this to the 1.22.0 milestone Apr 22, 2020
@kinnison kinnison merged commit c022b92 into rust-lang:master Apr 22, 2020
AJ-Ianozi pushed a commit to AJ-Ianozi/getada-download that referenced this pull request Oct 12, 2023
Force strong TLS cipher suite in rustup-init.sh for curl and wget if support is detected
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants