mirror of
https://github.com/curl/curl.git
synced 2026-08-02 21:10:33 +03:00
wolfssl: support CA caching
As a bonus, add SSLSUPP_CA_CACHE to let TLS backends signal its support for this so that *setopt() return error if there is no support. Closes #13786
This commit is contained in:
parent
6da320357f
commit
80aa519545
11 changed files with 374 additions and 155 deletions
|
|
@ -14,6 +14,8 @@ Protocol:
|
|||
- TLS
|
||||
TLS-backend:
|
||||
- OpenSSL
|
||||
- Schannel
|
||||
- wolfSSL
|
||||
---
|
||||
|
||||
# NAME
|
||||
|
|
@ -31,16 +33,17 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CA_CACHE_TIMEOUT, long age);
|
|||
# DESCRIPTION
|
||||
|
||||
Pass a long, this sets the timeout in seconds. This tells libcurl the maximum
|
||||
time any cached certificate store it has in memory may be kept and reused for
|
||||
new connections. Once the timeout has expired, a subsequent fetch requiring a
|
||||
certificate has to reload it.
|
||||
time any cached CA certificate store it has in memory may be kept and reused
|
||||
for new connections. Once the timeout has expired, a subsequent fetch
|
||||
requiring a CA certificate has to reload it.
|
||||
|
||||
Building a certificate store from a CURLOPT_CAINFO(3) file is a slow
|
||||
operation so curl may cache the generated certificate store internally to speed
|
||||
up future connections.
|
||||
Building a CA certificate store from a CURLOPT_CAINFO(3) file is a slow
|
||||
operation so curl may cache the generated certificate store internally to
|
||||
speed up future connections.
|
||||
|
||||
Set to zero to completely disable caching, or set to -1 to retain the cached
|
||||
store remain forever. By default, libcurl caches this info for 24 hours.
|
||||
Set the timeout to zero to completely disable caching, or set to -1 to retain
|
||||
the cached store remain forever. By default, libcurl caches this info for 24
|
||||
hours.
|
||||
|
||||
# DEFAULT
|
||||
|
||||
|
|
@ -74,8 +77,8 @@ int main(void)
|
|||
|
||||
This option was added in curl 7.87.0.
|
||||
|
||||
This option is supported by OpenSSL and its forks (since 7.87.0) and Schannel
|
||||
(since 8.5.0).
|
||||
This option is supported by OpenSSL and its forks (since 7.87.0), Schannel
|
||||
(since 8.5.0) and wolfSSL (since 8.9.0).
|
||||
|
||||
# RETURN VALUE
|
||||
|
||||
|
|
|
|||
16
lib/setopt.c
16
lib/setopt.c
|
|
@ -203,13 +203,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||
data->set.dns_cache_timeout = (int)arg;
|
||||
break;
|
||||
case CURLOPT_CA_CACHE_TIMEOUT:
|
||||
arg = va_arg(param, long);
|
||||
if(arg < -1)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
else if(arg > INT_MAX)
|
||||
arg = INT_MAX;
|
||||
if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) {
|
||||
arg = va_arg(param, long);
|
||||
if(arg < -1)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
else if(arg > INT_MAX)
|
||||
arg = INT_MAX;
|
||||
|
||||
data->set.general_ssl.ca_cache_timeout = (int)arg;
|
||||
data->set.general_ssl.ca_cache_timeout = (int)arg;
|
||||
}
|
||||
else
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
break;
|
||||
case CURLOPT_DNS_USE_GLOBAL_CACHE:
|
||||
/* deprecated */
|
||||
|
|
|
|||
|
|
@ -2120,7 +2120,7 @@ static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
|
|||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
#elif defined(USE_WOLFSSL)
|
||||
if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->ssl_ctx) != 0) {
|
||||
if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
|
||||
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
|
@ -2211,7 +2211,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
|||
#elif defined(USE_GNUTLS)
|
||||
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
|
||||
#else
|
||||
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl);
|
||||
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
|
||||
#endif
|
||||
|
||||
ngtcp2_ccerr_default(&ctx->last_error);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ static void keylog_callback(const WOLFSSL *ssl, const char *line)
|
|||
}
|
||||
#endif
|
||||
|
||||
static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
||||
static CURLcode Curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
Curl_vquic_tls_ctx_setup *cb_setup,
|
||||
|
|
@ -91,8 +91,8 @@ static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ctx->ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
||||
if(!ctx->ssl_ctx) {
|
||||
ctx->wssl.ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
||||
if(!ctx->wssl.ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -103,9 +103,9 @@ static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
|||
goto out;
|
||||
}
|
||||
|
||||
wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx);
|
||||
wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);
|
||||
|
||||
if(wolfSSL_CTX_set_cipher_list(ctx->ssl_ctx, conn_config->cipher_list13 ?
|
||||
if(wolfSSL_CTX_set_cipher_list(ctx->wssl.ctx, conn_config->cipher_list13 ?
|
||||
conn_config->cipher_list13 :
|
||||
QUIC_CIPHERS) != 1) {
|
||||
char error_buffer[256];
|
||||
|
|
@ -115,7 +115,7 @@ static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if(wolfSSL_CTX_set1_groups_list(ctx->ssl_ctx, conn_config->curves ?
|
||||
if(wolfSSL_CTX_set1_groups_list(ctx->wssl.ctx, conn_config->curves ?
|
||||
conn_config->curves :
|
||||
(char *)QUIC_GROUPS) != 1) {
|
||||
failf(data, "wolfSSL failed to set curves");
|
||||
|
|
@ -127,7 +127,7 @@ static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
|||
Curl_tls_keylog_open();
|
||||
if(Curl_tls_keylog_enabled()) {
|
||||
#if defined(HAVE_SECRET_CALLBACK)
|
||||
wolfSSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback);
|
||||
wolfSSL_CTX_set_keylog_callback(ctx->wssl.ctx, keylog_callback);
|
||||
#else
|
||||
failf(data, "wolfSSL was built without keylog callback");
|
||||
result = CURLE_NOT_BUILT_IN;
|
||||
|
|
@ -139,12 +139,12 @@ static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
|||
const char * const ssl_cafile = conn_config->CAfile;
|
||||
const char * const ssl_capath = conn_config->CApath;
|
||||
|
||||
wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
|
||||
wolfSSL_CTX_set_verify(ctx->wssl.ctx, SSL_VERIFY_PEER, NULL);
|
||||
if(ssl_cafile || ssl_capath) {
|
||||
/* tell wolfSSL where to find CA certificates that are used to verify
|
||||
the server's certificate. */
|
||||
int rc =
|
||||
wolfSSL_CTX_load_verify_locations_ex(ctx->ssl_ctx, ssl_cafile,
|
||||
wolfSSL_CTX_load_verify_locations_ex(ctx->wssl.ctx, ssl_cafile,
|
||||
ssl_capath,
|
||||
WOLFSSL_LOAD_FLAG_IGNORE_ERR);
|
||||
if(SSL_SUCCESS != rc) {
|
||||
|
|
@ -163,18 +163,18 @@ static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
|||
else {
|
||||
/* verifying the peer without any CA certificates won't work so
|
||||
use wolfssl's built-in default as fallback */
|
||||
wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx);
|
||||
wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
||||
wolfSSL_CTX_set_verify(ctx->wssl.ctx, SSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
|
||||
/* give application a chance to interfere with SSL set up. */
|
||||
if(data->set.ssl.fsslctx) {
|
||||
Curl_set_in_callback(data, true);
|
||||
result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx,
|
||||
result = (*data->set.ssl.fsslctx)(data, ctx->wssl.ctx,
|
||||
data->set.ssl.fsslctxp);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result) {
|
||||
|
|
@ -185,36 +185,36 @@ static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
|
|||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
if(result && ctx->ssl_ctx) {
|
||||
SSL_CTX_free(ctx->ssl_ctx);
|
||||
ctx->ssl_ctx = NULL;
|
||||
if(result && ctx->wssl.ctx) {
|
||||
SSL_CTX_free(ctx->wssl.ctx);
|
||||
ctx->wssl.ctx = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** SSL callbacks ***/
|
||||
|
||||
static CURLcode curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
|
||||
static CURLcode Curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
|
||||
struct Curl_easy *data,
|
||||
struct ssl_peer *peer,
|
||||
const char *alpn, size_t alpn_len,
|
||||
void *user_data)
|
||||
{
|
||||
(void)data;
|
||||
DEBUGASSERT(!ctx->ssl);
|
||||
DEBUGASSERT(ctx->ssl_ctx);
|
||||
ctx->ssl = wolfSSL_new(ctx->ssl_ctx);
|
||||
DEBUGASSERT(!ctx->wssl.handle);
|
||||
DEBUGASSERT(ctx->wssl.ctx);
|
||||
ctx->wssl.handle = wolfSSL_new(ctx->wssl.ctx);
|
||||
|
||||
wolfSSL_set_app_data(ctx->ssl, user_data);
|
||||
wolfSSL_set_connect_state(ctx->ssl);
|
||||
wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
|
||||
wolfSSL_set_app_data(ctx->wssl.handle, user_data);
|
||||
wolfSSL_set_connect_state(ctx->wssl.handle);
|
||||
wolfSSL_set_quic_use_legacy_codepoint(ctx->wssl.handle, 0);
|
||||
|
||||
if(alpn)
|
||||
wolfSSL_set_alpn_protos(ctx->ssl, (const unsigned char *)alpn,
|
||||
wolfSSL_set_alpn_protos(ctx->wssl.handle, (const unsigned char *)alpn,
|
||||
(int)alpn_len);
|
||||
|
||||
if(peer->sni) {
|
||||
wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME,
|
||||
wolfSSL_UseSNI(ctx->wssl.handle, WOLFSSL_SNI_HOST_NAME,
|
||||
peer->sni, (unsigned short)strlen(peer->sni));
|
||||
}
|
||||
|
||||
|
|
@ -243,11 +243,11 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
|||
(const unsigned char *)alpn, alpn_len,
|
||||
cb_setup, cb_user_data, ssl_user_data);
|
||||
#elif defined(USE_WOLFSSL)
|
||||
result = curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
|
||||
result = Curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
|
||||
return Curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
|
||||
#else
|
||||
#error "no TLS lib in used, should not happen"
|
||||
return CURLE_FAILED_INIT;
|
||||
|
|
@ -267,10 +267,10 @@ void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx)
|
|||
if(ctx->gtls.session)
|
||||
gnutls_deinit(ctx->gtls.session);
|
||||
#elif defined(USE_WOLFSSL)
|
||||
if(ctx->ssl)
|
||||
wolfSSL_free(ctx->ssl);
|
||||
if(ctx->ssl_ctx)
|
||||
wolfSSL_CTX_free(ctx->ssl_ctx);
|
||||
if(ctx->wssl.handle)
|
||||
wolfSSL_free(ctx->wssl.handle);
|
||||
if(ctx->wssl.ctx)
|
||||
wolfSSL_CTX_free(ctx->wssl.ctx);
|
||||
#endif
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
|
@ -286,6 +286,12 @@ CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx,
|
|||
return result;
|
||||
ctx->ossl.x509_store_setup = TRUE;
|
||||
}
|
||||
#elif defined(USE_WOLFSSL)
|
||||
if(!ctx->wssl.x509_store_setup) {
|
||||
CURLcode result = Curl_wssl_setup_x509_store(cf, data, &ctx->wssl);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
#elif defined(USE_GNUTLS)
|
||||
if(!ctx->gtls.trust_setup) {
|
||||
CURLcode result = Curl_gtls_client_trust_setup(cf, data, &ctx->gtls);
|
||||
|
|
@ -325,7 +331,7 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
|
|||
(void)data;
|
||||
if(conn_config->verifyhost) {
|
||||
if(peer->sni) {
|
||||
WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->ssl);
|
||||
WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.handle);
|
||||
if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
|
||||
== WOLFSSL_FAILURE) {
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
|
|
|
|||
|
|
@ -31,14 +31,15 @@
|
|||
#if defined(USE_HTTP3) && \
|
||||
(defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))
|
||||
|
||||
#include "vtls/wolfssl.h"
|
||||
|
||||
struct curl_tls_ctx {
|
||||
#ifdef USE_OPENSSL
|
||||
struct ossl_ctx ossl;
|
||||
#elif defined(USE_GNUTLS)
|
||||
struct gtls_ctx gtls;
|
||||
#elif defined(USE_WOLFSSL)
|
||||
WOLFSSL_CTX *ssl_ctx;
|
||||
WOLFSSL *ssl;
|
||||
struct wolfssl_ctx wssl;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2849,8 +2849,8 @@ typedef long ctx_option_t;
|
|||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */
|
||||
static CURLcode
|
||||
ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
long ssl_version = conn_config->version;
|
||||
|
|
@ -5273,6 +5273,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
|
|||
#ifdef USE_ECH
|
||||
SSLSUPP_ECH |
|
||||
#endif
|
||||
SSLSUPP_CA_CACHE |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ossl_ctx),
|
||||
|
|
|
|||
|
|
@ -2910,6 +2910,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
|
|||
#endif
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
SSLSUPP_TLS13_CIPHERSUITES |
|
||||
SSLSUPP_CA_CACHE |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct schannel_ssl_backend_data),
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ static bool ssl_prefs_check(struct Curl_easy *data)
|
|||
}
|
||||
|
||||
static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
|
||||
const struct alpn_spec *alpn)
|
||||
const struct alpn_spec *alpn)
|
||||
{
|
||||
struct ssl_connect_data *ctx;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ struct Curl_ssl_session;
|
|||
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
|
||||
#define SSLSUPP_CAINFO_BLOB (1<<6)
|
||||
#define SSLSUPP_ECH (1<<7)
|
||||
#define SSLSUPP_CA_CACHE (1<<8)
|
||||
|
||||
#define ALPN_ACCEPTED "ALPN: server accepted "
|
||||
|
||||
|
|
|
|||
|
|
@ -99,12 +99,6 @@
|
|||
#undef USE_BIO_CHAIN
|
||||
#endif
|
||||
|
||||
struct wolfssl_ssl_backend_data {
|
||||
WOLFSSL_CTX *ctx;
|
||||
WOLFSSL *handle;
|
||||
CURLcode io_result; /* result of last BIO cfilter operation */
|
||||
};
|
||||
|
||||
#ifdef OPENSSL_EXTRA
|
||||
/*
|
||||
* Availability note:
|
||||
|
|
@ -290,8 +284,8 @@ static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
|
|||
{
|
||||
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nwritten;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
|
@ -311,8 +305,8 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
|
|||
{
|
||||
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nread;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
|
@ -357,6 +351,252 @@ static void wolfssl_bio_cf_free_methods(void)
|
|||
|
||||
#endif /* !USE_BIO_CHAIN */
|
||||
|
||||
static CURLcode populate_x509_store(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
X509_STORE *store,
|
||||
struct wolfssl_ctx *wssl)
|
||||
{
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
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 char * const ssl_capath = conn_config->CApath;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
bool imported_native_ca = false;
|
||||
|
||||
#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
|
||||
/* load native CA certificates */
|
||||
if(ssl_config->native_ca_store) {
|
||||
if(wolfSSL_CTX_load_system_CA_certs(wssl->ctx) != WOLFSSL_SUCCESS) {
|
||||
infof(data, "error importing native CA store, continuing anyway");
|
||||
}
|
||||
else {
|
||||
imported_native_ca = true;
|
||||
infof(data, "successfully imported native CA store");
|
||||
wssl->x509_store_setup = TRUE;
|
||||
}
|
||||
}
|
||||
#endif /* !NO_FILESYSTEM */
|
||||
|
||||
/* load certificate blob */
|
||||
if(ca_info_blob) {
|
||||
if(wolfSSL_CTX_load_verify_buffer(wssl->ctx, ca_info_blob->data,
|
||||
ca_info_blob->len,
|
||||
SSL_FILETYPE_PEM) != SSL_SUCCESS) {
|
||||
if(imported_native_ca) {
|
||||
infof(data, "error importing CA certificate blob, continuing anyway");
|
||||
}
|
||||
else {
|
||||
failf(data, "error importing CA certificate blob");
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
infof(data, "successfully imported CA certificate blob");
|
||||
wssl->x509_store_setup = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_FILESYSTEM
|
||||
/* load trusted cacert from file if not blob */
|
||||
|
||||
CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
|
||||
ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
|
||||
if(!store)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if((ssl_cafile || ssl_capath) && (!wssl->x509_store_setup)) {
|
||||
int rc =
|
||||
wolfSSL_CTX_load_verify_locations_ex(wssl->ctx,
|
||||
ssl_cafile,
|
||||
ssl_capath,
|
||||
WOLFSSL_LOAD_FLAG_IGNORE_ERR);
|
||||
if(SSL_SUCCESS != rc) {
|
||||
if(conn_config->verifypeer) {
|
||||
/* Fail if we insist on successfully verifying the server. */
|
||||
failf(data, "error setting certificate verify locations:"
|
||||
" CAfile: %s CApath: %s",
|
||||
ssl_cafile ? ssl_cafile : "none",
|
||||
ssl_capath ? ssl_capath : "none");
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
else {
|
||||
/* Just continue with a warning if no strict certificate
|
||||
verification is required. */
|
||||
infof(data, "error setting certificate verify locations,"
|
||||
" continuing anyway:");
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Everything is fine. */
|
||||
infof(data, "successfully set certificate verify locations:");
|
||||
}
|
||||
infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
|
||||
infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
|
||||
wssl->x509_store_setup = TRUE;
|
||||
}
|
||||
#endif
|
||||
(void)store;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* key to use at `multi->proto_hash` */
|
||||
#define MPROTO_WSSL_X509_KEY "tls:wssl:x509:share"
|
||||
|
||||
struct wssl_x509_share {
|
||||
char *CAfile; /* CAfile path used to generate X509 store */
|
||||
WOLFSSL_X509_STORE *store; /* cached X509 store or NULL if none */
|
||||
struct curltime time; /* when the cached store was created */
|
||||
};
|
||||
|
||||
static void wssl_x509_share_free(void *key, size_t key_len, void *p)
|
||||
{
|
||||
struct wssl_x509_share *share = p;
|
||||
DEBUGASSERT(key_len == (sizeof(MPROTO_WSSL_X509_KEY)-1));
|
||||
DEBUGASSERT(!memcmp(MPROTO_WSSL_X509_KEY, key, key_len));
|
||||
(void)key;
|
||||
(void)key_len;
|
||||
if(share->store) {
|
||||
wolfSSL_X509_STORE_free(share->store);
|
||||
}
|
||||
free(share->CAfile);
|
||||
free(share);
|
||||
}
|
||||
|
||||
static bool
|
||||
cached_x509_store_expired(const struct Curl_easy *data,
|
||||
const struct wssl_x509_share *mb)
|
||||
{
|
||||
const struct ssl_general_config *cfg = &data->set.general_ssl;
|
||||
struct curltime now = Curl_now();
|
||||
timediff_t elapsed_ms = Curl_timediff(now, mb->time);
|
||||
timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
|
||||
|
||||
if(timeout_ms < 0)
|
||||
return false;
|
||||
|
||||
return elapsed_ms >= timeout_ms;
|
||||
}
|
||||
|
||||
static bool
|
||||
cached_x509_store_different(struct Curl_cfilter *cf,
|
||||
const struct wssl_x509_share *mb)
|
||||
{
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
if(!mb->CAfile || !conn_config->CAfile)
|
||||
return mb->CAfile != conn_config->CAfile;
|
||||
|
||||
return strcmp(mb->CAfile, conn_config->CAfile);
|
||||
}
|
||||
|
||||
static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct Curl_multi *multi = data->multi;
|
||||
struct wssl_x509_share *share;
|
||||
WOLFSSL_X509_STORE *store = NULL;
|
||||
|
||||
DEBUGASSERT(multi);
|
||||
share = multi? Curl_hash_pick(&multi->proto_hash,
|
||||
(void *)MPROTO_WSSL_X509_KEY,
|
||||
sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
|
||||
if(share && share->store &&
|
||||
!cached_x509_store_expired(data, share) &&
|
||||
!cached_x509_store_different(cf, share)) {
|
||||
store = share->store;
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
static void set_cached_x509_store(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data,
|
||||
X509_STORE *store)
|
||||
{
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct Curl_multi *multi = data->multi;
|
||||
struct wssl_x509_share *share;
|
||||
|
||||
DEBUGASSERT(multi);
|
||||
if(!multi)
|
||||
return;
|
||||
share = Curl_hash_pick(&multi->proto_hash,
|
||||
(void *)MPROTO_WSSL_X509_KEY,
|
||||
sizeof(MPROTO_WSSL_X509_KEY)-1);
|
||||
|
||||
if(!share) {
|
||||
share = calloc(1, sizeof(*share));
|
||||
if(!share)
|
||||
return;
|
||||
if(!Curl_hash_add2(&multi->proto_hash,
|
||||
(void *)MPROTO_WSSL_X509_KEY,
|
||||
sizeof(MPROTO_WSSL_X509_KEY)-1,
|
||||
share, wssl_x509_share_free)) {
|
||||
free(share);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(wolfSSL_X509_STORE_up_ref(store)) {
|
||||
char *CAfile = NULL;
|
||||
|
||||
if(conn_config->CAfile) {
|
||||
CAfile = strdup(conn_config->CAfile);
|
||||
if(!CAfile) {
|
||||
X509_STORE_free(store);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(share->store) {
|
||||
X509_STORE_free(share->store);
|
||||
free(share->CAfile);
|
||||
}
|
||||
|
||||
share->time = Curl_now();
|
||||
share->store = store;
|
||||
share->CAfile = CAfile;
|
||||
}
|
||||
}
|
||||
|
||||
CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct wolfssl_ctx *wssl)
|
||||
{
|
||||
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);
|
||||
CURLcode result = CURLE_OK;
|
||||
WOLFSSL_X509_STORE *cached_store;
|
||||
bool cache_criteria_met;
|
||||
|
||||
/* Consider the X509 store cacheable if it comes exclusively from a CAfile,
|
||||
or no source is provided and we are falling back to openssl's built-in
|
||||
default. */
|
||||
cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
|
||||
conn_config->verifypeer &&
|
||||
!conn_config->CApath &&
|
||||
!conn_config->ca_info_blob &&
|
||||
!ssl_config->primary.CRLfile &&
|
||||
!ssl_config->native_ca_store;
|
||||
|
||||
cached_store = get_cached_x509_store(cf, data);
|
||||
if(cached_store && cache_criteria_met
|
||||
&& wolfSSL_X509_STORE_up_ref(cached_store)) {
|
||||
wolfSSL_CTX_set_cert_store(wssl->ctx, cached_store);
|
||||
}
|
||||
else {
|
||||
X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
|
||||
|
||||
result = populate_x509_store(cf, data, store, wssl);
|
||||
if(result == CURLE_OK && cache_criteria_met) {
|
||||
set_cached_x509_store(cf, data, store);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function loads all the client/CA certificates and CRLs. Setup the TLS
|
||||
* layer and do all necessary magic.
|
||||
|
|
@ -366,15 +606,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
{
|
||||
char *ciphers, *curves;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
|
||||
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
const char * const ssl_cafile =
|
||||
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
|
||||
(ca_info_blob ? NULL : conn_config->CAfile);
|
||||
const char * const ssl_capath = conn_config->CApath;
|
||||
WOLFSSL_METHOD* req_method = NULL;
|
||||
#ifdef HAVE_LIBOQS
|
||||
word16 oqsAlg = 0;
|
||||
|
|
@ -386,8 +621,6 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
#else
|
||||
#define use_sni(x) Curl_nop_stmt
|
||||
#endif
|
||||
bool imported_native_ca = false;
|
||||
bool imported_ca_info_blob = false;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
|
|
@ -524,71 +757,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
}
|
||||
}
|
||||
|
||||
#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
|
||||
/* load native CA certificates */
|
||||
if(ssl_config->native_ca_store) {
|
||||
if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) {
|
||||
infof(data, "error importing native CA store, continuing anyway");
|
||||
}
|
||||
else {
|
||||
imported_native_ca = true;
|
||||
infof(data, "successfully imported native CA store");
|
||||
}
|
||||
}
|
||||
#endif /* !NO_FILESYSTEM */
|
||||
|
||||
/* load certificate blob */
|
||||
if(ca_info_blob) {
|
||||
if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data,
|
||||
ca_info_blob->len,
|
||||
SSL_FILETYPE_PEM) != SSL_SUCCESS) {
|
||||
if(imported_native_ca) {
|
||||
infof(data, "error importing CA certificate blob, continuing anyway");
|
||||
}
|
||||
else {
|
||||
failf(data, "error importing CA certificate blob");
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
imported_ca_info_blob = true;
|
||||
infof(data, "successfully imported CA certificate blob");
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_FILESYSTEM
|
||||
/* load trusted cacert from file if not blob */
|
||||
if(ssl_cafile || ssl_capath) {
|
||||
int rc =
|
||||
wolfSSL_CTX_load_verify_locations_ex(backend->ctx,
|
||||
ssl_cafile,
|
||||
ssl_capath,
|
||||
WOLFSSL_LOAD_FLAG_IGNORE_ERR);
|
||||
if(SSL_SUCCESS != rc) {
|
||||
if(conn_config->verifypeer && !imported_ca_info_blob &&
|
||||
!imported_native_ca) {
|
||||
/* Fail if we insist on successfully verifying the server. */
|
||||
failf(data, "error setting certificate verify locations:"
|
||||
" CAfile: %s CApath: %s",
|
||||
ssl_cafile ? ssl_cafile : "none",
|
||||
ssl_capath ? ssl_capath : "none");
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
else {
|
||||
/* Just continue with a warning if no strict certificate
|
||||
verification is required. */
|
||||
infof(data, "error setting certificate verify locations,"
|
||||
" continuing anyway:");
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Everything is fine. */
|
||||
infof(data, "successfully set certificate verify locations:");
|
||||
}
|
||||
infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
|
||||
infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
|
||||
}
|
||||
|
||||
/* Load the client certificate, and private key */
|
||||
if(ssl_config->primary.clientcert && ssl_config->key) {
|
||||
int file_type = do_file_type(ssl_config->cert_type);
|
||||
|
|
@ -839,8 +1008,8 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
{
|
||||
int ret = -1;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
|
||||
|
|
@ -862,6 +1031,21 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if(!backend->x509_store_setup) {
|
||||
/* After having send off the ClientHello, we prepare the x509
|
||||
* store to verify the coming certificate from the server */
|
||||
CURLcode result;
|
||||
struct wolfssl_ctx wssl;
|
||||
wssl.ctx = backend->ctx;
|
||||
wssl.handle = backend->handle;
|
||||
wssl.io_result = CURLE_OK;
|
||||
wssl.x509_store_setup = FALSE;
|
||||
result = Curl_wssl_setup_x509_store(cf, data, &wssl);
|
||||
if(result)
|
||||
return result;
|
||||
backend->x509_store_setup = wssl.x509_store_setup;
|
||||
}
|
||||
|
||||
ret = wolfSSL_connect(backend->handle);
|
||||
|
||||
#ifdef OPENSSL_EXTRA
|
||||
|
|
@ -1070,8 +1254,8 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
|
||||
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
|
||||
|
|
@ -1116,8 +1300,8 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
|
|||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
|
||||
int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
|
||||
int rc;
|
||||
|
|
@ -1158,8 +1342,8 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
|
|||
static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
|
||||
(void) data;
|
||||
|
||||
|
|
@ -1187,8 +1371,8 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
|
|||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
|
||||
int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
|
||||
int nread;
|
||||
|
|
@ -1269,12 +1453,12 @@ static bool wolfssl_data_pending(struct Curl_cfilter *cf,
|
|||
const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend;
|
||||
struct wolfssl_ctx *backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
|
||||
backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
|
||||
backend = (struct wolfssl_ctx *)ctx->backend;
|
||||
if(backend->handle) /* SSL is in use */
|
||||
return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
|
||||
else
|
||||
|
|
@ -1290,13 +1474,13 @@ static int wolfssl_shutdown(struct Curl_cfilter *cf,
|
|||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend;
|
||||
struct wolfssl_ctx *backend;
|
||||
int retval = 0;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
|
||||
backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
|
||||
backend = (struct wolfssl_ctx *)ctx->backend;
|
||||
if(backend->handle) {
|
||||
wolfSSL_ERR_clear_error();
|
||||
wolfSSL_free(backend->handle);
|
||||
|
|
@ -1472,8 +1656,8 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
|
|||
static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct wolfssl_ctx *backend =
|
||||
(struct wolfssl_ctx *)connssl->backend;
|
||||
(void)info;
|
||||
DEBUGASSERT(backend);
|
||||
return backend->handle;
|
||||
|
|
@ -1493,9 +1677,10 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
|
|||
#ifdef USE_ECH
|
||||
SSLSUPP_ECH |
|
||||
#endif
|
||||
SSLSUPP_SSL_CTX,
|
||||
SSLSUPP_SSL_CTX |
|
||||
SSLSUPP_CA_CACHE,
|
||||
|
||||
sizeof(struct wolfssl_ssl_backend_data),
|
||||
sizeof(struct wolfssl_ctx),
|
||||
|
||||
wolfssl_init, /* init */
|
||||
wolfssl_cleanup, /* cleanup */
|
||||
|
|
|
|||
|
|
@ -26,8 +26,25 @@
|
|||
#include "curl_setup.h"
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
#include <wolfssl/version.h>
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/error-ssl.h>
|
||||
|
||||
#include "urldata.h"
|
||||
|
||||
extern const struct Curl_ssl Curl_ssl_wolfssl;
|
||||
|
||||
struct wolfssl_ctx {
|
||||
WOLFSSL_CTX *ctx;
|
||||
WOLFSSL *handle;
|
||||
CURLcode io_result; /* result of last BIO cfilter operation */
|
||||
BIT(x509_store_setup); /* x509 store has been set up */
|
||||
};
|
||||
|
||||
CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct wolfssl_ctx *wssl);
|
||||
|
||||
#endif /* USE_WOLFSSL */
|
||||
#endif /* HEADER_CURL_WOLFSSL_H */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue