diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index 0c17e6fd5..ec12c3f7d 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -715,6 +715,7 @@ runtests runtime Ruslan rustc +Rustls rustls Sagula SanDisk diff --git a/CMakeLists.txt b/CMakeLists.txt index 67c1e24b3..4bc7681f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ # HAVE_OPENSSL_SRP: `SSL_CTX_set_srp_username` present in OpenSSL/wolfSSL # HAVE_GNUTLS_SRP: `gnutls_srp_verifier` present in GnuTLS # HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL/wolfSSL -# HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in QUICHE +# HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in quiche # HAVE_ECH: ECH API checks for OpenSSL, BoringSSL or wolfSSL # # For each of the above variables, if the variable is DEFINED (either @@ -465,7 +465,7 @@ cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_EN cmake_dependent_option(CURL_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF) cmake_dependent_option(CURL_USE_WOLFSSL "Enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF) cmake_dependent_option(CURL_USE_GNUTLS "Enable GnuTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF) -cmake_dependent_option(CURL_USE_RUSTLS "Enable rustls for SSL/TLS" OFF CURL_ENABLE_SSL OFF) +cmake_dependent_option(CURL_USE_RUSTLS "Enable Rustls for SSL/TLS" OFF CURL_ENABLE_SSL OFF) set(_openssl_default ON) if(WIN32 OR CURL_USE_SECTRANSP OR CURL_USE_SCHANNEL OR CURL_USE_MBEDTLS OR CURL_USE_WOLFSSL) diff --git a/configure.ac b/configure.ac index 61e5872bc..da636b446 100644 --- a/configure.ac +++ b/configure.ac @@ -293,7 +293,7 @@ AS_HELP_STRING([--with-bearssl=PATH],[where to look for BearSSL, PATH points to OPT_RUSTLS=no AC_ARG_WITH(rustls,dnl -AS_HELP_STRING([--with-rustls=PATH],[where to look for rustls, PATH points to the installation root]),[ +AS_HELP_STRING([--with-rustls=PATH],[where to look for Rustls, PATH points to the installation root]),[ OPT_RUSTLS=$withval if test X"$withval" != Xno; then TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }rustls" diff --git a/docs/EXPERIMENTAL.md b/docs/EXPERIMENTAL.md index 23be5a5c3..670e19156 100644 --- a/docs/EXPERIMENTAL.md +++ b/docs/EXPERIMENTAL.md @@ -49,7 +49,7 @@ Graduation requirements: - Using HTTP/3 with the given build should perform without risking busy-loops -### The rustls backend +### The Rustls backend Graduation requirements: diff --git a/docs/HISTORY.md b/docs/HISTORY.md index 2e7ea8680..0ec3cd159 100644 --- a/docs/HISTORY.md +++ b/docs/HISTORY.md @@ -419,7 +419,7 @@ April: added the cyassl backend (later renamed to wolfSSL) February 3: curl 7.75.0 ships with support for Hyper as an HTTP backend - March 31: curl 7.76.0 ships with support for rustls + March 31: curl 7.76.0 ships with support for Rustls July: HSTS is supported diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 1f8adff82..e5dd6efd2 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -16,7 +16,7 @@ problems may have been fixed or changed somewhat since this was written. 1.5 Expect-100 meets 417 2. TLS - 2.1 IMAPS connection fails with rustls error + 2.1 IMAPS connection fails with Rustls error 2.3 Unable to use PKCS12 certificate with Secure Transport 2.4 Secure Transport does not import PKCS#12 client certificates without a password 2.5 Client cert handling with Issuer DN differs between backends @@ -143,7 +143,7 @@ problems may have been fixed or changed somewhat since this was written. 2. TLS -2.1 IMAPS connection fails with rustls error +2.1 IMAPS connection fails with Rustls error https://github.com/curl/curl/issues/10457 diff --git a/docs/RUSTLS.md b/docs/RUSTLS.md index cf32afc5e..a4196410c 100644 --- a/docs/RUSTLS.md +++ b/docs/RUSTLS.md @@ -11,7 +11,7 @@ be built to use it as an alternative to OpenSSL or other TLS backends. We use the [rustls-ffi C bindings](https://github.com/rustls/rustls-ffi/). This version of curl depends on version v0.13.0 of rustls-ffi. -# Building with rustls +# Building with Rustls First, [install Rust](https://rustup.rs/). @@ -22,7 +22,7 @@ Next, check out, build, and install the appropriate version of rustls-ffi: % make % make DESTDIR=${HOME}/rustls-ffi-built/ install -Now configure and build curl with rustls: +Now configure and build curl with Rustls: % git clone https://github.com/curl/curl % cd curl diff --git a/docs/cmdline-opts/proxy.md b/docs/cmdline-opts/proxy.md index 51f638c67..529d3369f 100644 --- a/docs/cmdline-opts/proxy.md +++ b/docs/cmdline-opts/proxy.md @@ -28,7 +28,7 @@ Unix domain sockets are supported for socks proxy. Set localhost for the host part. e.g. socks5h://localhost/path/to/socket.sock HTTPS proxy support works set with the https:// protocol prefix for OpenSSL -and GnuTLS (added in 7.52.0). It also works for BearSSL, mbedTLS, rustls, +and GnuTLS (added in 7.52.0). It also works for BearSSL, mbedTLS, Rustls, Schannel, Secure Transport and wolfSSL (added in 7.87.0). Unrecognized and unsupported proxy protocols cause an error (added in 7.52.0). diff --git a/docs/libcurl/libcurl-env.md b/docs/libcurl/libcurl-env.md index bf5624f3c..70b41d12d 100644 --- a/docs/libcurl/libcurl-env.md +++ b/docs/libcurl/libcurl-env.md @@ -52,7 +52,7 @@ this variable's selection is used. Setting a name that is not a built-in alternative makes libcurl stay with the default. SSL backend names (case-insensitive): BearSSL, GnuTLS, mbedTLS, -nss, OpenSSL, rustls, Schannel, Secure-Transport, wolfSSL +nss, OpenSSL, Rustls, Schannel, Secure-Transport, wolfSSL ## `HOME` diff --git a/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md b/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md index efb071737..39b1f9873 100644 --- a/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md +++ b/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md @@ -82,7 +82,7 @@ int main(void) # HISTORY This option is supported by the BearSSL (since 7.79.0), mbedTLS (since -7.81.0), rustls (since 7.82.0), wolfSSL (since 8.2.0), OpenSSL, Secure +7.81.0), Rustls (since 7.82.0), wolfSSL (since 8.2.0), OpenSSL, Secure Transport and Schannel backends. # %AVAILABILITY% diff --git a/docs/libcurl/opts/CURLOPT_PROXY.md b/docs/libcurl/opts/CURLOPT_PROXY.md index abc42d7f1..3611a6264 100644 --- a/docs/libcurl/opts/CURLOPT_PROXY.md +++ b/docs/libcurl/opts/CURLOPT_PROXY.md @@ -48,7 +48,7 @@ HTTP Proxy. Default when no scheme or proxy type is specified. ## https:// HTTPS Proxy. (Added in 7.52.0 for OpenSSL and GnuTLS Since 7.87.0, it -also works for BearSSL, mbedTLS, rustls, Schannel, Secure Transport and +also works for BearSSL, mbedTLS, Rustls, Schannel, Secure Transport and wolfSSL.) This uses HTTP/1 by default. Setting CURLOPT_PROXYTYPE(3) to diff --git a/docs/libcurl/opts/CURLOPT_PROXYTYPE.md b/docs/libcurl/opts/CURLOPT_PROXYTYPE.md index dafd99603..15aa2f845 100644 --- a/docs/libcurl/opts/CURLOPT_PROXYTYPE.md +++ b/docs/libcurl/opts/CURLOPT_PROXYTYPE.md @@ -35,7 +35,7 @@ HTTP Proxy. Default. ## CURLPROXY_HTTPS HTTPS Proxy using HTTP/1. (Added in 7.52.0 for OpenSSL and GnuTLS. Since -7.87.0, it also works for BearSSL, mbedTLS, rustls, Schannel, Secure Transport +7.87.0, it also works for BearSSL, mbedTLS, Rustls, Schannel, Secure Transport and wolfSSL.) ## CURLPROXY_HTTPS2 diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md index 5e4c2fa9e..7c6e57915 100644 --- a/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md @@ -91,7 +91,7 @@ int main(void) OpenSSL support added in 7.52.0. wolfSSL, Schannel, Secure Transport, and BearSSL support added in 7.87.0 mbedTLS support added in 8.8.0. -rustls support added in 8.10.0. +Rustls support added in 8.10.0. Since curl 8.10.0 returns CURLE_NOT_BUILT_IN when not supported. diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md b/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md index 5567f2dfd..4ded737b5 100644 --- a/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md +++ b/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md @@ -85,7 +85,7 @@ Schannel support added in 7.87.0. LibreSSL support added in 8.3.0, available when built with LibreSSL \>= 3.4.1. wolfSSL support added in 8.10.0. mbedTLS support added in 8.10.0, available when built with mbedTLS \>= 3.6.0. -rustls support added in 8.10.0. +Rustls support added in 8.10.0. Before curl 8.10.0 with mbedTLS or wolfSSL, TLS 1.3 cipher suites where set by using the CURLOPT_PROXY_SSL_CIPHER_LIST(3) option. diff --git a/docs/libcurl/opts/CURLOPT_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_SSLVERSION.md index 9ac0bc751..fd05eb416 100644 --- a/docs/libcurl/opts/CURLOPT_SSLVERSION.md +++ b/docs/libcurl/opts/CURLOPT_SSLVERSION.md @@ -148,7 +148,7 @@ Since 8.10.0 wolfSSL is fully supported. Before 8.10.0 the MAX macros were not supported with wolfSSL and the other macros did not set a minimum, but restricted the TLS version to only the specified one. -rustls support added in 8.10.0. +Rustls support added in 8.10.0. # %AVAILABILITY% diff --git a/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md b/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md index 97561e793..495c6e92e 100644 --- a/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md +++ b/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md @@ -92,7 +92,7 @@ Schannel support added in 7.61.0. Secure Transport support added in 7.77.0. BearSSL support added in 7.83.0. mbedTLS support added in 8.8.0. -rustls support added in 8.10.0. +Rustls support added in 8.10.0. Since curl 8.10.0 returns CURLE_NOT_BUILT_IN when not supported. diff --git a/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md b/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md index a2543d270..cc15dea0f 100644 --- a/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md +++ b/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md @@ -85,7 +85,7 @@ Schannel support added in 7.85.0. LibreSSL support added in 8.3.0, available when built with LibreSSL \>= 3.4.1. wolfSSL support added in 8.10.0. mbedTLS support added in 8.10.0, available when built with mbedTLS \>= 3.6.0. -rustls support added in 8.10.0. +Rustls support added in 8.10.0. Before curl 8.10.0 with mbedTLS or wolfSSL, TLS 1.3 cipher suites where set by using the CURLOPT_SSL_CIPHER_LIST(3) option. diff --git a/lib/config-os400.h b/lib/config-os400.h index ec83be923..d5a527e70 100644 --- a/lib/config-os400.h +++ b/lib/config-os400.h @@ -232,7 +232,7 @@ /* Define if you have the ANSI C header files. */ #define STDC_HEADERS -/* Define to enable HTTP3 support (experimental, requires NGTCP2, QUICHE or +/* Define to enable HTTP3 support (experimental, requires NGTCP2, quiche or MSH3) */ #undef USE_HTTP3 diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 80a4e03a7..984727fdd 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -689,7 +689,7 @@ ${SIZEOF_TIME_T_CODE} /* if BearSSL is enabled */ #cmakedefine USE_BEARSSL 1 -/* if rustls is enabled */ +/* if Rustls is enabled */ #cmakedefine USE_RUSTLS 1 /* if wolfSSL is enabled */ diff --git a/lib/curl_sha512_256.c b/lib/curl_sha512_256.c index 35791a07d..576eda244 100644 --- a/lib/curl_sha512_256.c +++ b/lib/curl_sha512_256.c @@ -37,7 +37,7 @@ * * SecureTransport (Darwin) * * mbedTLS * * BearSSL - * * rustls + * * Rustls * Skip the backend if it does not support the required algorithm */ #if defined(USE_OPENSSL) diff --git a/lib/rand.c b/lib/rand.c index 8dd778d17..44984f29e 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -192,7 +192,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd, * 'rnd' points to. * * If libcurl is built without TLS support or with a TLS backend that lacks a - * proper random API (rustls or mbedTLS), this function will use "weak" + * proper random API (Rustls or mbedTLS), this function will use "weak" * random. * * When built *with* TLS support and a backend that offers strong random, it diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index c8a6810df..96cd8dfa5 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -176,14 +176,14 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf, /* * On each run: - * - Read a chunk of bytes from the socket into rustls' TLS input buffer. - * - Tell rustls to process any new packets. - * - Read out as many plaintext bytes from rustls as possible, until hitting + * - Read a chunk of bytes from the socket into Rustls' TLS input buffer. + * - Tell Rustls to process any new packets. + * - Read out as many plaintext bytes from Rustls as possible, until hitting * error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up. * * it is okay to call this function with plainbuf == NULL and plainlen == 0. In - * that case, it will copy bytes from the socket into rustls' TLS input - * buffer, and process packets, but will not consume bytes from rustls' + * that case, it will copy bytes from the socket into Rustls' TLS input + * buffer, and process packets, but will not consume bytes from Rustls' * plaintext output buffer. */ static ssize_t @@ -307,13 +307,13 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data, /* * On each call: - * - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0). - * - Fully drain rustls' plaintext output buffer into the socket until + * - Copy `plainlen` bytes into Rustls' plaintext input buffer (if > 0). + * - Fully drain Rustls' plaintext output buffer into the socket until * we get either an error or EAGAIN/EWOULDBLOCK. * * it is okay to call this function with plainbuf == NULL and plainlen == 0. - * In that case, it will not read anything into rustls' plaintext input buffer. - * It will only drain rustls' plaintext output buffer into the socket. + * In that case, it will not read anything into Rustls' plaintext input buffer. + * It will only drain Rustls' plaintext output buffer into the socket. */ static ssize_t cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -358,7 +358,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, } if(blen > 0) { - CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to rustls", blen); + CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to Rustls", blen); rresult = rustls_connection_write(rconn, buf, blen, &plainwritten); if(rresult != RUSTLS_RESULT_OK) { rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); @@ -377,9 +377,9 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, if(*err) { if(CURLE_AGAIN == *err) { /* The TLS bytes may have been partially written, but we fail the - * complete send() and remember how much we already added to rustls. */ + * complete send() and remember how much we already added to Rustls. */ CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain" - " bytes already to rustls", blen); + " bytes already to Rustls", blen); backend->plain_out_buffered = plainwritten; if(nwritten) { *err = CURLE_OK; @@ -396,7 +396,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, return nwritten; } -/* A server certificate verify callback for rustls that always returns +/* A server certificate verify callback for Rustls that always returns RUSTLS_RESULT_OK, or in other words disable certificate verification. */ static uint32_t cr_verify_none(void *userdata UNUSED_PARAM, @@ -788,12 +788,12 @@ cr_connect_common(struct Curl_cfilter *cf, /* Read/write data until the handshake is done or the socket would block. */ for(;;) { /* - * Connection has been established according to rustls. Set send/recv + * Connection has been established according to Rustls. Set send/recv * handlers, and update the state machine. */ connssl->io_need = CURL_SSL_IO_NEED_NONE; if(!rustls_connection_is_handshaking(rconn)) { - /* rustls claims it is no longer handshaking *before* it has + /* Rustls claims it is no longer handshaking *before* it has * send its FINISHED message off. We attempt to let it write * one more time. Oh my. */ @@ -855,7 +855,7 @@ cr_connect_common(struct Curl_cfilter *cf, return CURLE_SSL_CONNECT_ERROR; } if(blocking && 0 == what) { - failf(data, "rustls connection timeout after %" + failf(data, "rustls: connection timeout after %" CURL_FORMAT_TIMEDIFF_T " ms", socket_check_timeout); return CURLE_OPERATION_TIMEDOUT; } diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h index 8d6df4694..7f32e8c38 100644 --- a/lib/vtls/vtls_int.h +++ b/lib/vtls/vtls_int.h @@ -225,7 +225,7 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, #include "sectransp.h" /* SecureTransport (Darwin) version */ #include "mbedtls.h" /* mbedTLS versions */ #include "bearssl.h" /* BearSSL versions */ -#include "rustls.h" /* rustls versions */ +#include "rustls.h" /* Rustls versions */ #endif /* USE_SSL */ diff --git a/m4/curl-rustls.m4 b/m4/curl-rustls.m4 index c9f9caedd..dc47d4d9f 100644 --- a/m4/curl-rustls.m4 +++ b/m4/curl-rustls.m4 @@ -24,7 +24,7 @@ AC_DEFUN([CURL_WITH_RUSTLS], [ dnl ---------------------------------------------------- -dnl check for rustls +dnl check for Rustls dnl ---------------------------------------------------- if test "x$OPT_RUSTLS" != xno; then @@ -90,14 +90,14 @@ if test "x$OPT_RUSTLS" != xno; then AC_CHECK_LIB(rustls, rustls_connection_read, [ - AC_DEFINE(USE_RUSTLS, 1, [if rustls is enabled]) + AC_DEFINE(USE_RUSTLS, 1, [if Rustls is enabled]) AC_SUBST(USE_RUSTLS, [1]) RUSTLS_ENABLED=1 USE_RUSTLS="yes" ssl_msg="rustls" test rustls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes ], - AC_MSG_ERROR([--with-rustls was specified but could not find rustls.]), + AC_MSG_ERROR([--with-rustls was specified but could not find Rustls.]), -lpthread -ldl -lm) LIB_RUSTLS="$PREFIX_RUSTLS/lib$libsuff" @@ -138,18 +138,18 @@ if test "x$OPT_RUSTLS" != xno; then dnl don't need any. LIBS="$SSL_LIBS $LIBS" ssl_msg="rustls" - AC_DEFINE(USE_RUSTLS, 1, [if rustls is enabled]) + AC_DEFINE(USE_RUSTLS, 1, [if Rustls is enabled]) AC_SUBST(USE_RUSTLS, [1]) USE_RUSTLS="yes" RUSTLS_ENABLED=1 test rustls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes else - AC_MSG_ERROR([pkg-config: Could not find rustls]) + AC_MSG_ERROR([pkg-config: Could not find Rustls]) fi else dnl we did not use pkg-config, so we need to add the - dnl rustls lib to LIBS + dnl Rustls lib to LIBS LIBS="-lrustls -lpthread -ldl -lm $LIBS" fi @@ -158,7 +158,7 @@ if test "x$OPT_RUSTLS" != xno; then LDFLAGS="$CLAN_LDFLAGS $SSL_LDFLAGS" if test "x$USE_RUSTLS" = "xyes"; then - AC_MSG_NOTICE([detected rustls]) + AC_MSG_NOTICE([detected Rustls]) check_for_ca_bundle=1 if test -n "$LIB_RUSTLS"; then diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index d4431d414..6f76852eb 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -79,7 +79,7 @@ class TestSSLUse: if tls_max == '1.3': exp_resumed = 'Initial' # 1.2 works in wolfSSL, but 1.3 does not, TODO if env.curl_uses_lib('rustls-ffi'): - exp_resumed = 'Initial' # rustls does not support sessions, TODO + exp_resumed = 'Initial' # Rustls does not support sessions, TODO if env.curl_uses_lib('bearssl') and tls_max == '1.3': pytest.skip('BearSSL does not support TLSv1.3') if env.curl_uses_lib('mbedtls') and tls_max == '1.3': @@ -140,7 +140,7 @@ class TestSSLUse: if proto != 'h3': # we proxy h3 assert r.json['SSL_TLS_SNI'] == env.domain1, f'{r.json}' assert False, f'should not have succeeded: {r.json}' - # 7 - rustls rejects a servername with .. during setup + # 7 - Rustls rejects a servername with .. during setup # 35 - LibreSSL rejects setting an SNI name with trailing dot # 60 - peer name matching failed against certificate assert r.exit_code in [7, 35, 60], f'{r}'