mirror of
https://github.com/curl/curl.git
synced 2026-07-12 04:37:18 +03:00
parent
e601668154
commit
088f0e6a5b
1 changed files with 319 additions and 239 deletions
|
|
@ -8,6 +8,7 @@
|
|||
* Copyright (C) Jacob Hoffman-Andrews,
|
||||
* <github@hoffman-andrews.com>
|
||||
* Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
|
||||
* Copyright (C) Daniel McCarney, <daniel@binaryparadox.net>
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
|
|
@ -37,12 +38,8 @@
|
|||
#include "vtls.h"
|
||||
#include "vtls_int.h"
|
||||
#include "rustls.h"
|
||||
#include "select.h"
|
||||
#include "strerror.h"
|
||||
#include "multiif.h"
|
||||
#include "connect.h" /* for the connect timeout */
|
||||
#include "cipher_suite.h"
|
||||
#include "rand.h"
|
||||
#include "x509asn1.h"
|
||||
|
||||
struct rustls_ssl_backend_data
|
||||
|
|
@ -55,7 +52,7 @@ struct rustls_ssl_backend_data
|
|||
};
|
||||
|
||||
/* For a given rustls_result error code, return the best-matching CURLcode. */
|
||||
static CURLcode map_error(rustls_result r)
|
||||
static CURLcode map_error(const rustls_result r)
|
||||
{
|
||||
if(rustls_result_is_cert_error(r)) {
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
|
|
@ -70,10 +67,19 @@ static CURLcode map_error(rustls_result r)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rustls_failf(struct Curl_easy *data, const rustls_result rr, const char *msg)
|
||||
{
|
||||
char errorbuf[STRERROR_LEN];
|
||||
size_t errorlen;
|
||||
rustls_error(rr, errorbuf, sizeof(errorbuf), &errorlen);
|
||||
failf(data, "%s: %.*s", msg, (int)errorlen, errorbuf);
|
||||
}
|
||||
|
||||
static bool
|
||||
cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
const struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct rustls_ssl_backend_data *backend;
|
||||
|
||||
(void)data;
|
||||
|
|
@ -90,7 +96,7 @@ struct io_ctx {
|
|||
static int
|
||||
read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
|
||||
{
|
||||
struct io_ctx *io_ctx = userdata;
|
||||
const struct io_ctx *io_ctx = userdata;
|
||||
struct ssl_connect_data *const connssl = io_ctx->cf->ctx;
|
||||
CURLcode result;
|
||||
int ret = 0;
|
||||
|
|
@ -115,7 +121,7 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
|
|||
static int
|
||||
write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
|
||||
{
|
||||
struct io_ctx *io_ctx = userdata;
|
||||
const struct io_ctx *io_ctx = userdata;
|
||||
CURLcode result;
|
||||
int ret = 0;
|
||||
ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
|
||||
|
|
@ -137,7 +143,7 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
|
|||
static ssize_t tls_recv_more(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, CURLcode *err)
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
const struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct io_ctx io_ctx;
|
||||
|
|
@ -163,11 +169,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
|
|||
|
||||
rresult = rustls_connection_process_new_packets(backend->conn);
|
||||
if(rresult != RUSTLS_RESULT_OK) {
|
||||
char errorbuf[255];
|
||||
size_t errorlen;
|
||||
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
|
||||
failf(data, "rustls_connection_process_new_packets: %.*s",
|
||||
(int)errorlen, errorbuf);
|
||||
rustls_failf(data, rresult, "rustls_connection_process_new_packets");
|
||||
*err = map_error(rresult);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -193,7 +195,7 @@ static ssize_t
|
|||
cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *plainbuf, size_t plainlen, CURLcode *err)
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
const struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
|
|
@ -233,10 +235,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
}
|
||||
else if(rresult != RUSTLS_RESULT_OK) {
|
||||
/* n always equals 0 in this case, do not need to check it */
|
||||
char errorbuf[255];
|
||||
size_t errorlen;
|
||||
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
|
||||
failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
|
||||
rustls_failf(data, rresult, "rustls_connection_read");
|
||||
*err = CURLE_RECV_ERROR;
|
||||
nread = -1;
|
||||
goto out;
|
||||
|
|
@ -279,7 +278,6 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
rustls_io_result io_error;
|
||||
size_t tlswritten = 0;
|
||||
size_t tlswritten_total = 0;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
io_ctx.cf = cf;
|
||||
io_ctx.data = data;
|
||||
|
|
@ -305,7 +303,7 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
|
||||
tlswritten_total += tlswritten;
|
||||
}
|
||||
return result;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -322,14 +320,11 @@ static ssize_t
|
|||
cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *plainbuf, size_t plainlen, CURLcode *err)
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
const struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
size_t plainwritten = 0;
|
||||
rustls_result rresult;
|
||||
char errorbuf[256];
|
||||
size_t errorlen;
|
||||
const unsigned char *buf = plainbuf;
|
||||
size_t blen = plainlen;
|
||||
ssize_t nwritten = 0;
|
||||
|
|
@ -361,11 +356,11 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
}
|
||||
|
||||
if(blen > 0) {
|
||||
rustls_result rresult;
|
||||
CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to Rustls", blen);
|
||||
rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
|
||||
if(rresult != RUSTLS_RESULT_OK) {
|
||||
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
|
||||
failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf);
|
||||
rustls_failf(data, rresult, "rustls_connection_write");
|
||||
*err = CURLE_WRITE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -419,7 +414,7 @@ read_file_into(const char *filename,
|
|||
|
||||
while(!feof(f)) {
|
||||
uint8_t buf[256];
|
||||
size_t rr = fread(buf, 1, sizeof(buf), f);
|
||||
const size_t rr = fread(buf, 1, sizeof(buf), f);
|
||||
if(rr == 0 ||
|
||||
CURLE_OK != Curl_dyn_addn(out, buf, rr)) {
|
||||
fclose(f);
|
||||
|
|
@ -437,8 +432,8 @@ cr_get_selected_ciphers(struct Curl_easy *data,
|
|||
const struct rustls_supported_ciphersuite **selected,
|
||||
size_t *selected_size)
|
||||
{
|
||||
size_t supported_len = *selected_size;
|
||||
size_t default_len = rustls_default_crypto_provider_ciphersuites_len();
|
||||
const size_t supported_len = *selected_size;
|
||||
const size_t default_len = rustls_default_crypto_provider_ciphersuites_len();
|
||||
const struct rustls_supported_ciphersuite *entry;
|
||||
const char *ciphers = ciphers12;
|
||||
size_t count = 0, default13_count = 0, i, j;
|
||||
|
|
@ -524,246 +519,329 @@ add_ciphers:
|
|||
}
|
||||
|
||||
static CURLcode
|
||||
cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
struct rustls_ssl_backend_data *const backend)
|
||||
init_config_builder(struct Curl_easy *data,
|
||||
const struct ssl_primary_config *conn_config,
|
||||
struct rustls_client_config_builder **config_builder)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
const struct rustls_supported_ciphersuite **cipher_suites = NULL;
|
||||
struct rustls_crypto_provider_builder *custom_provider_builder = NULL;
|
||||
const struct rustls_crypto_provider *custom_provider = NULL;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
struct rustls_client_config_builder *config_builder = NULL;
|
||||
|
||||
uint16_t tls_versions[2] = {
|
||||
RUSTLS_TLS_VERSION_TLSV1_2,
|
||||
RUSTLS_TLS_VERSION_TLSV1_3,
|
||||
};
|
||||
size_t tls_versions_len = 2;
|
||||
size_t cipher_suites_len =
|
||||
rustls_default_crypto_provider_ciphersuites_len();
|
||||
|
||||
CURLcode result = CURLE_OK;
|
||||
rustls_result rr;
|
||||
|
||||
switch(conn_config->version) {
|
||||
case CURL_SSLVERSION_DEFAULT:
|
||||
case CURL_SSLVERSION_TLSv1:
|
||||
case CURL_SSLVERSION_TLSv1_0:
|
||||
case CURL_SSLVERSION_TLSv1_1:
|
||||
case CURL_SSLVERSION_TLSv1_2:
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_3:
|
||||
tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
|
||||
tls_versions_len = 1;
|
||||
break;
|
||||
default:
|
||||
failf(data, "rustls: unsupported minimum TLS version value");
|
||||
result = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
switch(conn_config->version_max) {
|
||||
case CURL_SSLVERSION_MAX_DEFAULT:
|
||||
case CURL_SSLVERSION_MAX_NONE:
|
||||
case CURL_SSLVERSION_MAX_TLSv1_3:
|
||||
break;
|
||||
case CURL_SSLVERSION_MAX_TLSv1_2:
|
||||
if(tls_versions[0] == RUSTLS_TLS_VERSION_TLSV1_2) {
|
||||
tls_versions_len = 1;
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH();
|
||||
case CURL_SSLVERSION_MAX_TLSv1_1:
|
||||
case CURL_SSLVERSION_MAX_TLSv1_0:
|
||||
default:
|
||||
failf(data, "rustls: unsupported maximum TLS version value");
|
||||
result = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len));
|
||||
if(!cipher_suites) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cr_get_selected_ciphers(data,
|
||||
conn_config->cipher_list,
|
||||
conn_config->cipher_list13,
|
||||
cipher_suites, &cipher_suites_len);
|
||||
if(cipher_suites_len == 0) {
|
||||
failf(data, "rustls: no supported cipher in list");
|
||||
result = CURLE_SSL_CIPHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rr = rustls_crypto_provider_builder_new_from_default(
|
||||
&custom_provider_builder);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr,
|
||||
"failed to create crypto provider builder from default");
|
||||
result = CURLE_SSL_CIPHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rr =
|
||||
rustls_crypto_provider_builder_set_cipher_suites(
|
||||
custom_provider_builder,
|
||||
cipher_suites,
|
||||
cipher_suites_len);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr,
|
||||
"failed to set ciphersuites for crypto provider builder");
|
||||
result = CURLE_SSL_CIPHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rr = rustls_crypto_provider_builder_build(
|
||||
custom_provider_builder, &custom_provider);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "failed to build custom crypto provider");
|
||||
result = CURLE_SSL_CIPHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rr = rustls_client_config_builder_new_custom(custom_provider,
|
||||
tls_versions,
|
||||
tls_versions_len,
|
||||
config_builder);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "failed to create client config builder");
|
||||
result = CURLE_SSL_CIPHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if(cipher_suites) {
|
||||
free(cipher_suites);
|
||||
}
|
||||
if(custom_provider_builder) {
|
||||
rustls_crypto_provider_builder_free(custom_provider_builder);
|
||||
}
|
||||
if(custom_provider) {
|
||||
rustls_crypto_provider_free(custom_provider);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
init_config_builder_alpn(struct Curl_easy *data,
|
||||
const struct ssl_connect_data *connssl,
|
||||
struct rustls_client_config_builder *config_builder) {
|
||||
struct alpn_proto_buf proto;
|
||||
rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < connssl->alpn->count; ++i) {
|
||||
alpn[i].data = (const uint8_t *)connssl->alpn->entries[i];
|
||||
alpn[i].len = strlen(connssl->alpn->entries[i]);
|
||||
}
|
||||
rustls_client_config_builder_set_alpn_protocols(config_builder, alpn,
|
||||
connssl->alpn->count);
|
||||
Curl_alpn_to_proto_str(&proto, connssl->alpn);
|
||||
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
init_config_builder_verifier_crl(
|
||||
struct Curl_easy *data,
|
||||
const struct ssl_primary_config *conn_config,
|
||||
struct rustls_web_pki_server_cert_verifier_builder *builder)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct dynbuf crl_contents;
|
||||
rustls_result rr;
|
||||
|
||||
Curl_dyn_init(&crl_contents, DYN_CRLFILE_SIZE);
|
||||
if(!read_file_into(conn_config->CRLfile, &crl_contents)) {
|
||||
failf(data, "rustls: failed to read revocation list file");
|
||||
result = CURLE_SSL_CRL_BADFILE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rr = rustls_web_pki_server_cert_verifier_builder_add_crl(
|
||||
builder,
|
||||
Curl_dyn_uptr(&crl_contents),
|
||||
Curl_dyn_len(&crl_contents));
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "failed to parse revocation list");
|
||||
result = CURLE_SSL_CRL_BADFILE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
Curl_dyn_free(&crl_contents);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
init_config_builder_verifier(struct Curl_easy *data,
|
||||
struct rustls_client_config_builder *builder,
|
||||
const struct ssl_primary_config *conn_config,
|
||||
const struct curl_blob *ca_info_blob,
|
||||
const char * const ssl_cafile) {
|
||||
const struct rustls_root_cert_store *roots = NULL;
|
||||
struct rustls_root_cert_store_builder *roots_builder = NULL;
|
||||
struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
|
||||
struct rustls_server_cert_verifier *server_cert_verifier = NULL;
|
||||
rustls_result rr = RUSTLS_RESULT_OK;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
roots_builder = rustls_root_cert_store_builder_new();
|
||||
if(ca_info_blob) {
|
||||
rr = rustls_root_cert_store_builder_add_pem(roots_builder,
|
||||
ca_info_blob->data,
|
||||
ca_info_blob->len,
|
||||
1);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "failed to parse trusted certificates from blob");
|
||||
|
||||
result = CURLE_SSL_CACERT_BADFILE;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else if(ssl_cafile) {
|
||||
rr = rustls_root_cert_store_builder_load_roots_from_file(roots_builder,
|
||||
ssl_cafile,
|
||||
1);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "failed to load trusted certificates");
|
||||
|
||||
result = CURLE_SSL_CACERT_BADFILE;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
rr = rustls_root_cert_store_builder_build(roots_builder, &roots);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "failed to build trusted root certificate store");
|
||||
result = CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
|
||||
verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
|
||||
|
||||
if(conn_config->CRLfile) {
|
||||
result = init_config_builder_verifier_crl(data,
|
||||
conn_config,
|
||||
verifier_builder);
|
||||
if(result != CURLE_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
rr = rustls_web_pki_server_cert_verifier_builder_build(
|
||||
verifier_builder, &server_cert_verifier);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "failed to build certificate verifier");
|
||||
result = CURLE_SSL_CACERT_BADFILE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rustls_client_config_builder_set_server_verifier(builder,
|
||||
server_cert_verifier);
|
||||
cleanup:
|
||||
if(roots_builder) {
|
||||
rustls_root_cert_store_builder_free(roots_builder);
|
||||
}
|
||||
if(roots) {
|
||||
rustls_root_cert_store_free(roots);
|
||||
}
|
||||
if(verifier_builder) {
|
||||
rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
|
||||
}
|
||||
if(server_cert_verifier) {
|
||||
rustls_server_cert_verifier_free(server_cert_verifier);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
struct rustls_ssl_backend_data *const backend)
|
||||
{
|
||||
const struct ssl_connect_data *connssl = cf->ctx;
|
||||
const struct ssl_primary_config *conn_config =
|
||||
Curl_ssl_cf_get_primary_config(cf);
|
||||
struct rustls_connection *rconn = NULL;
|
||||
struct rustls_client_config_builder *config_builder = NULL;
|
||||
|
||||
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
|
||||
const char * const ssl_cafile =
|
||||
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
|
||||
(ca_info_blob ? NULL : conn_config->CAfile);
|
||||
const bool verifypeer = conn_config->verifypeer;
|
||||
char errorbuf[256];
|
||||
size_t errorlen;
|
||||
rustls_result result;
|
||||
CURLcode result = CURLE_OK;
|
||||
rustls_result rr;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
rconn = backend->conn;
|
||||
|
||||
{
|
||||
uint16_t tls_versions[2] = {
|
||||
RUSTLS_TLS_VERSION_TLSV1_2,
|
||||
RUSTLS_TLS_VERSION_TLSV1_3,
|
||||
};
|
||||
size_t tls_versions_len = 2;
|
||||
const struct rustls_supported_ciphersuite **cipher_suites;
|
||||
size_t cipher_suites_len =
|
||||
rustls_default_crypto_provider_ciphersuites_len();
|
||||
|
||||
switch(conn_config->version) {
|
||||
case CURL_SSLVERSION_DEFAULT:
|
||||
case CURL_SSLVERSION_TLSv1:
|
||||
case CURL_SSLVERSION_TLSv1_0:
|
||||
case CURL_SSLVERSION_TLSv1_1:
|
||||
case CURL_SSLVERSION_TLSv1_2:
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_3:
|
||||
tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
|
||||
tls_versions_len = 1;
|
||||
break;
|
||||
default:
|
||||
failf(data, "rustls: unsupported minimum TLS version value");
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
|
||||
switch(conn_config->version_max) {
|
||||
case CURL_SSLVERSION_MAX_DEFAULT:
|
||||
case CURL_SSLVERSION_MAX_NONE:
|
||||
case CURL_SSLVERSION_MAX_TLSv1_3:
|
||||
break;
|
||||
case CURL_SSLVERSION_MAX_TLSv1_2:
|
||||
if(tls_versions[0] == RUSTLS_TLS_VERSION_TLSV1_2) {
|
||||
tls_versions_len = 1;
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH();
|
||||
case CURL_SSLVERSION_MAX_TLSv1_1:
|
||||
case CURL_SSLVERSION_MAX_TLSv1_0:
|
||||
default:
|
||||
failf(data, "rustls: unsupported maximum TLS version value");
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
|
||||
cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len));
|
||||
if(!cipher_suites)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
cr_get_selected_ciphers(data,
|
||||
conn_config->cipher_list,
|
||||
conn_config->cipher_list13,
|
||||
cipher_suites, &cipher_suites_len);
|
||||
if(cipher_suites_len == 0) {
|
||||
failf(data, "rustls: no supported cipher in list");
|
||||
free(cipher_suites);
|
||||
return CURLE_SSL_CIPHER;
|
||||
}
|
||||
|
||||
result = rustls_crypto_provider_builder_new_from_default(
|
||||
&custom_provider_builder);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data,
|
||||
"rustls: failed to create crypto provider builder from default");
|
||||
return CURLE_SSL_CIPHER;
|
||||
}
|
||||
|
||||
result =
|
||||
rustls_crypto_provider_builder_set_cipher_suites(
|
||||
custom_provider_builder,
|
||||
cipher_suites,
|
||||
cipher_suites_len);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data,
|
||||
"rustls: failed to set ciphersuites for crypto provider builder");
|
||||
rustls_crypto_provider_builder_free(custom_provider_builder);
|
||||
return CURLE_SSL_CIPHER;
|
||||
}
|
||||
|
||||
result = rustls_crypto_provider_builder_build(
|
||||
custom_provider_builder, &custom_provider);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data, "rustls: failed to build custom crypto provider");
|
||||
rustls_crypto_provider_builder_free(custom_provider_builder);
|
||||
return CURLE_SSL_CIPHER;
|
||||
}
|
||||
|
||||
result = rustls_client_config_builder_new_custom(custom_provider,
|
||||
tls_versions,
|
||||
tls_versions_len,
|
||||
&config_builder);
|
||||
free(cipher_suites);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data, "rustls: failed to create client config");
|
||||
return CURLE_SSL_CIPHER;
|
||||
}
|
||||
result = init_config_builder(data, conn_config, &config_builder);
|
||||
if(result != CURLE_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
rustls_crypto_provider_builder_free(custom_provider_builder);
|
||||
rustls_crypto_provider_free(custom_provider);
|
||||
|
||||
if(connssl->alpn) {
|
||||
struct alpn_proto_buf proto;
|
||||
rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < connssl->alpn->count; ++i) {
|
||||
alpn[i].data = (const uint8_t *)connssl->alpn->entries[i];
|
||||
alpn[i].len = strlen(connssl->alpn->entries[i]);
|
||||
}
|
||||
rustls_client_config_builder_set_alpn_protocols(config_builder, alpn,
|
||||
connssl->alpn->count);
|
||||
Curl_alpn_to_proto_str(&proto, connssl->alpn);
|
||||
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
|
||||
init_config_builder_alpn(data, connssl, config_builder);
|
||||
}
|
||||
if(!verifypeer) {
|
||||
|
||||
if(!conn_config->verifypeer) {
|
||||
rustls_client_config_builder_dangerous_set_certificate_verifier(
|
||||
config_builder, cr_verify_none);
|
||||
}
|
||||
else if(ca_info_blob || ssl_cafile) {
|
||||
roots_builder = rustls_root_cert_store_builder_new();
|
||||
|
||||
if(ca_info_blob) {
|
||||
/* Enable strict parsing only if verification is not disabled. */
|
||||
result = rustls_root_cert_store_builder_add_pem(roots_builder,
|
||||
ca_info_blob->data,
|
||||
ca_info_blob->len,
|
||||
verifypeer);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data, "rustls: failed to parse trusted certificates from blob");
|
||||
rustls_root_cert_store_builder_free(roots_builder);
|
||||
rustls_client_config_builder_free(config_builder);
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
else if(ssl_cafile) {
|
||||
/* Enable strict parsing only if verification is not disabled. */
|
||||
result = rustls_root_cert_store_builder_load_roots_from_file(
|
||||
roots_builder, ssl_cafile, verifypeer);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data, "rustls: failed to load trusted certificates");
|
||||
rustls_root_cert_store_builder_free(roots_builder);
|
||||
rustls_client_config_builder_free(config_builder);
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
|
||||
result = rustls_root_cert_store_builder_build(roots_builder, &roots);
|
||||
rustls_root_cert_store_builder_free(roots_builder);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data, "rustls: failed to build trusted root certificate store");
|
||||
result = init_config_builder_verifier(data,
|
||||
config_builder,
|
||||
conn_config,
|
||||
ca_info_blob,
|
||||
ssl_cafile);
|
||||
if(result != CURLE_OK) {
|
||||
rustls_client_config_builder_free(config_builder);
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
return result;
|
||||
}
|
||||
|
||||
verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
|
||||
rustls_root_cert_store_free(roots);
|
||||
|
||||
if(conn_config->CRLfile) {
|
||||
struct dynbuf crl_contents;
|
||||
Curl_dyn_init(&crl_contents, DYN_CRLFILE_SIZE);
|
||||
if(!read_file_into(conn_config->CRLfile, &crl_contents)) {
|
||||
failf(data, "rustls: failed to read revocation list file");
|
||||
Curl_dyn_free(&crl_contents);
|
||||
rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
|
||||
return CURLE_SSL_CRL_BADFILE;
|
||||
}
|
||||
|
||||
result = rustls_web_pki_server_cert_verifier_builder_add_crl(
|
||||
verifier_builder,
|
||||
Curl_dyn_uptr(&crl_contents),
|
||||
Curl_dyn_len(&crl_contents));
|
||||
Curl_dyn_free(&crl_contents);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data, "rustls: failed to parse revocation list");
|
||||
rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
|
||||
return CURLE_SSL_CRL_BADFILE;
|
||||
}
|
||||
}
|
||||
|
||||
result = rustls_web_pki_server_cert_verifier_builder_build(
|
||||
verifier_builder, &server_cert_verifier);
|
||||
rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data, "rustls: failed to build certificate verifier");
|
||||
rustls_server_cert_verifier_free(server_cert_verifier);
|
||||
rustls_client_config_builder_free(config_builder);
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
|
||||
rustls_client_config_builder_set_server_verifier(config_builder,
|
||||
server_cert_verifier);
|
||||
rustls_server_cert_verifier_free(server_cert_verifier);
|
||||
}
|
||||
|
||||
result = rustls_client_config_builder_build(
|
||||
rr = rustls_client_config_builder_build(
|
||||
config_builder,
|
||||
&backend->config);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
failf(data, "rustls: failed to build client config");
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "failed to build client config");
|
||||
rustls_client_config_builder_free(config_builder);
|
||||
rustls_client_config_free(backend->config);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
DEBUGASSERT(rconn == NULL);
|
||||
result = rustls_client_connection_new(backend->config,
|
||||
connssl->peer.hostname, &rconn);
|
||||
if(result != RUSTLS_RESULT_OK) {
|
||||
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
|
||||
failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf);
|
||||
rr = rustls_client_connection_new(backend->config,
|
||||
connssl->peer.hostname,
|
||||
&rconn);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, result, "rustls_client_connection_new");
|
||||
return CURLE_COULDNT_CONNECT;
|
||||
}
|
||||
DEBUGASSERT(rconn);
|
||||
rustls_connection_set_userdata(rconn, backend);
|
||||
backend->conn = rconn;
|
||||
return CURLE_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -788,9 +866,9 @@ cr_connect(struct Curl_cfilter *cf,
|
|||
struct Curl_easy *data, bool *done)
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
const struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
const struct rustls_connection *rconn = NULL;
|
||||
CURLcode tmperr = CURLE_OK;
|
||||
int result;
|
||||
bool wants_read;
|
||||
|
|
@ -835,8 +913,10 @@ cr_connect(struct Curl_cfilter *cf,
|
|||
}
|
||||
/* REALLY Done with the handshake. */
|
||||
{
|
||||
uint16_t proto = rustls_connection_get_protocol_version(rconn);
|
||||
uint16_t cipher = rustls_connection_get_negotiated_ciphersuite(rconn);
|
||||
const uint16_t proto =
|
||||
rustls_connection_get_protocol_version(rconn);
|
||||
const uint16_t cipher =
|
||||
rustls_connection_get_negotiated_ciphersuite(rconn);
|
||||
char buf[64] = "";
|
||||
const char *ver = "TLS version unknown";
|
||||
if(proto == RUSTLS_TLS_VERSION_TLSV1_3)
|
||||
|
|
@ -944,14 +1024,13 @@ cr_get_internals(struct ssl_connect_data *connssl,
|
|||
static CURLcode
|
||||
cr_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool send_shutdown, bool *done)
|
||||
const bool send_shutdown, bool *done)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct rustls_ssl_backend_data *backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
CURLcode result = CURLE_OK;
|
||||
ssize_t nwritten, nread;
|
||||
char buf[1024];
|
||||
size_t i;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
|
@ -984,6 +1063,7 @@ cr_shutdown(struct Curl_cfilter *cf,
|
|||
}
|
||||
|
||||
for(i = 0; i < 10; ++i) {
|
||||
char buf[1024];
|
||||
nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result);
|
||||
if(nread <= 0)
|
||||
break;
|
||||
|
|
@ -1013,7 +1093,7 @@ out:
|
|||
static void
|
||||
cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
const struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct rustls_ssl_backend_data *backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
|
||||
|
|
@ -1031,7 +1111,7 @@ cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
|
||||
static size_t cr_version(char *buffer, size_t size)
|
||||
{
|
||||
struct rustls_str ver = rustls_version();
|
||||
const struct rustls_str ver = rustls_version();
|
||||
return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue