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

@ -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 */