vtls/rustls: support strong CSRNG data

Now that the curl rustls vtls backend is using rustls 0.14 we can
address the weak random situation by using
`rustls_default_crypto_provider_random()` to provide a `Curl_ssl`
`random` callback that fills the provided buffer with cryptographically
secure random data.

The mentions in `docs/` about weak RNG when using rustls are removed as
they are no longer applicable.

Closes #14889
This commit is contained in:
Daniel McCarney 2024-09-12 12:38:51 -04:00 committed by Daniel Stenberg
parent 6d9b40d6a4
commit 8972845123
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
5 changed files with 27 additions and 38 deletions

View File

@ -56,7 +56,6 @@ Graduation requirements:
Graduation requirements: Graduation requirements:
- a reasonable expectation of a stable API going forward. - a reasonable expectation of a stable API going forward.
- a sufficient approach to avoid using weak random numbers
### WebSocket ### WebSocket

View File

@ -34,18 +34,3 @@ See the [rustls-ffi README] for more information on cryptography providers and
their build/platform requirements. their build/platform requirements.
[rustls-ffi README]: https://github.com/rustls/rustls-ffi/blob/main/README.md#cryptography-provide [rustls-ffi README]: https://github.com/rustls/rustls-ffi/blob/main/README.md#cryptography-provide
## Randomness
Every TLS libcurl curl supports - *except* Rustls - provides a function for
curl to extract cryptographically safe random numbers with.
When you build curl with Rustls, curl uses its own internal attempts to get a
decent random value:
1. Windows specific APIs
2. arc4random
If neither of those are present, then curl using Rustls falls back to **weak
pseudo-random values**, and thus weakening several curl authentication
implementations.

View File

