vquic: add support for GnuTLS backend of ngtcp2
Currently, the TLS backend used by vquic/ngtcp2.c is selected at compile time. Therefore OpenSSL support needs to be explicitly disabled. Signed-off-by: Daiki Ueno <dueno@redhat.com> Closes #5148
This commit is contained in:
parent
e37dc71eae
commit
0736ee73d3
57
configure.ac
57
configure.ac
@ -3528,7 +3528,7 @@ if test X"$want_tcp2" != Xno; then
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "x$NGTCP2_ENABLED" = "x1"; then
|
if test "x$NGTCP2_ENABLED" = "x1" -a "x$OPENSSL_ENABLED" = "x1"; then
|
||||||
dnl backup the pre-ngtcp2_crypto_openssl variables
|
dnl backup the pre-ngtcp2_crypto_openssl variables
|
||||||
CLEANLDFLAGS="$LDFLAGS"
|
CLEANLDFLAGS="$LDFLAGS"
|
||||||
CLEANCPPFLAGS="$CPPFLAGS"
|
CLEANCPPFLAGS="$CPPFLAGS"
|
||||||
@ -3583,6 +3583,61 @@ if test "x$NGTCP2_ENABLED" = "x1"; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "x$NGTCP2_ENABLED" = "x1" -a "x$GNUTLS_ENABLED" = "x1"; then
|
||||||
|
dnl backup the pre-ngtcp2_crypto_gnutls variables
|
||||||
|
CLEANLDFLAGS="$LDFLAGS"
|
||||||
|
CLEANCPPFLAGS="$CPPFLAGS"
|
||||||
|
CLEANLIBS="$LIBS"
|
||||||
|
|
||||||
|
CURL_CHECK_PKGCONFIG(libngtcp2_crypto_gnutls, $want_tcp2_path)
|
||||||
|
|
||||||
|
if test "$PKGCONFIG" != "no" ; then
|
||||||
|
LIB_NGTCP2_CRYPTO_GNUTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path])
|
||||||
|
$PKGCONFIG --libs-only-l libngtcp2_crypto_gnutls`
|
||||||
|
AC_MSG_NOTICE([-l is $LIB_NGTCP2_CRYPTO_GNUTLS])
|
||||||
|
|
||||||
|
CPP_NGTCP2_CRYPTO_GNUTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path]) dnl
|
||||||
|
$PKGCONFIG --cflags-only-I libngtcp2_crypto_gnutls`
|
||||||
|
AC_MSG_NOTICE([-I is $CPP_NGTCP2_CRYPTO_GNUTLS])
|
||||||
|
|
||||||
|
LD_NGTCP2_CRYPTO_GNUTLS=`CURL_EXPORT_PCDIR([$want_tcp2_path])
|
||||||
|
$PKGCONFIG --libs-only-L libngtcp2_crypto_gnutls`
|
||||||
|
AC_MSG_NOTICE([-L is $LD_NGTCP2_CRYPTO_GNUTLS])
|
||||||
|
|
||||||
|
LDFLAGS="$LDFLAGS $LD_NGTCP2_CRYPTO_GNUTLS"
|
||||||
|
CPPFLAGS="$CPPFLAGS $CPP_NGTCP2_CRYPTO_GNUTLS"
|
||||||
|
LIBS="$LIB_NGTCP2_CRYPTO_GNUTLS $LIBS"
|
||||||
|
|
||||||
|
if test "x$cross_compiling" != "xyes"; then
|
||||||
|
DIR_NGTCP2_CRYPTO_GNUTLS=`echo $LD_NGTCP2_CRYPTO_GNUTLS | $SED -e 's/-L//'`
|
||||||
|
fi
|
||||||
|
AC_CHECK_LIB(ngtcp2_crypto_gnutls, ngtcp2_crypto_ctx_initial,
|
||||||
|
[
|
||||||
|
AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
|
||||||
|
NGTCP2_ENABLED=1
|
||||||
|
AC_DEFINE(USE_NGTCP2_CRYPTO_GNUTLS, 1, [if ngtcp2_crypto_gnutls is in use])
|
||||||
|
AC_SUBST(USE_NGTCP2_CRYPTO_GNUTLS, [1])
|
||||||
|
CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_GNUTLS"
|
||||||
|
export CURL_LIBRARY_PATH
|
||||||
|
AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH])
|
||||||
|
)
|
||||||
|
],
|
||||||
|
dnl not found, revert back to clean variables
|
||||||
|
LDFLAGS=$CLEANLDFLAGS
|
||||||
|
CPPFLAGS=$CLEANCPPFLAGS
|
||||||
|
LIBS=$CLEANLIBS
|
||||||
|
)
|
||||||
|
|
||||||
|
else
|
||||||
|
dnl no ngtcp2_crypto_gnutls 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_gnutls 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 **********************************************************************
|
||||||
|
|||||||
@ -29,7 +29,7 @@ in the master branch using pull-requests, just like ordinary changes.
|
|||||||
|
|
||||||
# ngtcp2 version
|
# ngtcp2 version
|
||||||
|
|
||||||
## Build
|
## Build with OpenSSL
|
||||||
|
|
||||||
Build (patched) OpenSSL
|
Build (patched) OpenSSL
|
||||||
|
|
||||||
@ -68,6 +68,46 @@ Build curl
|
|||||||
% LDFLAGS="-Wl,-rpath,<somewhere1>/lib" ./configure --with-ssl=<somewhere1> --with-nghttp3=<somewhere2> --with-ngtcp2=<somewhere3> --enable-alt-svc
|
% LDFLAGS="-Wl,-rpath,<somewhere1>/lib" ./configure --with-ssl=<somewhere1> --with-nghttp3=<somewhere2> --with-ngtcp2=<somewhere3> --enable-alt-svc
|
||||||
% make
|
% make
|
||||||
|
|
||||||
|
## Build with GnuTLS
|
||||||
|
|
||||||
|
Build (patched) GnuTLS
|
||||||
|
|
||||||
|
% git clone --depth 1 -b tmp-quic https://gitlab.com/gnutls/gnutls.git
|
||||||
|
% cd gnutls
|
||||||
|
% ./bootstrap
|
||||||
|
% ./configure --disable-doc --prefix=<somewhere1>
|
||||||
|
% make
|
||||||
|
% make install
|
||||||
|
|
||||||
|
Build nghttp3
|
||||||
|
|
||||||
|
% cd ..
|
||||||
|
% git clone https://github.com/ngtcp2/nghttp3
|
||||||
|
% cd nghttp3
|
||||||
|
% autoreconf -i
|
||||||
|
% ./configure --prefix=<somewhere2> --enable-lib-only
|
||||||
|
% make
|
||||||
|
% make install
|
||||||
|
|
||||||
|
Build ngtcp2
|
||||||
|
|
||||||
|
% cd ..
|
||||||
|
% git clone https://github.com/ngtcp2/ngtcp2
|
||||||
|
% cd ngtcp2
|
||||||
|
% autoreconf -i
|
||||||
|
% ./configure PKG_CONFIG_PATH=<somewhere1>/lib/pkgconfig:<somewhere2>/lib/pkgconfig LDFLAGS="-Wl,-rpath,<somewhere1>/lib" --prefix=<somewhere3>
|
||||||
|
% make
|
||||||
|
% make install
|
||||||
|
|
||||||
|
Build curl
|
||||||
|
|
||||||
|
% cd ..
|
||||||
|
% git clone https://github.com/curl/curl
|
||||||
|
% cd curl
|
||||||
|
% ./buildconf
|
||||||
|
% ./configure --without-ssl --with-gnutls=<somewhere1> --with-nghttp3=<somewhere2> --with-ngtcp2=<somewhere3> --enable-alt-svc
|
||||||
|
% make
|
||||||
|
|
||||||
# quiche version
|
# quiche version
|
||||||
|
|
||||||
## build
|
## build
|
||||||
|
|||||||
@ -26,7 +26,9 @@
|
|||||||
#include <ngtcp2/ngtcp2.h>
|
#include <ngtcp2/ngtcp2.h>
|
||||||
#include <ngtcp2/ngtcp2_crypto.h>
|
#include <ngtcp2/ngtcp2_crypto.h>
|
||||||
#include <nghttp3/nghttp3.h>
|
#include <nghttp3/nghttp3.h>
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#endif
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
#include "sendf.h"
|
#include "sendf.h"
|
||||||
#include "strdup.h"
|
#include "strdup.h"
|
||||||
@ -69,10 +71,18 @@ struct h3out {
|
|||||||
#define QUIC_MAX_STREAMS (256*1024)
|
#define QUIC_MAX_STREAMS (256*1024)
|
||||||
#define QUIC_MAX_DATA (1*1024*1024)
|
#define QUIC_MAX_DATA (1*1024*1024)
|
||||||
#define QUIC_IDLE_TIMEOUT 60000 /* milliseconds */
|
#define QUIC_IDLE_TIMEOUT 60000 /* milliseconds */
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
#define QUIC_CIPHERS \
|
#define QUIC_CIPHERS \
|
||||||
"TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
|
"TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
|
||||||
"POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
|
"POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
|
||||||
#define QUIC_GROUPS "P-256:X25519:P-384:P-521"
|
#define QUIC_GROUPS "P-256:X25519:P-384:P-521"
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
#define QUIC_PRIORITY \
|
||||||
|
"NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
|
||||||
|
"+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
|
||||||
|
"+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1"
|
||||||
|
#endif
|
||||||
|
|
||||||
static CURLcode ng_process_ingress(struct connectdata *conn,
|
static CURLcode ng_process_ingress(struct connectdata *conn,
|
||||||
curl_socket_t sockfd,
|
curl_socket_t sockfd,
|
||||||
@ -101,6 +111,7 @@ static void quic_printf(void *user_data, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
static ngtcp2_crypto_level
|
static ngtcp2_crypto_level
|
||||||
quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)
|
quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)
|
||||||
{
|
{
|
||||||
@ -117,6 +128,24 @@ quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
static ngtcp2_crypto_level
|
||||||
|
quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level)
|
||||||
|
{
|
||||||
|
switch(gtls_level) {
|
||||||
|
case GNUTLS_ENCRYPTION_LEVEL_INITIAL:
|
||||||
|
return NGTCP2_CRYPTO_LEVEL_INITIAL;
|
||||||
|
case GNUTLS_ENCRYPTION_LEVEL_EARLY:
|
||||||
|
return NGTCP2_CRYPTO_LEVEL_EARLY;
|
||||||
|
case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE:
|
||||||
|
return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
|
||||||
|
case GNUTLS_ENCRYPTION_LEVEL_APPLICATION:
|
||||||
|
return NGTCP2_CRYPTO_LEVEL_APP;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int setup_initial_crypto_context(struct quicsocket *qs)
|
static int setup_initial_crypto_context(struct quicsocket *qs)
|
||||||
{
|
{
|
||||||
@ -150,6 +179,7 @@ static void quic_settings(ngtcp2_settings *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FILE *keylog_file; /* not thread-safe */
|
static FILE *keylog_file; /* not thread-safe */
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
static void keylog_callback(const SSL *ssl, const char *line)
|
static void keylog_callback(const SSL *ssl, const char *line)
|
||||||
{
|
{
|
||||||
(void)ssl;
|
(void)ssl;
|
||||||
@ -157,9 +187,81 @@ static void keylog_callback(const SSL *ssl, const char *line)
|
|||||||
fputc('\n', keylog_file);
|
fputc('\n', keylog_file);
|
||||||
fflush(keylog_file);
|
fflush(keylog_file);
|
||||||
}
|
}
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
static int keylog_callback(gnutls_session_t session, const char *label,
|
||||||
|
const gnutls_datum_t *secret)
|
||||||
|
{
|
||||||
|
gnutls_datum_t crandom;
|
||||||
|
gnutls_datum_t srandom;
|
||||||
|
gnutls_datum_t crandom_hex = { NULL, 0 };
|
||||||
|
gnutls_datum_t secret_hex = { NULL, 0 };
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
gnutls_session_get_random(session, &crandom, &srandom);
|
||||||
|
if(crandom.size != 32) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_hex_encode2(&crandom, &crandom_hex);
|
||||||
|
if(rc < 0) {
|
||||||
|
fprintf(stderr, "gnutls_hex_encode2 failed: %s\n",
|
||||||
|
gnutls_strerror(rc));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_hex_encode2(secret, &secret_hex);
|
||||||
|
if(rc < 0) {
|
||||||
|
fprintf(stderr, "gnutls_hex_encode2 failed: %s\n",
|
||||||
|
gnutls_strerror(rc));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(keylog_file, "%s %s %s\n", label, crandom_hex.data, secret_hex.data);
|
||||||
|
fflush(keylog_file);
|
||||||
|
|
||||||
|
out:
|
||||||
|
gnutls_free(crandom_hex.data);
|
||||||
|
gnutls_free(secret_hex.data);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int init_ngh3_conn(struct quicsocket *qs);
|
static int init_ngh3_conn(struct quicsocket *qs);
|
||||||
|
|
||||||
|
static int write_client_handshake(struct quicsocket *qs,
|
||||||
|
ngtcp2_crypto_level level,
|
||||||
|
const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
struct quic_handshake *crypto_data;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
crypto_data = &qs->crypto_data[level];
|
||||||
|
if(crypto_data->buf == NULL) {
|
||||||
|
crypto_data->buf = malloc(4096);
|
||||||
|
if(!crypto_data->buf)
|
||||||
|
return 0;
|
||||||
|
crypto_data->alloclen = 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO Just pretend that handshake does not grow more than 4KiB for
|
||||||
|
now */
|
||||||
|
assert(crypto_data->len + len <= crypto_data->alloclen);
|
||||||
|
|
||||||
|
memcpy(&crypto_data->buf[crypto_data->len], data, len);
|
||||||
|
crypto_data->len += len;
|
||||||
|
|
||||||
|
rv = ngtcp2_conn_submit_crypto_data(
|
||||||
|
qs->qconn, level, (uint8_t *)(&crypto_data->buf[crypto_data->len] - len),
|
||||||
|
len);
|
||||||
|
if(rv) {
|
||||||
|
H3BUGF(fprintf(stderr, "write_client_handshake failed\n"));
|
||||||
|
}
|
||||||
|
assert(0 == rv);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
static int quic_set_encryption_secrets(SSL *ssl,
|
static int quic_set_encryption_secrets(SSL *ssl,
|
||||||
OSSL_ENCRYPTION_LEVEL ossl_level,
|
OSSL_ENCRYPTION_LEVEL ossl_level,
|
||||||
const uint8_t *rx_secret,
|
const uint8_t *rx_secret,
|
||||||
@ -190,34 +292,9 @@ static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
|
|||||||
const uint8_t *data, size_t len)
|
const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
|
struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
|
||||||
struct quic_handshake *crypto_data;
|
|
||||||
ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level);
|
ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level);
|
||||||
int rv;
|
|
||||||
|
|
||||||
crypto_data = &qs->crypto_data[level];
|
return write_client_handshake(qs, level, data, len);
|
||||||
if(crypto_data->buf == NULL) {
|
|
||||||
crypto_data->buf = malloc(4096);
|
|
||||||
if(!crypto_data->buf)
|
|
||||||
return 0;
|
|
||||||
crypto_data->alloclen = 4096;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO Just pretend that handshake does not grow more than 4KiB for
|
|
||||||
now */
|
|
||||||
assert(crypto_data->len + len <= crypto_data->alloclen);
|
|
||||||
|
|
||||||
memcpy(&crypto_data->buf[crypto_data->len], data, len);
|
|
||||||
crypto_data->len += len;
|
|
||||||
|
|
||||||
rv = ngtcp2_conn_submit_crypto_data(
|
|
||||||
qs->qconn, level, (uint8_t *)(&crypto_data->buf[crypto_data->len] - len),
|
|
||||||
len);
|
|
||||||
if(rv) {
|
|
||||||
H3BUGF(fprintf(stderr, "write_client_handshake failed\n"));
|
|
||||||
}
|
|
||||||
assert(0 == rv);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quic_flush_flight(SSL *ssl)
|
static int quic_flush_flight(SSL *ssl)
|
||||||
@ -307,6 +384,193 @@ static int quic_init_ssl(struct quicsocket *qs)
|
|||||||
SSL_set_tlsext_host_name(qs->ssl, hostname);
|
SSL_set_tlsext_host_name(qs->ssl, hostname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
static int secret_func(gnutls_session_t ssl,
|
||||||
|
gnutls_record_encryption_level_t gtls_level,
|
||||||
|
const void *rx_secret,
|
||||||
|
const void *tx_secret, size_t secretlen)
|
||||||
|
{
|
||||||
|
struct quicsocket *qs = gnutls_session_get_ptr(ssl);
|
||||||
|
int level = quic_from_gtls_level(gtls_level);
|
||||||
|
|
||||||
|
if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
|
||||||
|
ngtcp2_crypto_derive_and_install_rx_key(
|
||||||
|
qs->qconn, ssl, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(ngtcp2_crypto_derive_and_install_tx_key(
|
||||||
|
qs->qconn, ssl, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(level == NGTCP2_CRYPTO_LEVEL_APP) {
|
||||||
|
if(init_ngh3_conn(qs) != CURLE_OK)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_func(gnutls_session_t ssl,
|
||||||
|
gnutls_record_encryption_level_t gtls_level,
|
||||||
|
gnutls_handshake_description_t htype, const void *data,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct quicsocket *qs = gnutls_session_get_ptr(ssl);
|
||||||
|
ngtcp2_crypto_level level = quic_from_gtls_level(gtls_level);
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if(htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rv = write_client_handshake(qs, level, data, len);
|
||||||
|
if(rv == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alert_read_func(gnutls_session_t ssl,
|
||||||
|
gnutls_record_encryption_level_t gtls_level,
|
||||||
|
gnutls_alert_level_t alert_level,
|
||||||
|
gnutls_alert_description_t alert_desc)
|
||||||
|
{
|
||||||
|
struct quicsocket *qs = gnutls_session_get_ptr(ssl);
|
||||||
|
(void)gtls_level;
|
||||||
|
(void)alert_level;
|
||||||
|
|
||||||
|
qs->tls_alert = alert_desc;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tp_recv_func(gnutls_session_t ssl, const uint8_t *data,
|
||||||
|
size_t data_size)
|
||||||
|
{
|
||||||
|
struct quicsocket *qs = gnutls_session_get_ptr(ssl);
|
||||||
|
ngtcp2_transport_params params;
|
||||||
|
|
||||||
|
if(ngtcp2_decode_transport_params(
|
||||||
|
¶ms, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS,
|
||||||
|
data, data_size) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(ngtcp2_conn_set_remote_transport_params(qs->qconn, ¶ms) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata)
|
||||||
|
{
|
||||||
|
struct quicsocket *qs = gnutls_session_get_ptr(ssl);
|
||||||
|
uint8_t paramsbuf[64];
|
||||||
|
ngtcp2_transport_params params;
|
||||||
|
ssize_t nwrite;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms);
|
||||||
|
nwrite = ngtcp2_encode_transport_params(
|
||||||
|
paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
|
||||||
|
¶ms);
|
||||||
|
if(nwrite < 0) {
|
||||||
|
fprintf(stderr, "ngtcp2_encode_transport_params: %s\n",
|
||||||
|
ngtcp2_strerror((int)nwrite));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_buffer_append_data(extdata, paramsbuf, nwrite);
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return (int)nwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int quic_init_ssl(struct quicsocket *qs)
|
||||||
|
{
|
||||||
|
gnutls_datum_t alpn = {NULL, 0};
|
||||||
|
/* this will need some attention when HTTPS proxy over QUIC get fixed */
|
||||||
|
const char * const hostname = qs->conn->host.name;
|
||||||
|
const char *keylog_filename;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if(qs->ssl)
|
||||||
|
gnutls_deinit(qs->ssl);
|
||||||
|
|
||||||
|
gnutls_init(&qs->ssl, GNUTLS_CLIENT);
|
||||||
|
gnutls_session_set_ptr(qs->ssl, qs);
|
||||||
|
|
||||||
|
rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL);
|
||||||
|
if(rc < 0) {
|
||||||
|
fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
|
||||||
|
gnutls_strerror(rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnutls_handshake_set_secret_function(qs->ssl, secret_func);
|
||||||
|
gnutls_handshake_set_read_function(qs->ssl, read_func);
|
||||||
|
gnutls_alert_set_read_function(qs->ssl, alert_read_func);
|
||||||
|
|
||||||
|
rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters",
|
||||||
|
0xffa5, GNUTLS_EXT_TLS,
|
||||||
|
tp_recv_func, tp_send_func,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
GNUTLS_EXT_FLAG_TLS |
|
||||||
|
GNUTLS_EXT_FLAG_CLIENT_HELLO |
|
||||||
|
GNUTLS_EXT_FLAG_EE);
|
||||||
|
if(rc < 0) {
|
||||||
|
fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
|
||||||
|
gnutls_strerror(rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
keylog_filename = getenv("SSLKEYLOGFILE");
|
||||||
|
if(keylog_filename) {
|
||||||
|
keylog_file = fopen(keylog_filename, "wb");
|
||||||
|
if(keylog_file) {
|
||||||
|
gnutls_session_set_keylog_function(qs->ssl, keylog_callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(qs->cred)
|
||||||
|
gnutls_certificate_free_credentials(qs->cred);
|
||||||
|
|
||||||
|
rc = gnutls_certificate_allocate_credentials(&qs->cred);
|
||||||
|
if(rc < 0) {
|
||||||
|
fprintf(stderr, "gnutls_certificate_allocate_credentials failed: %s\n",
|
||||||
|
gnutls_strerror(rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_certificate_set_x509_system_trust(qs->cred);
|
||||||
|
if(rc < 0) {
|
||||||
|
fprintf(stderr, "gnutls_certificate_set_x509_system_trust failed: %s\n",
|
||||||
|
gnutls_strerror(rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred);
|
||||||
|
if(rc < 0) {
|
||||||
|
fprintf(stderr, "gnutls_credentials_set failed: %s\n",
|
||||||
|
gnutls_strerror(rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(qs->version) {
|
||||||
|
#ifdef NGTCP2_PROTO_VER
|
||||||
|
case NGTCP2_PROTO_VER:
|
||||||
|
/* strip the first byte from NGTCP2_ALPN_H3 */
|
||||||
|
alpn.data = (unsigned char *)NGTCP2_ALPN_H3 + 1;
|
||||||
|
alpn.size = sizeof(NGTCP2_ALPN_H3) - 2;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if(alpn.data)
|
||||||
|
gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0);
|
||||||
|
|
||||||
|
/* set SNI */
|
||||||
|
gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int cb_initial(ngtcp2_conn *quic, void *user_data)
|
static int cb_initial(ngtcp2_conn *quic, void *user_data)
|
||||||
{
|
{
|
||||||
@ -560,9 +824,11 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
|
|||||||
struct quicsocket *qs = &conn->hequic[sockindex];
|
struct quicsocket *qs = &conn->hequic[sockindex];
|
||||||
char ipbuf[40];
|
char ipbuf[40];
|
||||||
long port;
|
long port;
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
uint8_t paramsbuf[64];
|
uint8_t paramsbuf[64];
|
||||||
ngtcp2_transport_params params;
|
ngtcp2_transport_params params;
|
||||||
ssize_t nwrite;
|
ssize_t nwrite;
|
||||||
|
#endif
|
||||||
|
|
||||||
qs->conn = conn;
|
qs->conn = conn;
|
||||||
|
|
||||||
@ -578,9 +844,11 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
|
|||||||
sockfd, ipbuf, port);
|
sockfd, ipbuf, port);
|
||||||
|
|
||||||
qs->version = NGTCP2_PROTO_VER;
|
qs->version = NGTCP2_PROTO_VER;
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
qs->sslctx = quic_ssl_ctx(data);
|
qs->sslctx = quic_ssl_ctx(data);
|
||||||
if(!qs->sslctx)
|
if(!qs->sslctx)
|
||||||
return CURLE_QUIC_CONNECT_ERROR;
|
return CURLE_QUIC_CONNECT_ERROR;
|
||||||
|
#endif
|
||||||
|
|
||||||
if(quic_init_ssl(qs))
|
if(quic_init_ssl(qs))
|
||||||
return CURLE_QUIC_CONNECT_ERROR;
|
return CURLE_QUIC_CONNECT_ERROR;
|
||||||
@ -617,6 +885,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
|
|||||||
if(rc)
|
if(rc)
|
||||||
return CURLE_QUIC_CONNECT_ERROR;
|
return CURLE_QUIC_CONNECT_ERROR;
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms);
|
ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms);
|
||||||
nwrite = ngtcp2_encode_transport_params(
|
nwrite = ngtcp2_encode_transport_params(
|
||||||
paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
|
paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
|
||||||
@ -629,6 +898,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
|
|||||||
|
|
||||||
if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite))
|
if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite))
|
||||||
return CURLE_QUIC_CONNECT_ERROR;
|
return CURLE_QUIC_CONNECT_ERROR;
|
||||||
|
#endif
|
||||||
|
|
||||||
rc = setup_initial_crypto_context(qs);
|
rc = setup_initial_crypto_context(qs);
|
||||||
if(rc)
|
if(rc)
|
||||||
@ -680,12 +950,22 @@ static CURLcode ng_disconnect(struct connectdata *conn,
|
|||||||
struct quicsocket *qs = &conn->hequic[0];
|
struct quicsocket *qs = &conn->hequic[0];
|
||||||
(void)dead_connection;
|
(void)dead_connection;
|
||||||
if(qs->ssl)
|
if(qs->ssl)
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
SSL_free(qs->ssl);
|
SSL_free(qs->ssl);
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
gnutls_deinit(qs->ssl);
|
||||||
|
#endif
|
||||||
|
#ifdef USE_GNUTLS
|
||||||
|
if(qs->cred)
|
||||||
|
gnutls_certificate_free_credentials(qs->cred);
|
||||||
|
#endif
|
||||||
for(i = 0; i < 3; i++)
|
for(i = 0; i < 3; i++)
|
||||||
free(qs->crypto_data[i].buf);
|
free(qs->crypto_data[i].buf);
|
||||||
nghttp3_conn_del(qs->h3conn);
|
nghttp3_conn_del(qs->h3conn);
|
||||||
ngtcp2_conn_del(qs->qconn);
|
ngtcp2_conn_del(qs->qconn);
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
SSL_CTX_free(qs->sslctx);
|
SSL_CTX_free(qs->sslctx);
|
||||||
|
#endif
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,11 @@
|
|||||||
|
|
||||||
#include <ngtcp2/ngtcp2.h>
|
#include <ngtcp2/ngtcp2.h>
|
||||||
#include <nghttp3/nghttp3.h>
|
#include <nghttp3/nghttp3.h>
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
#include <gnutls/gnutls.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
struct quic_handshake {
|
struct quic_handshake {
|
||||||
char *buf; /* pointer to the buffer */
|
char *buf; /* pointer to the buffer */
|
||||||
@ -44,8 +48,13 @@ struct quicsocket {
|
|||||||
ngtcp2_cid scid;
|
ngtcp2_cid scid;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
ngtcp2_settings settings;
|
ngtcp2_settings settings;
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
SSL_CTX *sslctx;
|
SSL_CTX *sslctx;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
|
#elif defined(USE_GNUTLS)
|
||||||
|
gnutls_certificate_credentials_t cred;
|
||||||
|
gnutls_session_t ssl;
|
||||||
|
#endif
|
||||||
struct quic_handshake crypto_data[3];
|
struct quic_handshake crypto_data[3];
|
||||||
/* the last TLS alert description generated by the local endpoint */
|
/* the last TLS alert description generated by the local endpoint */
|
||||||
uint8_t tls_alert;
|
uint8_t tls_alert;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user