From: Yedaya Katsman Date: Wed, 1 Jan 2025 19:14:49 +0000 (+0200) Subject: rustls: use client cert and key if available X-Git-Tag: curl-8_13_0~52 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1c8c93ae15c692c547e3238c4f067f76616a53e8;p=thirdparty%2Fcurl.git rustls: use client cert and key if available --- diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 3d5d573c04..11c9a3a662 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -811,6 +811,84 @@ init_config_builder_keylog(struct Curl_easy *data, return CURLE_OK; } +static CURLcode +init_config_builder_client_auth(struct Curl_easy *data, + const struct ssl_primary_config *conn_config, + const struct ssl_config_data *ssl_config, + struct rustls_client_config_builder *builder) +{ + struct dynbuf cert_contents; + struct dynbuf key_contents; + rustls_result rr; + const struct rustls_certified_key *certified_key = NULL; + CURLcode result = CURLE_OK; + + if(conn_config->clientcert && !ssl_config->key) { + failf(data, "rustls: must provide key with certificate '%s'", + conn_config->clientcert); + return CURLE_SSL_CERTPROBLEM; + } + else if(!conn_config->clientcert && ssl_config->key) { + failf(data, "rustls: must provide certificate with key '%s'", + conn_config->clientcert); + return CURLE_SSL_CERTPROBLEM; + } + + Curl_dyn_init(&cert_contents, SIZE_MAX); + Curl_dyn_init(&key_contents, SIZE_MAX); + + if(!read_file_into(conn_config->clientcert, &cert_contents)) { + failf(data, "rustls: failed to read client certificate file: '%s'", + conn_config->clientcert); + result = CURLE_SSL_CERTPROBLEM; + goto cleanup; + } + + if(!read_file_into(ssl_config->key, &key_contents)) { + failf(data, "rustls: failed to read key file: '%s'", ssl_config->key); + result = CURLE_SSL_CERTPROBLEM; + goto cleanup; + } + + rr = rustls_certified_key_build(Curl_dyn_uptr(&cert_contents), + Curl_dyn_len(&cert_contents), + Curl_dyn_uptr(&key_contents), + Curl_dyn_len(&key_contents), + &certified_key); + if(rr != RUSTLS_RESULT_OK) { + rustls_failf(data, rr, "rustls: failed to build certified key"); + result = CURLE_SSL_CERTPROBLEM; + goto cleanup; + } + + rr = rustls_certified_key_keys_match(certified_key); + if(rr != RUSTLS_RESULT_OK) { + rustls_failf(data, + rr, + "rustls: client certificate and keypair files do not match:"); + + result = CURLE_SSL_CERTPROBLEM; + goto cleanup; + } + + rr = rustls_client_config_builder_set_certified_key(builder, + &certified_key, + 1); + if(rr != RUSTLS_RESULT_OK) { + rustls_failf(data, rr, "rustls: failed to set certified key"); + result = CURLE_SSL_CERTPROBLEM; + goto cleanup; + } + +cleanup: + Curl_dyn_free(&cert_contents); + Curl_dyn_free(&key_contents); + if(certified_key) { + rustls_certified_key_free(certified_key); + } + return result; +} + static CURLcode cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, struct rustls_ssl_backend_data *const backend) @@ -818,6 +896,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, const struct ssl_connect_data *connssl = cf->ctx; const struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); struct rustls_connection *rconn = NULL; struct rustls_client_config_builder *config_builder = NULL; @@ -856,6 +935,17 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, } } + if(conn_config->clientcert || ssl_config->key) { + result = init_config_builder_client_auth(data, + conn_config, + ssl_config, + config_builder); + if(result != CURLE_OK) { + rustls_client_config_builder_free(config_builder); + return result; + } + } + result = init_config_builder_keylog(data, config_builder); if(result != CURLE_OK) { rustls_client_config_builder_free(config_builder);