From: Tatsuhiro Tsujikawa Date: Sun, 5 Jun 2022 01:10:51 +0000 (+0900) Subject: ngtcp2: use handshake helper funcs to simplify TLS handshake integration X-Git-Tag: curl-7_84_0~61 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d2c6d8be18adfe4c49ca8948d04e228ba1a6e9fb;p=thirdparty%2Fcurl.git ngtcp2: use handshake helper funcs to simplify TLS handshake integration Closes #8968 --- diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c index e8c013e5d8..5460048858 100644 --- a/lib/vquic/ngtcp2.c +++ b/lib/vquic/ngtcp2.c @@ -24,7 +24,6 @@ #ifdef USE_NGTCP2 #include -#include #include #ifdef USE_OPENSSL #include @@ -115,6 +114,12 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, size_t datalen, void *user_data, void *stream_user_data); +static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) +{ + struct quicsocket *qs = conn_ref->user_data; + return qs->qconn; +} + static ngtcp2_tstamp timestamp(void) { struct curltime ct = Curl_now(); @@ -199,145 +204,24 @@ static int keylog_callback(gnutls_session_t session, const char *label, 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) -{ - int rv; - - rv = ngtcp2_conn_submit_crypto_data(qs->qconn, level, data, len); - if(rv) { - H3BUGF(fprintf(stderr, "write_client_handshake failed\n")); - return 0; - } - - return 1; -} - #ifdef USE_OPENSSL -#ifdef OPENSSL_IS_BORINGSSL -static int quic_set_read_secret(SSL *ssl, - enum ssl_encryption_level_t ssl_level, - const SSL_CIPHER *cipher UNUSED_PARAM, - const uint8_t *secret, - size_t secretlen) +static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) { - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - ngtcp2_crypto_level level = - ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level); - - if(ngtcp2_crypto_derive_and_install_rx_key( - qs->qconn, NULL, NULL, NULL, level, secret, secretlen) != 0) - return 0; + struct connectdata *conn = data->conn; + SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); - if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) { - if(init_ngh3_conn(qs) != CURLE_OK) - return 0; +#ifdef OPENSSL_IS_BORINGSSL + if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed"); + return NULL; } - - return 1; -} - -static int quic_set_write_secret(SSL *ssl, - enum ssl_encryption_level_t ssl_level, - const SSL_CIPHER *cipher UNUSED_PARAM, - const uint8_t *secret, - size_t secretlen) -{ - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - ngtcp2_crypto_level level = - ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level); - - if(ngtcp2_crypto_derive_and_install_tx_key( - qs->qconn, NULL, NULL, NULL, level, secret, secretlen) != 0) - return 0; - - return 1; -} - -static int quic_add_handshake_data(SSL *ssl, - enum ssl_encryption_level_t ssl_level, - const uint8_t *data, - size_t len) -{ - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - ngtcp2_crypto_level level = - ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level); - - return write_client_handshake(qs, level, data, len); -} #else -static int quic_set_encryption_secrets(SSL *ssl, - OSSL_ENCRYPTION_LEVEL ossl_level, - const uint8_t *rx_secret, - const uint8_t *tx_secret, - size_t secretlen) -{ - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - ngtcp2_crypto_level level = - ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); - - if(ngtcp2_crypto_derive_and_install_rx_key( - qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0) - return 0; - - if(ngtcp2_crypto_derive_and_install_tx_key( - qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0) - return 0; - - if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) { - if(init_ngh3_conn(qs) != CURLE_OK) - return 0; + if(ngtcp2_crypto_openssl_configure_client_context(ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_openssl_configure_client_context failed"); + return NULL; } - - return 1; -} - -static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, - const uint8_t *data, size_t len) -{ - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - ngtcp2_crypto_level level = - ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); - - return write_client_handshake(qs, level, data, len); -} #endif -static int quic_flush_flight(SSL *ssl) -{ - (void)ssl; - return 1; -} - -static int quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level, - uint8_t alert) -{ - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - (void)level; - - qs->tls_alert = alert; - return 1; -} - -static SSL_QUIC_METHOD quic_method = { -#ifdef OPENSSL_IS_BORINGSSL - quic_set_read_secret, - quic_set_write_secret, -#else - quic_set_encryption_secrets, -#endif - quic_add_handshake_data, - quic_flush_flight, quic_send_alert}; - -static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) -{ - struct connectdata *conn = data->conn; - SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); - - SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_default_verify_paths(ssl_ctx); #ifdef OPENSSL_IS_BORINGSSL @@ -359,8 +243,6 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) } #endif - SSL_CTX_set_quic_method(ssl_ctx, &quic_method); - /* Open the file if a TLS or QUIC backend has not done this before. */ Curl_tls_keylog_open(); if(Curl_tls_keylog_enabled()) { @@ -428,7 +310,7 @@ static int quic_init_ssl(struct quicsocket *qs) DEBUGASSERT(!qs->ssl); qs->ssl = SSL_new(qs->sslctx); - SSL_set_app_data(qs->ssl, qs); + SSL_set_app_data(qs->ssl, &qs->conn_ref); SSL_set_connect_state(qs->ssl); SSL_set_quic_use_legacy_codepoint(qs->ssl, 0); @@ -442,114 +324,6 @@ static int quic_init_ssl(struct quicsocket *qs) 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 = - ngtcp2_crypto_gnutls_from_gnutls_record_encryption_level(gtls_level); - - if(level != NGTCP2_CRYPTO_LEVEL_EARLY && - ngtcp2_crypto_derive_and_install_rx_key( - qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0) - return 0; - - if(ngtcp2_crypto_derive_and_install_tx_key( - qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0) - return 0; - - if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) { - 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 = - ngtcp2_crypto_gnutls_from_gnutls_record_encryption_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 0; -} - -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; - int rv; - - rv = ngtcp2_decode_transport_params( - ¶ms, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, - data, data_size); - if(rv) { - ngtcp2_conn_set_tls_error(qs->qconn, rv); - return -1; - } - - rv = ngtcp2_conn_set_remote_transport_params(qs->qconn, ¶ms); - if(rv) { - ngtcp2_conn_set_tls_error(qs->qconn, rv); - 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[256]; - ngtcp2_transport_params params; - ngtcp2_ssize 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) { - H3BUGF(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[2]; @@ -560,26 +334,17 @@ static int quic_init_ssl(struct quicsocket *qs) DEBUGASSERT(!qs->ssl); gnutls_init(&qs->ssl, GNUTLS_CLIENT); - gnutls_session_set_ptr(qs->ssl, qs); + gnutls_session_set_ptr(qs->ssl, &qs->conn_ref); - rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL); - if(rc < 0) { - H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n", - gnutls_strerror(rc))); + if(ngtcp2_crypto_gnutls_configure_client_session(qs->ssl) != 0) { + H3BUGF(fprintf(stderr, + "ngtcp2_crypto_gnutls_configure_client_session failed\n")); 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", - NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1, 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); + rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL); if(rc < 0) { - H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n", + H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n", gnutls_strerror(rc))); return 1; } @@ -822,6 +587,23 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, return 0; } +static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_crypto_level level, + void *user_data) +{ + struct quicsocket *qs = (struct quicsocket *)user_data; + (void)tconn; + + if(level != NGTCP2_CRYPTO_LEVEL_APPLICATION) { + return 0; + } + + if(init_ngh3_conn(qs) != CURLE_OK) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_client_initial_cb, NULL, /* recv_client_initial */ @@ -860,6 +642,8 @@ static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_get_path_challenge_data_cb, cb_stream_stop_sending, NULL, /* version_negotiation */ + cb_recv_rx_key, + NULL, /* recv_tx_key */ }; /* @@ -962,6 +746,9 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } + qs->conn_ref.get_conn = get_conn; + qs->conn_ref.user_data = qs; + return CURLE_OK; } @@ -1811,7 +1598,7 @@ static CURLcode ng_process_ingress(struct Curl_easy *data, if(!qs->last_error.error_code) { if(rv == NGTCP2_ERR_CRYPTO) { ngtcp2_connection_close_error_set_transport_error_tls_alert( - &qs->last_error, qs->tls_alert, NULL, 0); + &qs->last_error, ngtcp2_conn_get_tls_alert(qs->qconn), NULL, 0); } else { ngtcp2_connection_close_error_set_transport_error_liberr( diff --git a/lib/vquic/ngtcp2.h b/lib/vquic/ngtcp2.h index 60fb43e519..469927b900 100644 --- a/lib/vquic/ngtcp2.h +++ b/lib/vquic/ngtcp2.h @@ -30,7 +30,7 @@ #include #endif -#include +#include #include #ifdef USE_OPENSSL #include @@ -53,6 +53,7 @@ struct quicsocket { ngtcp2_settings settings; ngtcp2_transport_params transport_params; ngtcp2_connection_close_error last_error; + ngtcp2_crypto_conn_ref conn_ref; #ifdef USE_OPENSSL SSL_CTX *sslctx; SSL *ssl; @@ -60,8 +61,6 @@ struct quicsocket { gnutls_certificate_credentials_t cred; gnutls_session_t ssl; #endif - /* the last TLS alert description generated by the local endpoint */ - uint8_t tls_alert; struct sockaddr_storage local_addr; socklen_t local_addrlen; bool no_gso;