quic: add support via wolfSSL

- based on ngtcp2 PR https://github.com/ngtcp2/ngtcp2/pull/505
- configure adapted to build against ngtcp2 wolfssl crypto lib
- quic code added for creation of WOLFSSL* instances

Closes #9290
This commit is contained in:
Stefan Eissing 2022-08-10 10:06:52 +02:00 committed by Daniel Stenberg
parent 6526b36271
commit 8a13be227e
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
4 changed files with 230 additions and 1 deletions

View File

@ -2890,6 +2890,61 @@ if test "x$NGTCP2_ENABLED" = "x1" -a "x$GNUTLS_ENABLED" = "x1"; then
fi fi
fi fi
if test "x$NGTCP2_ENABLED" = "x1" -a "x$WOLFSSL_ENABLED" = "x1"; then
dnl backup the pre-ngtcp2_crypto_wolfssl variables
CLEANLDFLAGS="$LDFLAGS"
CLEANCPPFLAGS="$CPPFLAGS"
CLEANLIBS="$LIBS"
CURL_CHECK_PKGCONFIG(libngtcp2_crypto_wolfssl, $want_tcp2_path)
if test "$PKGCONFIG" != "no" ; then
LIB_NGTCP2_CRYPTO_WOLFSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path])
$PKGCONFIG --libs-only-l libngtcp2_crypto_wolfssl`
AC_MSG_NOTICE([-l is $LIB_NGTCP2_CRYPTO_WOLFSSL])
CPP_NGTCP2_CRYPTO_WOLFSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path]) dnl
$PKGCONFIG --cflags-only-I libngtcp2_crypto_wolfssl`
AC_MSG_NOTICE([-I is $CPP_NGTCP2_CRYPTO_WOLFSSL])
LD_NGTCP2_CRYPTO_WOLFSSL=`CURL_EXPORT_PCDIR([$want_tcp2_path])
$PKGCONFIG --libs-only-L libngtcp2_crypto_wolfssl`
AC_MSG_NOTICE([-L is $LD_NGTCP2_CRYPTO_WOLFSSL])
LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_WOLFSSL"
CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_WOLFSSL"
LIBS="$LIB_NGTCP2_CRYPTO_WOLFSSL $LIBS"
if test "x$cross_compiling" != "xyes"; then
DIR_NGTCP2_CRYPTO_WOLFSSL=`echo $LD_NGTCP2_CRYPTO_WOLFSSL | $SED -e 's/^-L//'`
fi
AC_CHECK_LIB(ngtcp2_crypto_wolfssl, ngtcp2_crypto_recv_client_initial_cb,
[
AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
NGTCP2_ENABLED=1
AC_DEFINE(USE_NGTCP2_CRYPTO_WOLFSSL, 1, [if ngtcp2_crypto_wolfssl is in use])
AC_SUBST(USE_NGTCP2_CRYPTO_WOLFSSL, [1])
CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_WOLFSSL"
export CURL_LIBRARY_PATH
AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH])
)
],
dnl not found, revert back to clean variables
LDFLAGS=$CLEANLDFLAGS
CPPFLAGS=$CLEANCPPFLAGS
LIBS=$CLEANLIBS
)
else
dnl no ngtcp2_crypto_wolfssl pkg-config found, deal with it
if test X"$want_tcp2" != Xdefault; then
dnl To avoid link errors, we do not allow --with-ngtcp2 without
dnl a pkgconfig file
AC_MSG_ERROR([--with-ngtcp2 was specified but could not find ngtcp2_crypto_wolfssl pkg-config file.])
fi
fi
fi
dnl ********************************************************************** dnl **********************************************************************
dnl Check for nghttp3 (HTTP/3 with ngtcp2) dnl Check for nghttp3 (HTTP/3 with ngtcp2)
dnl ********************************************************************** dnl **********************************************************************

View File

