rustls: add CURLOPT_CAINFO_BLOB support

Add support for `CURLOPT_CAINFO_BLOB` `CURLOPT_PROXY_CAINFO_BLOB` to the
rustls TLS backend. Multiple certificates in a single PEM string are
supported just like OpenSSL does with this option.

This is compatible at least with rustls-ffi 0.8+ which is our new
minimum version anyway.

I was able to build and run this on Windows, pulling trusted certs from
the system and then add them to rustls by setting
`CURLOPT_CAINFO_BLOB`. Handy!

Closes #8255
This commit is contained in:
Stephen M. Coakley 2022-01-09 15:59:30 -06:00 committed by Daniel Stenberg
parent dbde76bdd6
commit 3be94d84fc
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
3 changed files with 33 additions and 5 deletions

View File

@ -62,7 +62,7 @@ if(curl) {
Added in 7.77.0.
This option is supported by the BearSSL (since 7.79.0), mbedTLS (since 7.81.0),
OpenSSL, Secure Transport and Schannel backends.
rustls (since 7.82.0), OpenSSL, Secure Transport and Schannel backends.
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.

View File

@ -65,7 +65,7 @@ if(curl) {
.SH AVAILABILITY
Added in 7.77.0.
This option is supported by the OpenSSL, Secure
This option is supported by the rustls (since 7.82.0), OpenSSL, Secure
Transport and Schannel backends.
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2020 - 2021, Jacob Hoffman-Andrews,
* Copyright (C) 2020 - 2022, Jacob Hoffman-Andrews,
* <github@hoffman-andrews.com>
*
* This software is licensed as described in the file COPYING, which
@ -297,7 +297,11 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
{
struct rustls_connection *rconn = backend->conn;
struct rustls_client_config_builder *config_builder = NULL;
const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
struct rustls_root_cert_store *roots = NULL;
const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
(ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
const char *hostname = conn->host.name;
char errorbuf[256];
@ -328,6 +332,29 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
hostname = "example.invalid";
}
}
else if(ca_info_blob) {
roots = rustls_root_cert_store_new();
/* Enable strict parsing only if verification isn't disabled. */
result = rustls_root_cert_store_add_pem(roots, ca_info_blob->data,
ca_info_blob->len, verifypeer);
if(result != RUSTLS_RESULT_OK) {
failf(data, "failed to parse trusted certificates from blob");
rustls_root_cert_store_free(roots);
rustls_client_config_free(
rustls_client_config_builder_build(config_builder));
return CURLE_SSL_CACERT_BADFILE;
}
result = rustls_client_config_builder_use_roots(config_builder, roots);
rustls_root_cert_store_free(roots);
if(result != RUSTLS_RESULT_OK) {
failf(data, "failed to load trusted certificates");
rustls_client_config_free(
rustls_client_config_builder_build(config_builder));
return CURLE_SSL_CACERT_BADFILE;
}
}
else if(ssl_cafile) {
result = rustls_client_config_builder_load_roots_from_file(
config_builder, ssl_cafile);
@ -550,7 +577,8 @@ static size_t cr_version(char *buffer, size_t size)
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_TLS13_CIPHERSUITES, /* supports */
SSLSUPP_CAINFO_BLOB | /* supports */
SSLSUPP_TLS13_CIPHERSUITES,
sizeof(struct ssl_backend_data),
Curl_none_init, /* init */