multissl: make openssl + wolfssl builds work

- make colliding vtls static function names unique.
- wolfssl: stop including an unused compatibility header.
- cmake: adapt detection logic for openssl+wolfssl coexist.
- wolfssl: fix to use native wolfSSL API in ECH codepath.
- openssl+wolfssl: fix ECH code to coexist.

Requires a post wolfSSL v5.7.4, recent master for `OPENSSL_COEXIST`
feature, and `CPPFLAGS=-DOPENSSL_COEXIST`.

Ref: https://github.com/wolfSSL/wolfssl/issues/8194

Closes #15596
This commit is contained in:
Viktor Szakats 2024-11-16 21:24:17 +01:00
parent 54c5cb8b7f
commit fd067bfb5b
No known key found for this signature in database
GPG Key ID: B5ABD165E2AEF201
5 changed files with 99 additions and 77 deletions

View File

@ -879,7 +879,8 @@ macro(curl_openssl_check_symbol_exists _symbol _files _variable _extra_libs)
list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
list(APPEND CMAKE_REQUIRED_LIBRARIES "bcrypt") # for OpenSSL/LibreSSL
endif()
elseif(USE_WOLFSSL)
endif()
if(USE_WOLFSSL)
list(APPEND CMAKE_REQUIRED_INCLUDES "${WOLFSSL_INCLUDE_DIRS}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${WOLFSSL_LIBRARIES}")
curl_required_libpaths("${WOLFSSL_LIBRARY_DIRS}")
@ -902,7 +903,8 @@ macro(curl_openssl_check_quic)
if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD)
if(USE_OPENSSL)
curl_openssl_check_symbol_exists("SSL_CTX_set_quic_method" "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD "")
elseif(USE_WOLFSSL)
endif()
if(USE_WOLFSSL)
curl_openssl_check_symbol_exists("wolfSSL_set_quic_method" "wolfssl/options.h;wolfssl/openssl/ssl.h"
HAVE_SSL_CTX_SET_QUIC_METHOD "")
endif()
@ -933,14 +935,21 @@ option(USE_ECH "Enable ECH support" OFF)
if(USE_ECH)
if(USE_OPENSSL OR USE_WOLFSSL)
# Be sure that the TLS library actually supports ECH.
if(NOT DEFINED HAVE_ECH)
if(USE_OPENSSL AND (HAVE_BORINGSSL OR HAVE_AWSLC))
curl_openssl_check_symbol_exists("SSL_set1_ech_config_list" "openssl/ssl.h" HAVE_ECH "")
elseif(USE_OPENSSL)
curl_openssl_check_symbol_exists("SSL_ech_set1_echconfig" "openssl/ech.h" HAVE_ECH "")
elseif(USE_WOLFSSL)
curl_openssl_check_symbol_exists("wolfSSL_CTX_GenerateEchConfig" "wolfssl/options.h;wolfssl/ssl.h" HAVE_ECH "")
endif()
if(USE_WOLFSSL)
curl_openssl_check_symbol_exists("wolfSSL_CTX_GenerateEchConfig" "wolfssl/options.h;wolfssl/ssl.h"
HAVE_WOLFSSL_CTX_GENERATEECHCONFIG "")
endif()
if(HAVE_BORINGSSL OR HAVE_AWSLC)
curl_openssl_check_symbol_exists("SSL_set1_ech_config_list" "openssl/ssl.h"
HAVE_SSL_SET1_ECH_CONFIG_LIST "")
elseif(HAVE_OPENSSL)
curl_openssl_check_symbol_exists("SSL_ech_set1_echconfig" "openssl/ech.h"
HAVE_SSL_ECH_SET1_ECHCONFIG "")
endif()
if(HAVE_WOLFSSL_CTX_GENERATEECHCONFIG OR
HAVE_SSL_SET1_ECH_CONFIG_LIST OR
HAVE_SSL_ECH_SET1_ECHCONFIG)
set(HAVE_ECH 1)
endif()
if(NOT HAVE_ECH)
message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL")

View File

@ -841,3 +841,12 @@ ${SIZEOF_TIME_T_CODE}
/* if ECH support is available */
#cmakedefine USE_ECH 1
/* Define to 1 if you have the wolfSSL_CTX_GenerateEchConfig function. */
#cmakedefine HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
/* Define to 1 if you have the SSL_set1_ech_config_list function. */
#cmakedefine HAVE_SSL_SET1_ECH_CONFIG_LIST
/* Define to 1 if you have the SSL_ech_set1_echconfig function. */
#cmakedefine HAVE_SSL_ECH_SET1_ECHCONFIG

View File

@ -82,16 +82,16 @@
#include <openssl/tls1.h>
#include <openssl/evp.h>
#ifdef USE_ECH
#if defined(HAVE_SSL_SET1_ECH_CONFIG_LIST) || \
defined(HAVE_SSL_ECH_SET1_ECHCONFIG)
#define USE_ECH_OPENSSL
#endif
#ifdef USE_ECH_OPENSSL
# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
# include <openssl/ech.h>
# endif
# include "curl_base64.h"
# define ECH_ENABLED(__data__) \
(__data__->set.tls_ech && \
!(__data__->set.tls_ech & CURLECH_DISABLE)\
)
#endif /* USE_ECH */
#endif /* USE_ECH_OPENSSL */
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
@ -3133,9 +3133,9 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data,
}
#endif
static CURLcode populate_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
X509_STORE *store)
static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
X509_STORE *store)
{
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);
@ -3151,7 +3151,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
bool imported_native_ca = FALSE;
bool imported_ca_info_blob = FALSE;
CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
CURL_TRC_CF(data, cf, "ossl_populate_x509_store, path=%s, blob=%d",
ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
if(!store)
return CURLE_OUT_OF_MEMORY;
@ -3322,8 +3322,8 @@ static void oss_x509_share_free(void *key, size_t key_len, void *p)
}
static bool
cached_x509_store_expired(const struct Curl_easy *data,
const struct ossl_x509_share *mb)
ossl_cached_x509_store_expired(const struct Curl_easy *data,
const struct ossl_x509_share *mb)
{
const struct ssl_general_config *cfg = &data->set.general_ssl;
if(cfg->ca_cache_timeout < 0)
@ -3338,8 +3338,8 @@ cached_x509_store_expired(const struct Curl_easy *data,
}
static bool
cached_x509_store_different(struct Curl_cfilter *cf,
const struct ossl_x509_share *mb)
ossl_cached_x509_store_different(struct Curl_cfilter *cf,
const struct ossl_x509_share *mb)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
if(!mb->CAfile || !conn_config->CAfile)
@ -3348,8 +3348,8 @@ cached_x509_store_different(struct Curl_cfilter *cf,
return strcmp(mb->CAfile, conn_config->CAfile);
}
static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi;
struct ossl_x509_share *share;
@ -3360,17 +3360,17 @@ static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
(void *)MPROTO_OSSL_X509_KEY,
sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
if(share && share->store &&
!cached_x509_store_expired(data, share) &&
!cached_x509_store_different(cf, share)) {
!ossl_cached_x509_store_expired(data, share) &&
!ossl_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)
static void ossl_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;
@ -3438,16 +3438,16 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
!ssl_config->primary.CRLfile &&
!ssl_config->native_ca_store;
cached_store = get_cached_x509_store(cf, data);
cached_store = ossl_get_cached_x509_store(cf, data);
if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) {
SSL_CTX_set_cert_store(ssl_ctx, cached_store);
}
else {
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
result = populate_x509_store(cf, data, store);
result = ossl_populate_x509_store(cf, data, store);
if(result == CURLE_OK && cache_criteria_met) {
set_cached_x509_store(cf, data, store);
ossl_set_cached_x509_store(cf, data, store);
}
}
@ -3460,7 +3460,7 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
{
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
return populate_x509_store(cf, data, store);
return ossl_populate_x509_store(cf, data, store);
}
#endif /* HAVE_SSL_X509_STORE_SHARE */
@ -3832,7 +3832,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
}
}
#ifdef USE_ECH
#ifdef USE_ECH_OPENSSL
if(ECH_ENABLED(data)) {
unsigned char *ech_config = NULL;
size_t ech_config_len = 0;
@ -3959,7 +3959,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
return CURLE_SSL_CONNECT_ERROR;
}
}
#endif /* USE_ECH */
#endif /* USE_ECH_OPENSSL */
#endif
@ -4055,7 +4055,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
return CURLE_OK;
}
#ifdef USE_ECH
#ifdef USE_ECH_OPENSSL
/* If we have retry configs, then trace those out */
static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl,
int reason)
@ -4230,7 +4230,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)));
}
#endif
#ifdef USE_ECH
#ifdef USE_ECH_OPENSSL
else if((lib == ERR_LIB_SSL) &&
# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
(reason == SSL_R_ECH_REQUIRED)) {
@ -4296,7 +4296,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
negotiated_group_name ? negotiated_group_name : "[blank]",
OBJ_nid2sn(psigtype_nid));
#ifdef USE_ECH
#ifdef USE_ECH_OPENSSL
# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
if(ECH_ENABLED(data)) {
char *inner = NULL, *outer = NULL;
@ -4356,7 +4356,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
infof(data, "ECH: result: status is not attempted");
}
# endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
#endif /* USE_ECH */
#endif /* USE_ECH_OPENSSL */
#ifdef HAS_ALPN
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
@ -5325,7 +5325,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
SSLSUPP_TLS13_CIPHERSUITES |
#endif
#ifdef USE_ECH
#ifdef USE_ECH_OPENSSL
SSLSUPP_ECH |
#endif
SSLSUPP_CA_CACHE |