@ -110,6 +110,46 @@ Build curl
% make % make
% make install % make install
## Build with wolfSSL
Build wolfSSL
% git clone https://github.com/wolfSSL/wolfssl.git
% cd wolfssl
% ./configure --prefix=<somewhere1> --enable-quic --enable-session-ticket --enable-earlydata --enable-psk --enable-harden --enable-altcertchains
% make
% make install
Build nghttp3
% cd ..
% git clone https://github.com/ngtcp2/nghttp3
% cd nghttp3
% autoreconf -fi
% ./configure --prefix=<somewhere2> --enable-lib-only
% make
% make install
Build ngtcp2 (once https://github.com/ngtcp2/ngtcp2/pull/505 is merged)
% cd ..
% git clone https://github.com/ngtcp2/ngtcp2
% cd ngtcp2
% autoreconf -fi
% ./configure PKG_CONFIG_PATH=<somewhere1>/lib/pkgconfig:<somewhere2>/lib/pkgconfig LDFLAGS="-Wl,-rpath,<somewhere1>/lib" --prefix=<somewhere3> --enable-lib-only --with-wolfssl
% make
% make install
Build curl
% cd ..
% git clone https://github.com/curl/curl
% cd curl
% autoreconf -fi
% ./configure --without-openssl --with-wolfssl=<somewhere1> --with-nghttp3=<somewhere2> --with-ngtcp2=<somewhere3>
% make
% make install
# quiche version # quiche version
## build ## build

View File

@ -38,6 +38,9 @@
#elif defined(USE_GNUTLS) #elif defined(USE_GNUTLS)
#include <ngtcp2/ngtcp2_crypto_gnutls.h> #include <ngtcp2/ngtcp2_crypto_gnutls.h>
#include "vtls/gtls.h" #include "vtls/gtls.h"
#elif defined(USE_WOLFSSL)
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
#include "vtls/wolfssl.h"
#endif #endif
#include "urldata.h" #include "urldata.h"
#include "sendf.h" #include "sendf.h"
@ -101,6 +104,11 @@ struct h3out {
"+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \ "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
"+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \ "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
"%DISABLE_TLS13_COMPAT_MODE" "%DISABLE_TLS13_COMPAT_MODE"
#elif defined(USE_WOLFSSL)
#define QUIC_CIPHERS \
"TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
"POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
#define QUIC_GROUPS "P-256:P-384:P-521"
#endif #endif
/* ngtcp2 default congestion controller does not perform pacing. Limit /* ngtcp2 default congestion controller does not perform pacing. Limit
@ -202,6 +210,12 @@ static int keylog_callback(gnutls_session_t session, const char *label,
Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size); Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
return 0; return 0;
} }
#elif defined(USE_WOLFSSL)
static void keylog_callback(const WOLFSSL *ssl, const char *line)
{
(void)ssl;
Curl_tls_keylog_write_line(line);
}
#endif #endif
static int init_ngh3_conn(struct quicsocket *qs); static int init_ngh3_conn(struct quicsocket *qs);
@ -395,7 +409,106 @@ static int quic_init_ssl(struct quicsocket *qs)
gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname)); gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
return 0; return 0;
} }
#elif defined(USE_WOLFSSL)
static WOLFSSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
WOLFSSL_CTX *ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
(void)wolfssl_logging;
if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) {
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
return NULL;
}
wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
if(wolfSSL_CTX_set_cipher_list(ssl_ctx, QUIC_CIPHERS) != 1) {
char error_buffer[256];
ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer);
return NULL;
}
if(wolfSSL_CTX_set1_groups_list(ssl_ctx, QUIC_GROUPS) != 1) {
failf(data, "SSL_CTX_set1_groups_list failed");
return NULL;
}
/* Open the file if a TLS or QUIC backend has not done this before. */
Curl_tls_keylog_open();
if(Curl_tls_keylog_enabled()) {
#if defined(HAVE_SECRET_CALLBACK)
wolfSSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
#else
failf(data, "wolfSSL was built without keylog callback");
return NULL;
#endif #endif
}
if(conn->ssl_config.verifypeer) {
const char * const ssl_cafile = conn->ssl_config.CAfile;
const char * const ssl_capath = conn->ssl_config.CApath;
if(ssl_cafile || ssl_capath) {
wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
/* tell wolfSSL where to find CA certificates that are used to verify
the server's certificate. */
if(!wolfSSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) {
/* 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 NULL;
}
infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
}
#ifdef CURL_CA_FALLBACK
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(ssl_ctx);
}
#endif
}
else {
wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
}
return ssl_ctx;
}
/** SSL callbacks ***/
static int quic_init_ssl(struct quicsocket *qs)
{
const uint8_t *alpn = NULL;
size_t alpnlen = 0;
/* this will need some attention when HTTPS proxy over QUIC get fixed */
const char * const hostname = qs->conn->host.name;
DEBUGASSERT(!qs->ssl);
qs->ssl = SSL_new(qs->sslctx);
wolfSSL_set_app_data(qs->ssl, &qs->conn_ref);
wolfSSL_set_connect_state(qs->ssl);
wolfSSL_set_quic_use_legacy_codepoint(qs->ssl, 0);
alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
if(alpn)
wolfSSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
/* set SNI */
wolfSSL_UseSNI(qs->ssl, WOLFSSL_SNI_HOST_NAME,
hostname, strlen(hostname));
return 0;
}
#endif /* defined(USE_WOLFSSL) */
static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data) static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
{ {
@ -691,6 +804,10 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
result = quic_set_client_cert(data, qs); result = quic_set_client_cert(data, qs);
if(result) if(result)
return result; return result;
#elif defined(USE_WOLFSSL)
qs->sslctx = quic_ssl_ctx(data);
if(!qs->sslctx)
return CURLE_QUIC_CONNECT_ERROR;
#endif #endif
if(quic_init_ssl(qs)) if(quic_init_ssl(qs))
@ -818,6 +935,8 @@ static void qs_disconnect(struct quicsocket *qs)
SSL_free(qs->ssl); SSL_free(qs->ssl);
#elif defined(USE_GNUTLS) #elif defined(USE_GNUTLS)
gnutls_deinit(qs->ssl); gnutls_deinit(qs->ssl);
#elif defined(USE_WOLFSSL)
wolfSSL_free(qs->ssl);
#endif #endif
qs->ssl = NULL; qs->ssl = NULL;
#ifdef USE_GNUTLS #ifdef USE_GNUTLS
@ -831,6 +950,8 @@ static void qs_disconnect(struct quicsocket *qs)
ngtcp2_conn_del(qs->qconn); ngtcp2_conn_del(qs->qconn);
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
SSL_CTX_free(qs->sslctx); SSL_CTX_free(qs->sslctx);
#elif defined(USE_WOLFSSL)
wolfSSL_CTX_free(qs->sslctx);
#endif #endif
} }
@ -1569,8 +1690,14 @@ static CURLcode ng_has_connected(struct Curl_easy *data,
if(result) if(result)
return result; return result;
infof(data, "Verified certificate just fine"); infof(data, "Verified certificate just fine");
#else #elif defined(USE_GNUTLS)
result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET); result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET);
#elif defined(USE_WOLFSSL)
char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
if(!snihost ||
(wolfSSL_check_domain_name(conn->quic->ssl, snihost) == SSL_FAILURE))
return CURLE_PEER_FAILED_VERIFICATION;
infof(data, "Verified certificate just fine");
#endif #endif
} }
else else

View File

@ -38,6 +38,10 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
#elif defined(USE_GNUTLS) #elif defined(USE_GNUTLS)
#include <gnutls/gnutls.h> #include <gnutls/gnutls.h>
#elif defined(USE_WOLFSSL)
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
#include <wolfssl/quic.h>
#endif #endif
struct blocked_pkt { struct blocked_pkt {
@ -62,6 +66,9 @@ struct quicsocket {
#elif defined(USE_GNUTLS) #elif defined(USE_GNUTLS)
gnutls_certificate_credentials_t cred; gnutls_certificate_credentials_t cred;
gnutls_session_t ssl; gnutls_session_t ssl;
#elif defined(USE_WOLFSSL)
WOLFSSL_CTX *sslctx;
WOLFSSL *ssl;
#endif #endif
struct sockaddr_storage local_addr; struct sockaddr_storage local_addr;
socklen_t local_addrlen; socklen_t local_addrlen;