|
@@ -41,7 +41,6 @@
|
|
|
#include "vtls/gtls.h"
|
|
|
#elif defined(USE_WOLFSSL)
|
|
|
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
|
|
|
-#include "vtls/wolfssl.h"
|
|
|
#endif
|
|
|
|
|
|
#include "urldata.h"
|
|
@@ -61,6 +60,7 @@
|
|
|
#include "inet_pton.h"
|
|
|
#include "vquic.h"
|
|
|
#include "vquic_int.h"
|
|
|
+#include "vquic-tls.h"
|
|
|
#include "vtls/keylog.h"
|
|
|
#include "vtls/vtls.h"
|
|
|
#include "curl_ngtcp2.h"
|
|
@@ -73,9 +73,6 @@
|
|
|
#include "memdebug.h"
|
|
|
|
|
|
|
|
|
-#define H3_ALPN_H3_29 "\x5h3-29"
|
|
|
-#define H3_ALPN_H3 "\x2h3"
|
|
|
-
|
|
|
#define QUIC_MAX_STREAMS (256*1024)
|
|
|
#define QUIC_MAX_DATA (1*1024*1024)
|
|
|
#define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS)
|
|
@@ -101,25 +98,6 @@
|
|
|
(H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
|
|
|
|
|
|
|
|
|
-#ifdef USE_OPENSSL
|
|
|
-#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: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:" \
|
|
|
- "%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
|
|
|
-
|
|
|
-
|
|
|
/*
|
|
|
* Store ngtcp2 version info in this buffer.
|
|
|
*/
|
|
@@ -134,6 +112,7 @@ void Curl_ngtcp2_ver(char *p, size_t len)
|
|
|
struct cf_ngtcp2_ctx {
|
|
|
struct cf_quic_ctx q;
|
|
|
struct ssl_peer peer;
|
|
|
+ struct quic_tls_ctx tls;
|
|
|
ngtcp2_path connected_path;
|
|
|
ngtcp2_conn *qconn;
|
|
|
ngtcp2_cid dcid;
|
|
@@ -143,30 +122,16 @@ struct cf_ngtcp2_ctx {
|
|
|
ngtcp2_transport_params transport_params;
|
|
|
ngtcp2_ccerr last_error;
|
|
|
ngtcp2_crypto_conn_ref conn_ref;
|
|
|
-#ifdef USE_OPENSSL
|
|
|
- SSL_CTX *sslctx;
|
|
|
- SSL *ssl;
|
|
|
-#elif defined(USE_GNUTLS)
|
|
|
- struct gtls_instance *gtls;
|
|
|
-#elif defined(USE_WOLFSSL)
|
|
|
- WOLFSSL_CTX *sslctx;
|
|
|
- WOLFSSL *ssl;
|
|
|
-#endif
|
|
|
struct cf_call_data call_data;
|
|
|
nghttp3_conn *h3conn;
|
|
|
nghttp3_settings h3settings;
|
|
|
struct curltime started_at; /* time the current attempt started */
|
|
|
struct curltime handshake_at; /* time connect handshake finished */
|
|
|
- struct curltime first_byte_at; /* when first byte was recvd */
|
|
|
struct curltime reconnect_at; /* time the next attempt should start */
|
|
|
struct bufc_pool stream_bufcp; /* chunk pool for streams */
|
|
|
size_t max_stream_window; /* max flow window for one stream */
|
|
|
uint64_t max_idle_ms; /* max idle time for QUIC connection */
|
|
|
int qlogfd;
|
|
|
- BIT(got_first_byte); /* if first byte was received */
|
|
|
-#ifdef USE_OPENSSL
|
|
|
- BIT(x509_store_setup); /* if x509 store has been set up */
|
|
|
-#endif
|
|
|
};
|
|
|
|
|
|
/* How to access `call_data` from a cf_ngtcp2 filter */
|
|
@@ -413,388 +378,8 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#ifdef USE_OPENSSL
|
|
|
-static void keylog_callback(const SSL *ssl, const char *line)
|
|
|
-{
|
|
|
- (void)ssl;
|
|
|
- Curl_tls_keylog_write_line(line);
|
|
|
-}
|
|
|
-#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_session_get_random(session, &crandom, &srandom);
|
|
|
- if(crandom.size != 32) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-#elif defined(USE_WOLFSSL)
|
|
|
-#if defined(HAVE_SECRET_CALLBACK)
|
|
|
-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 Curl_cfilter *cf);
|
|
|
|
|
|
-#ifdef USE_OPENSSL
|
|
|
-static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx,
|
|
|
- struct Curl_cfilter *cf, struct Curl_easy *data)
|
|
|
-{
|
|
|
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
|
|
- struct ssl_primary_config *conn_config;
|
|
|
- CURLcode result = CURLE_FAILED_INIT;
|
|
|
-
|
|
|
- SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
|
|
|
- if(!ssl_ctx) {
|
|
|
- result = CURLE_OUT_OF_MEMORY;
|
|
|
- goto out;
|
|
|
- }
|
|
|
- conn_config = Curl_ssl_cf_get_primary_config(cf);
|
|
|
- if(!conn_config) {
|
|
|
- result = CURLE_FAILED_INIT;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
-#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
|
|
|
- if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) {
|
|
|
- failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
|
|
|
- goto out;
|
|
|
- }
|
|
|
-#else
|
|
|
- if(ngtcp2_crypto_quictls_configure_client_context(ssl_ctx) != 0) {
|
|
|
- failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
|
|
|
- goto out;
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- SSL_CTX_set_default_verify_paths(ssl_ctx);
|
|
|
-
|
|
|
- {
|
|
|
- const char *curves = conn_config->curves ?
|
|
|
- conn_config->curves : QUIC_GROUPS;
|
|
|
- if(!SSL_CTX_set1_curves_list(ssl_ctx, curves)) {
|
|
|
- failf(data, "failed setting curves list for QUIC: '%s'", curves);
|
|
|
- return CURLE_SSL_CIPHER;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-#ifndef OPENSSL_IS_BORINGSSL
|
|
|
- {
|
|
|
- const char *ciphers13 = conn_config->cipher_list13 ?
|
|
|
- conn_config->cipher_list13 : QUIC_CIPHERS;
|
|
|
- if(SSL_CTX_set_ciphersuites(ssl_ctx, ciphers13) != 1) {
|
|
|
- failf(data, "failed setting QUIC cipher suite: %s", ciphers13);
|
|
|
- return CURLE_SSL_CIPHER;
|
|
|
- }
|
|
|
- infof(data, "QUIC cipher selection: %s", ciphers13);
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- /* Open the file if a TLS or QUIC backend has not done this before. */
|
|
|
- Curl_tls_keylog_open();
|
|
|
- if(Curl_tls_keylog_enabled()) {
|
|
|
- SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
|
|
|
- }
|
|
|
-
|
|
|
- /* OpenSSL always tries to verify the peer, this only says whether it should
|
|
|
- * fail to connect if the verification fails, or if it should continue
|
|
|
- * anyway. In the latter case the result of the verification is checked with
|
|
|
- * SSL_get_verify_result() below. */
|
|
|
- SSL_CTX_set_verify(ssl_ctx, conn_config->verifypeer ?
|
|
|
- SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
|
|
|
-
|
|
|
- /* give application a chance to interfere with SSL set up. */
|
|
|
- if(data->set.ssl.fsslctx) {
|
|
|
- /* When a user callback is installed to modify the SSL_CTX,
|
|
|
- * we need to do the full initialization before calling it.
|
|
|
- * See: #11800 */
|
|
|
- if(!ctx->x509_store_setup) {
|
|
|
- result = Curl_ssl_setup_x509_store(cf, data, ssl_ctx);
|
|
|
- if(result)
|
|
|
- goto out;
|
|
|
- ctx->x509_store_setup = TRUE;
|
|
|
- }
|
|
|
- Curl_set_in_callback(data, true);
|
|
|
- result = (*data->set.ssl.fsslctx)(data, ssl_ctx,
|
|
|
- data->set.ssl.fsslctxp);
|
|
|
- Curl_set_in_callback(data, false);
|
|
|
- if(result) {
|
|
|
- failf(data, "error signaled by ssl ctx callback");
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
- result = CURLE_OK;
|
|
|
-
|
|
|
-out:
|
|
|
- *pssl_ctx = result? NULL : ssl_ctx;
|
|
|
- if(result && ssl_ctx)
|
|
|
- SSL_CTX_free(ssl_ctx);
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-static CURLcode quic_set_client_cert(struct Curl_cfilter *cf,
|
|
|
- struct Curl_easy *data)
|
|
|
-{
|
|
|
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
|
|
- SSL_CTX *ssl_ctx = ctx->sslctx;
|
|
|
- const struct ssl_config_data *ssl_config;
|
|
|
-
|
|
|
- ssl_config = Curl_ssl_cf_get_config(cf, data);
|
|
|
- DEBUGASSERT(ssl_config);
|
|
|
-
|
|
|
- if(ssl_config->primary.clientcert || ssl_config->primary.cert_blob
|
|
|
- || ssl_config->cert_type) {
|
|
|
- return Curl_ossl_set_client_cert(
|
|
|
- data, ssl_ctx, ssl_config->primary.clientcert,
|
|
|
- ssl_config->primary.cert_blob, ssl_config->cert_type,
|
|
|
- ssl_config->key, ssl_config->key_blob,
|
|
|
- ssl_config->key_type, ssl_config->key_passwd);
|
|
|
- }
|
|
|
-
|
|
|
- return CURLE_OK;
|
|
|
-}
|
|
|
-
|
|
|
-/** SSL callbacks ***/
|
|
|
-
|
|
|
-static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
|
|
|
- struct Curl_easy *data)
|
|
|
-{
|
|
|
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
|
|
- const uint8_t *alpn = NULL;
|
|
|
- size_t alpnlen = 0;
|
|
|
-
|
|
|
- DEBUGASSERT(!ctx->ssl);
|
|
|
- ctx->ssl = SSL_new(ctx->sslctx);
|
|
|
-
|
|
|
- SSL_set_app_data(ctx->ssl, &ctx->conn_ref);
|
|
|
- SSL_set_connect_state(ctx->ssl);
|
|
|
- SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
|
|
|
-
|
|
|
- alpn = (const uint8_t *)H3_ALPN_H3 H3_ALPN_H3_29;
|
|
|
- alpnlen = sizeof(H3_ALPN_H3) - 1 + sizeof(H3_ALPN_H3_29) - 1;
|
|
|
- if(alpn)
|
|
|
- SSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen);
|
|
|
-
|
|
|
- /* set SNI */
|
|
|
- if(ctx->peer.sni) {
|
|
|
- if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->peer.sni)) {
|
|
|
- failf(data, "Failed set SNI");
|
|
|
- SSL_free(ctx->ssl);
|
|
|
- ctx->ssl = NULL;
|
|
|
- return CURLE_QUIC_CONNECT_ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- return CURLE_OK;
|
|
|
-}
|
|
|
-#elif defined(USE_GNUTLS)
|
|
|
-static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
|
|
|
- struct Curl_easy *data)
|
|
|
-{
|
|
|
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
|
|
- struct ssl_primary_config *conn_config;
|
|
|
- CURLcode result;
|
|
|
- gnutls_datum_t alpn[2];
|
|
|
- /* this will need some attention when HTTPS proxy over QUIC get fixed */
|
|
|
- long * const pverifyresult = &data->set.ssl.certverifyresult;
|
|
|
- int rc;
|
|
|
-
|
|
|
- conn_config = Curl_ssl_cf_get_primary_config(cf);
|
|
|
- if(!conn_config)
|
|
|
- return CURLE_FAILED_INIT;
|
|
|
-
|
|
|
- DEBUGASSERT(ctx->gtls == NULL);
|
|
|
- ctx->gtls = calloc(1, sizeof(*(ctx->gtls)));
|
|
|
- if(!ctx->gtls)
|
|
|
- return CURLE_OUT_OF_MEMORY;
|
|
|
-
|
|
|
- result = gtls_client_init(data, conn_config, &data->set.ssl,
|
|
|
- &ctx->peer, ctx->gtls, pverifyresult);
|
|
|
- if(result)
|
|
|
- return result;
|
|
|
-
|
|
|
- gnutls_session_set_ptr(ctx->gtls->session, &ctx->conn_ref);
|
|
|
-
|
|
|
- if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) {
|
|
|
- CURL_TRC_CF(data, cf,
|
|
|
- "ngtcp2_crypto_gnutls_configure_client_session failed\n");
|
|
|
- return CURLE_QUIC_CONNECT_ERROR;
|
|
|
- }
|
|
|
-
|
|
|
- rc = gnutls_priority_set_direct(ctx->gtls->session, QUIC_PRIORITY, NULL);
|
|
|
- if(rc < 0) {
|
|
|
- CURL_TRC_CF(data, cf, "gnutls_priority_set_direct failed: %s\n",
|
|
|
- gnutls_strerror(rc));
|
|
|
- return CURLE_QUIC_CONNECT_ERROR;
|
|
|
- }
|
|
|
-
|
|
|
- /* Open the file if a TLS or QUIC backend has not done this before. */
|
|
|
- Curl_tls_keylog_open();
|
|
|
- if(Curl_tls_keylog_enabled()) {
|
|
|
- gnutls_session_set_keylog_function(ctx->gtls->session, keylog_callback);
|
|
|
- }
|
|
|
-
|
|
|
- /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
|
|
|
- alpn[0].data = (unsigned char *)H3_ALPN_H3 + 1;
|
|
|
- alpn[0].size = sizeof(H3_ALPN_H3) - 2;
|
|
|
- alpn[1].data = (unsigned char *)H3_ALPN_H3_29 + 1;
|
|
|
- alpn[1].size = sizeof(H3_ALPN_H3_29) - 2;
|
|
|
-
|
|
|
- gnutls_alpn_set_protocols(ctx->gtls->session,
|
|
|
- alpn, 2, GNUTLS_ALPN_MANDATORY);
|
|
|
- return CURLE_OK;
|
|
|
-}
|
|
|
-#elif defined(USE_WOLFSSL)
|
|
|
-
|
|
|
-static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx,
|
|
|
- struct Curl_cfilter *cf, struct Curl_easy *data)
|
|
|
-{
|
|
|
- CURLcode result = CURLE_FAILED_INIT;
|
|
|
- struct ssl_primary_config *conn_config;
|
|
|
- WOLFSSL_CTX *ssl_ctx = NULL;
|
|
|
-
|
|
|
- conn_config = Curl_ssl_cf_get_primary_config(cf);
|
|
|
- if(!conn_config) {
|
|
|
- result = CURLE_FAILED_INIT;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
|
|
- if(!ssl_ctx) {
|
|
|
- result = CURLE_OUT_OF_MEMORY;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) {
|
|
|
- failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
|
|
|
- result = CURLE_FAILED_INIT;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
|
|
|
-
|
|
|
- if(wolfSSL_CTX_set_cipher_list(ssl_ctx, conn_config->cipher_list13 ?
|
|
|
- conn_config->cipher_list13 :
|
|
|
- QUIC_CIPHERS) != 1) {
|
|
|
- char error_buffer[256];
|
|
|
- ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
|
|
|
- failf(data, "wolfSSL failed to set ciphers: %s", error_buffer);
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- if(wolfSSL_CTX_set1_groups_list(ssl_ctx, conn_config->curves ?
|
|
|
- conn_config->curves :
|
|
|
- (char *)QUIC_GROUPS) != 1) {
|
|
|
- failf(data, "wolfSSL failed to set curves");
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- /* 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");
|
|
|
- goto out;
|
|
|
-#endif
|
|
|
- }
|
|
|
-
|
|
|
- if(conn_config->verifypeer) {
|
|
|
- const char * const ssl_cafile = conn_config->CAfile;
|
|
|
- const char * const ssl_capath = conn_config->CApath;
|
|
|
-
|
|
|
- wolfSSL_CTX_set_verify(ssl_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(ssl_ctx, ssl_cafile, ssl_capath,
|
|
|
- WOLFSSL_LOAD_FLAG_IGNORE_ERR);
|
|
|
- if(SSL_SUCCESS != rc) {
|
|
|
- /* 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");
|
|
|
- goto out;
|
|
|
- }
|
|
|
- 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);
|
|
|
- }
|
|
|
-
|
|
|
- /* 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, ssl_ctx,
|
|
|
- data->set.ssl.fsslctxp);
|
|
|
- Curl_set_in_callback(data, false);
|
|
|
- if(result) {
|
|
|
- failf(data, "error signaled by ssl ctx callback");
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
- result = CURLE_OK;
|
|
|
-
|
|
|
-out:
|
|
|
- *pssl_ctx = result? NULL : ssl_ctx;
|
|
|
- if(result && ssl_ctx)
|
|
|
- SSL_CTX_free(ssl_ctx);
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/** SSL callbacks ***/
|
|
|
-
|
|
|
-static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
|
|
|
- struct Curl_easy *data)
|
|
|
-{
|
|
|
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
|
|
- 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 = cf->conn->host.name;
|
|
|
-
|
|
|
- (void)data;
|
|
|
- DEBUGASSERT(!ctx->ssl);
|
|
|
- ctx->ssl = wolfSSL_new(ctx->sslctx);
|
|
|
-
|
|
|
- wolfSSL_set_app_data(ctx->ssl, &ctx->conn_ref);
|
|
|
- wolfSSL_set_connect_state(ctx->ssl);
|
|
|
- wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
|
|
|
-
|
|
|
- alpn = (const uint8_t *)H3_ALPN_H3 H3_ALPN_H3_29;
|
|
|
- alpnlen = sizeof(H3_ALPN_H3) - 1 + sizeof(H3_ALPN_H3_29) - 1;
|
|
|
- if(alpn)
|
|
|
- wolfSSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen);
|
|
|
-
|
|
|
- /* set SNI */
|
|
|
- wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME,
|
|
|
- hostname, (unsigned short)strlen(hostname));
|
|
|
-
|
|
|
- return CURLE_OK;
|
|
|
-}
|
|
|
-#endif /* defined(USE_WOLFSSL) */
|
|
|
-
|
|
|
static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
|
|
|
{
|
|
|
(void)user_data;
|
|
@@ -1950,49 +1535,12 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
|
|
|
struct Curl_easy *data)
|
|
|
{
|
|
|
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
|
|
- struct ssl_primary_config *conn_config;
|
|
|
- CURLcode result = CURLE_OK;
|
|
|
-
|
|
|
- conn_config = Curl_ssl_cf_get_primary_config(cf);
|
|
|
- if(!conn_config)
|
|
|
- return CURLE_FAILED_INIT;
|
|
|
|
|
|
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
|
|
|
cf->conn->httpversion = 30;
|
|
|
cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
|
|
|
|
|
|
- if(conn_config->verifyhost) {
|
|
|
-#ifdef USE_OPENSSL
|
|
|
- X509 *server_cert;
|
|
|
- server_cert = SSL_get1_peer_certificate(ctx->ssl);
|
|
|
- if(!server_cert) {
|
|
|
- return CURLE_PEER_FAILED_VERIFICATION;
|
|
|
- }
|
|
|
- result = Curl_ossl_verifyhost(data, cf->conn, &ctx->peer, server_cert);
|
|
|
- X509_free(server_cert);
|
|
|
- if(result)
|
|
|
- return result;
|
|
|
-#elif defined(USE_GNUTLS)
|
|
|
- result = Curl_gtls_verifyserver(data, ctx->gtls->session,
|
|
|
- conn_config, &data->set.ssl, &ctx->peer,
|
|
|
- data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
|
|
|
- if(result)
|
|
|
- return result;
|
|
|
-#elif defined(USE_WOLFSSL)
|
|
|
- if(!ctx->peer.sni ||
|
|
|
- wolfSSL_check_domain_name(ctx->ssl, ctx->peer.sni) == SSL_FAILURE)
|
|
|
- return CURLE_PEER_FAILED_VERIFICATION;
|
|
|
-#endif
|
|
|
- infof(data, "Verified certificate just fine");
|
|
|
- }
|
|
|
- else
|
|
|
- infof(data, "Skipped certificate verification");
|
|
|
-#ifdef USE_OPENSSL
|
|
|
- if(data->set.ssl.certinfo)
|
|
|
- /* asked to gather certificate info */
|
|
|
- (void)Curl_ossl_certchain(data, ctx->ssl);
|
|
|
-#endif
|
|
|
- return result;
|
|
|
+ return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
|
|
|
}
|
|
|
|
|
|
static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
|
|
@@ -2056,14 +1604,9 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
|
|
|
pktx_update_time(pktx, cf);
|
|
|
}
|
|
|
|
|
|
-#ifdef USE_OPENSSL
|
|
|
- if(!ctx->x509_store_setup) {
|
|
|
- result = Curl_ssl_setup_x509_store(cf, data, ctx->sslctx);
|
|
|
- if(result)
|
|
|
- return result;
|
|
|
- ctx->x509_store_setup = TRUE;
|
|
|
- }
|
|
|
-#endif
|
|
|
+ result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
|
|
|
+ if(result)
|
|
|
+ return result;
|
|
|
|
|
|
for(i = 0; i < pkts_max; i += pkts_chunk) {
|
|
|
pktx->pkt_count = 0;
|
|
@@ -2388,25 +1931,7 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
|
|
|
if(ctx->qlogfd != -1) {
|
|
|
close(ctx->qlogfd);
|
|
|
}
|
|
|
-#ifdef USE_OPENSSL
|
|
|
- if(ctx->ssl)
|
|
|
- SSL_free(ctx->ssl);
|
|
|
- if(ctx->sslctx)
|
|
|
- SSL_CTX_free(ctx->sslctx);
|
|
|
-#elif defined(USE_GNUTLS)
|
|
|
- if(ctx->gtls) {
|
|
|
- if(ctx->gtls->cred)
|
|
|
- gnutls_certificate_free_credentials(ctx->gtls->cred);
|
|
|
- if(ctx->gtls->session)
|
|
|
- gnutls_deinit(ctx->gtls->session);
|
|
|
- free(ctx->gtls);
|
|
|
- }
|
|
|
-#elif defined(USE_WOLFSSL)
|
|
|
- if(ctx->ssl)
|
|
|
- wolfSSL_free(ctx->ssl);
|
|
|
- if(ctx->sslctx)
|
|
|
- wolfSSL_CTX_free(ctx->sslctx);
|
|
|
-#endif
|
|
|
+ Curl_vquic_tls_cleanup(&ctx->tls);
|
|
|
vquic_ctx_free(&ctx->q);
|
|
|
if(ctx->h3conn)
|
|
|
nghttp3_conn_del(ctx->h3conn);
|
|
@@ -2465,6 +1990,37 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|
|
(void)save;
|
|
|
}
|
|
|
|
|
|
+static CURLcode tls_ctx_setup(struct quic_tls_ctx *ctx,
|
|
|
+ struct Curl_cfilter *cf,
|
|
|
+ struct Curl_easy *data)
|
|
|
+{
|
|
|
+ (void)cf;
|
|
|
+#ifdef USE_OPENSSL
|
|
|
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
|
|
|
+ if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ssl_ctx) != 0) {
|
|
|
+ failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
|
|
|
+ return CURLE_FAILED_INIT;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ if(ngtcp2_crypto_quictls_configure_client_context(ctx->ssl_ctx) != 0) {
|
|
|
+ failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
|
|
|
+ return CURLE_FAILED_INIT;
|
|
|
+ }
|
|
|
+#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
|
|
|
+#elif defined(USE_GNUTLS)
|
|
|
+ if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) {
|
|
|
+ failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
|
|
|
+ return CURLE_FAILED_INIT;
|
|
|
+ }
|
|
|
+#elif defined(USE_WOLFSSL)
|
|
|
+ if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->ssl_ctx) != 0) {
|
|
|
+ failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
|
|
|
+ return CURLE_FAILED_INIT;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return CURLE_OK;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Might be called twice for happy eyeballs.
|
|
|
*/
|
|
@@ -2489,21 +2045,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
|
|
if(result)
|
|
|
return result;
|
|
|
|
|
|
-#ifdef USE_OPENSSL
|
|
|
- result = quic_ssl_ctx(&ctx->sslctx, cf, data);
|
|
|
- if(result)
|
|
|
- return result;
|
|
|
-
|
|
|
- result = quic_set_client_cert(cf, data);
|
|
|
- if(result)
|
|
|
- return result;
|
|
|
-#elif defined(USE_WOLFSSL)
|
|
|
- result = quic_ssl_ctx(&ctx->sslctx, cf, data);
|
|
|
- if(result)
|
|
|
- return result;
|
|
|
-#endif
|
|
|
-
|
|
|
- result = quic_init_ssl(cf, data);
|
|
|
+#define H3_ALPN "\x2h3\x5h3-29"
|
|
|
+ result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
|
|
|
+ H3_ALPN, sizeof(H3_ALPN) - 1,
|
|
|
+ tls_ctx_setup, &ctx->conn_ref);
|
|
|
if(result)
|
|
|
return result;
|
|
|
|
|
@@ -2550,9 +2095,9 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
|
|
return CURLE_QUIC_CONNECT_ERROR;
|
|
|
|
|
|
#ifdef USE_GNUTLS
|
|
|
- ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->gtls->session);
|
|
|
+ ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls->session);
|
|
|
#else
|
|
|
- ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->ssl);
|
|
|
+ ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl);
|
|
|
#endif
|
|
|
|
|
|
ngtcp2_ccerr_default(&ctx->last_error);
|
|
@@ -2683,8 +2228,8 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
|
|
|
return CURLE_OK;
|
|
|
}
|
|
|
case CF_QUERY_CONNECT_REPLY_MS:
|
|
|
- if(ctx->got_first_byte) {
|
|
|
- timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
|
|
|
+ if(ctx->q.got_first_byte) {
|
|
|
+ timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
|
|
|
*pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
|
|
|
}
|
|
|
else
|
|
@@ -2692,8 +2237,8 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
|
|
|
return CURLE_OK;
|
|
|
case CF_QUERY_TIMER_CONNECT: {
|
|
|
struct curltime *when = pres2;
|
|
|
- if(ctx->got_first_byte)
|
|
|
- *when = ctx->first_byte_at;
|
|
|
+ if(ctx->q.got_first_byte)
|
|
|
+ *when = ctx->q.first_byte_at;
|
|
|
return CURLE_OK;
|
|
|
}
|
|
|
case CF_QUERY_TIMER_APPCONNECT: {
|