View File

@ -41,6 +41,14 @@ struct Curl_ssl_session;
#define SSLSUPP_CA_CACHE (1<<8)
#define SSLSUPP_CIPHER_LIST (1<<9) /* supports TLS 1.0-1.2 ciphersuites */
#ifdef USE_ECH
# include "curl_base64.h"
# define ECH_ENABLED(__data__) \
(__data__->set.tls_ech && \
!(__data__->set.tls_ech & CURLECH_DISABLE)\
)
#endif /* USE_ECH */
#define ALPN_ACCEPTED "ALPN: server accepted "
#define VTLS_INFOF_NO_ALPN \

View File

@ -69,7 +69,6 @@
#include "curl_printf.h"
#include "multiif.h"
#include <wolfssl/openssl/ssl.h>
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>
#include "wolfssl.h"
@ -78,13 +77,9 @@
#include "curl_memory.h"
#include "memdebug.h"
#ifdef USE_ECH
# include "curl_base64.h"
# define ECH_ENABLED(__data__) \
(__data__->set.tls_ech && \
!(__data__->set.tls_ech & CURLECH_DISABLE)\
)
#endif /* USE_ECH */
#ifdef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
#define USE_ECH_WOLFSSL
#endif
/* KEEP_PEER_CERT is a product of the presence of build time symbol
OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
@ -505,10 +500,10 @@ CURLcode wssl_setup_session(struct Curl_cfilter *cf,
return result;
}
static CURLcode populate_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
WOLFSSL_X509_STORE *store,
struct wolfssl_ctx *wssl)
static CURLcode wssl_populate_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
WOLFSSL_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;
@ -556,7 +551,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
#ifndef NO_FILESYSTEM
/* load trusted cacert from file if not blob */
CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
CURL_TRC_CF(data, cf, "wssl_populate_x509_store, path=%s, blob=%d",
ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
if(!store)
return CURLE_OUT_OF_MEMORY;
@ -620,8 +615,8 @@ static void wssl_x509_share_free(void *key, size_t key_len, void *p)
}
static bool
cached_x509_store_expired(const struct Curl_easy *data,
const struct wssl_x509_share *mb)
wssl_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();
@ -635,8 +630,8 @@ cached_x509_store_expired(const struct Curl_easy *data,
}
static bool
cached_x509_store_different(struct Curl_cfilter *cf,
const struct wssl_x509_share *mb)
wssl_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)
@ -645,8 +640,8 @@ cached_x509_store_different(struct Curl_cfilter *cf,
return strcmp(mb->CAfile, conn_config->CAfile);
}
static WOLFSSL_X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
static WOLFSSL_X509_STORE *wssl_get_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi;
struct wssl_x509_share *share;
@ -657,17 +652,17 @@ static WOLFSSL_X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
(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)) {
!wssl_cached_x509_store_expired(data, share) &&
!wssl_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,
WOLFSSL_X509_STORE *store)
static void wssl_set_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data,
WOLFSSL_X509_STORE *store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_multi *multi = data->multi;
@ -735,7 +730,8 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
!ssl_config->primary.CRLfile &&
!ssl_config->native_ca_store;
cached_store = cache_criteria_met ? get_cached_x509_store(cf, data) : NULL;
cached_store = cache_criteria_met ? wssl_get_cached_x509_store(cf, data)
: NULL;
if(cached_store && wolfSSL_CTX_get_cert_store(wssl->ctx) == cached_store) {
/* The cached store is already in use, do nothing. */
}
@ -752,15 +748,15 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
}
wolfSSL_CTX_set_cert_store(wssl->ctx, store);
result = populate_x509_store(cf, data, store, wssl);
result = wssl_populate_x509_store(cf, data, store, wssl);
if(!result) {
set_cached_x509_store(cf, data, store);
wssl_set_cached_x509_store(cf, data, store);
}
}
else {
/* We never share the CTX's store, use it. */
WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
result = populate_x509_store(cf, data, store, wssl);
result = wssl_populate_x509_store(cf, data, store, wssl);
}
return result;
@ -1198,7 +1194,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
wolfSSL_CTX_sess_set_new_cb(backend->ctx, wssl_vtls_new_session_cb);
}
#ifdef USE_ECH
#ifdef USE_ECH_WOLFSSL
if(ECH_ENABLED(data)) {
int trying_ech_now = 0;
@ -1265,14 +1261,14 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
if(trying_ech_now
&& SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
if(trying_ech_now && wolfSSL_set_min_proto_version(backend->handle,
TLS1_3_VERSION) != 1) {
infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
return CURLE_SSL_CONNECT_ERROR;
}
}
#endif /* USE_ECH */
#endif /* USE_ECH_WOLFSSL */
#ifdef USE_BIO_CHAIN
{
@ -1441,7 +1437,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
failf(data, "server verification failed: certificate not valid yet.");
return CURLE_PEER_FAILED_VERIFICATION;
}
#ifdef USE_ECH
#ifdef USE_ECH_WOLFSSL
else if(-1 == detail) {
/* try access a retry_config ECHConfigList for tracing */
byte echConfigs[1000];
@ -2020,7 +2016,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#endif
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
#ifdef USE_ECH
#ifdef USE_ECH_WOLFSSL
SSLSUPP_ECH |
#endif
SSLSUPP_SSL_CTX |