@ -100,9 +100,9 @@ CURLcode Curl_win32_random(unsigned char *entropy, size_t length)
} }
#endif #endif
#if !defined(USE_SSL) || defined(USE_RUSTLS) #if !defined(USE_SSL)
/* ---- possibly non-cryptographic version following ---- */ /* ---- possibly non-cryptographic version following ---- */
CURLcode Curl_weak_random(struct Curl_easy *data, static CURLcode weak_random(struct Curl_easy *data,
unsigned char *entropy, unsigned char *entropy,
size_t length) /* always 4, size of int */ size_t length) /* always 4, size of int */
{ {
@ -151,7 +151,7 @@ CURLcode Curl_weak_random(struct Curl_easy *data,
#ifdef USE_SSL #ifdef USE_SSL
#define _random(x,y,z) Curl_ssl_random(x,y,z) #define _random(x,y,z) Curl_ssl_random(x,y,z)
#else #else
#define _random(x,y,z) Curl_weak_random(x,y,z) #define _random(x,y,z) weak_random(x,y,z)
#endif #endif
static CURLcode randit(struct Curl_easy *data, unsigned int *rnd, static CURLcode randit(struct Curl_easy *data, unsigned int *rnd,

View File

@ -36,11 +36,6 @@ CURLcode Curl_rand_bytes(struct Curl_easy *data,
#define Curl_rand(a,b,c) Curl_rand_bytes((a), (b), (c)) #define Curl_rand(a,b,c) Curl_rand_bytes((a), (b), (c))
#endif #endif
/* ---- non-cryptographic version following ---- */
CURLcode Curl_weak_random(struct Curl_easy *data,
unsigned char *rnd,
size_t length);
/* /*
* Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
* hexadecimal digits PLUS a null-terminating byte. It must be an odd number * hexadecimal digits PLUS a null-terminating byte. It must be an odd number

View File

@ -216,15 +216,15 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
} }
rresult = rustls_connection_read(rconn, rresult = rustls_connection_read(rconn,
(uint8_t *)plainbuf + plain_bytes_copied, (uint8_t *)plainbuf + plain_bytes_copied,
plainlen - plain_bytes_copied, plainlen - plain_bytes_copied,
&n); &n);
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) { if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
backend->data_in_pending = FALSE; backend->data_in_pending = FALSE;
} }
else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) { else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
failf(data, "rustls: peer closed TCP connection " failf(data, "rustls: peer closed TCP connection "
"without first closing TLS connection"); "without first closing TLS connection");
*err = CURLE_RECV_ERROR; *err = CURLE_RECV_ERROR;
nread = -1; nread = -1;
goto out; goto out;
@ -449,7 +449,7 @@ cr_get_selected_ciphers(struct Curl_easy *data,
for(j = 0; j < default_len; j++) { for(j = 0; j < default_len; j++) {
entry = rustls_default_crypto_provider_ciphersuites_get(j); entry = rustls_default_crypto_provider_ciphersuites_get(j);
if(rustls_supported_ciphersuite_protocol_version(entry) != if(rustls_supported_ciphersuite_protocol_version(entry) !=
RUSTLS_TLS_VERSION_TLSV1_3) RUSTLS_TLS_VERSION_TLSV1_3)
continue; continue;
selected[count++] = entry; selected[count++] = entry;
@ -606,10 +606,10 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
} }
result = rustls_crypto_provider_builder_new_from_default( result = rustls_crypto_provider_builder_new_from_default(
&custom_provider_builder); &custom_provider_builder);
if(result != RUSTLS_RESULT_OK) { if(result != RUSTLS_RESULT_OK) {
failf(data, failf(data,
"rustls: failed to create crypto provider builder from default"); "rustls: failed to create crypto provider builder from default");
return CURLE_SSL_ENGINE_INITFAILED; return CURLE_SSL_ENGINE_INITFAILED;
} }
@ -620,9 +620,9 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
cipher_suites_len); cipher_suites_len);
if(result != RUSTLS_RESULT_OK) { if(result != RUSTLS_RESULT_OK) {
failf(data, failf(data,
"rustls: failed to set ciphersuites for crypto provider builder"); "rustls: failed to set ciphersuites for crypto provider builder");
rustls_crypto_provider_builder_free(custom_provider_builder); rustls_crypto_provider_builder_free(custom_provider_builder);
return CURLE_SSL_ENGINE_INITFAILED; return CURLE_SSL_ENGINE_INITFAILED;
} }
result = rustls_crypto_provider_builder_build( result = rustls_crypto_provider_builder_build(
@ -634,9 +634,9 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
} }
result = rustls_client_config_builder_new_custom(custom_provider, result = rustls_client_config_builder_new_custom(custom_provider,
tls_versions, tls_versions,
tls_versions_len, tls_versions_len,
&config_builder); &config_builder);
free(cipher_suites); free(cipher_suites);
if(result != RUSTLS_RESULT_OK) { if(result != RUSTLS_RESULT_OK) {
failf(data, "rustls: failed to create client config"); failf(data, "rustls: failed to create client config");
@ -1056,6 +1056,16 @@ static size_t cr_version(char *buffer, size_t size)
return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data); return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
} }
static CURLcode
cr_random(struct Curl_easy *data, unsigned char *entropy, size_t length)
{
rustls_result rresult = 0;
(void)data;
rresult =
rustls_default_crypto_provider_random(entropy, length);
return map_error(rresult);
}
const struct Curl_ssl Curl_ssl_rustls = { const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" }, { CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */ SSLSUPP_CAINFO_BLOB | /* supports */
@ -1070,7 +1080,7 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_check_cxn, /* check_cxn */ Curl_none_check_cxn, /* check_cxn */
cr_shutdown, /* shutdown */ cr_shutdown, /* shutdown */
cr_data_pending, /* data_pending */ cr_data_pending, /* data_pending */
Curl_weak_random, /* random */ cr_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */ Curl_none_cert_status_request, /* cert_status_request */
cr_connect_blocking, /* connect */ cr_connect_blocking, /* connect */
cr_connect_nonblocking, /* connect_nonblocking */ cr_connect_nonblocking, /* connect_nonblocking */