]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
rustls: add CURLOPT_CAINFO_BLOB support
authorStephen M. Coakley <me@stephencoakley.com>
Sun, 9 Jan 2022 21:59:30 +0000 (15:59 -0600)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 10 Jan 2022 08:30:12 +0000 (09:30 +0100)
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

docs/libcurl/opts/CURLOPT_CAINFO_BLOB.3
docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.3
lib/vtls/rustls.c

index 777b2e33698fc308846c82ab092793f63b910707..deae4ee069849dc17360dcfc62f2653fc0c4770f 100644 (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.
index df6ebe16f49b131bbc2aef71fb791ed193baa2f3..a85552e56677ad386181682de35213d5ebde60e7 100644 (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
index 6dbb1ef3cd7ba8f6b75f9ad74e633737ad66438d..51230b196705aa9df3a9142ce5553310ad23fdb9 100644 (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 */