aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/curl/lib/vquic
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.com>2022-09-21 14:47:18 +0300
committerrobot-contrib <robot-contrib@yandex-team.com>2022-09-21 14:47:18 +0300
commitf904cb56d9b1584ffcc28e53dec706fe1dc15d6f (patch)
treefe2764cc64c10b674559b367741a172323b52bcd /contrib/libs/curl/lib/vquic
parent37a16126ac62d0af47b33d50c786b9adc009f6f3 (diff)
downloadydb-f904cb56d9b1584ffcc28e53dec706fe1dc15d6f.tar.gz
Update contrib/libs/curl to 7.85.0
Diffstat (limited to 'contrib/libs/curl/lib/vquic')
-rw-r--r--contrib/libs/curl/lib/vquic/msh3.c34
-rw-r--r--contrib/libs/curl/lib/vquic/ngtcp2.c223
-rw-r--r--contrib/libs/curl/lib/vquic/quiche.c13
3 files changed, 229 insertions, 41 deletions
diff --git a/contrib/libs/curl/lib/vquic/msh3.c b/contrib/libs/curl/lib/vquic/msh3.c
index c546e0b624..8f66bcf493 100644
--- a/contrib/libs/curl/lib/vquic/msh3.c
+++ b/contrib/libs/curl/lib/vquic/msh3.c
@@ -27,7 +27,6 @@
#ifdef USE_MSH3
#include "urldata.h"
-#include "curl_printf.h"
#include "timeval.h"
#include "multiif.h"
#include "sendf.h"
@@ -35,6 +34,11 @@
#include "h2h3.h"
#error #include "msh3.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
/* #define DEBUG_HTTP3 1 */
#ifdef DEBUG_HTTP3
#define H3BUGF(x) x
@@ -222,13 +226,8 @@ static unsigned int msh3_conncheck(struct Curl_easy *data,
return CONNRESULT_NONE;
}
-static void msh3_cleanup(struct quicsocket *qs, struct HTTP *stream)
+static void disconnect(struct quicsocket *qs)
{
- if(stream && stream->recv_buf) {
- free(stream->recv_buf);
- stream->recv_buf = ZERO_NULL;
- msh3_lock_uninitialize(&stream->recv_lock);
- }
if(qs->conn) {
MsH3ConnectionClose(qs->conn);
qs->conn = ZERO_NULL;
@@ -242,18 +241,20 @@ static void msh3_cleanup(struct quicsocket *qs, struct HTTP *stream)
static CURLcode msh3_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead_connection)
{
+ (void)data;
(void)dead_connection;
H3BUGF(infof(data, "disconnecting (msh3)"));
- msh3_cleanup(conn->quic, data->req.p.http);
+ disconnect(conn->quic);
return CURLE_OK;
}
void Curl_quic_disconnect(struct Curl_easy *data, struct connectdata *conn,
int tempindex)
{
+ (void)data;
if(conn->transport == TRNSPRT_QUIC) {
- H3BUGF(infof(data, "disconnecting (curl)"));
- msh3_cleanup(&conn->hequic[tempindex], data->req.p.http);
+ H3BUGF(infof(data, "disconnecting QUIC index %u", tempindex));
+ disconnect(&conn->hequic[tempindex]);
}
}
@@ -288,7 +289,6 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
struct HTTP *stream = IfContext;
size_t total_len;
(void)Request;
- H3BUGF(printf("* msh3_header_received\n"));
if(stream->recv_header_complete) {
H3BUGF(printf("* ignoring header after data\n"));
@@ -490,9 +490,19 @@ CURLcode Curl_quic_done_sending(struct Curl_easy *data)
void Curl_quic_done(struct Curl_easy *data, bool premature)
{
- (void)data;
+ struct HTTP *stream = data->req.p.http;
(void)premature;
H3BUGF(infof(data, "Curl_quic_done"));
+ if(stream) {
+ if(stream->recv_buf) {
+ Curl_safefree(stream->recv_buf);
+ msh3_lock_uninitialize(&stream->recv_lock);
+ }
+ if(stream->req) {
+ MsH3RequestClose(stream->req);
+ stream->req = ZERO_NULL;
+ }
+ }
}
bool Curl_quic_data_pending(const struct Curl_easy *data)
diff --git a/contrib/libs/curl/lib/vquic/ngtcp2.c b/contrib/libs/curl/lib/vquic/ngtcp2.c
index c236d93b0b..11787cee5f 100644
--- a/contrib/libs/curl/lib/vquic/ngtcp2.c
+++ b/contrib/libs/curl/lib/vquic/ngtcp2.c
@@ -38,6 +38,9 @@
#elif defined(USE_GNUTLS)
#error #include <ngtcp2/ngtcp2_crypto_gnutls.h>
#include "vtls/gtls.h"
+#elif defined(USE_WOLFSSL)
+#error #include <ngtcp2/ngtcp2_crypto_wolfssl.h>
+#include "vtls/wolfssl.h"
#endif
#include "urldata.h"
#include "sendf.h"
@@ -101,6 +104,11 @@ struct h3out {
"+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
/* ngtcp2 default congestion controller does not perform pacing. Limit
@@ -113,7 +121,7 @@ static CURLcode ng_process_ingress(struct Curl_easy *data,
static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd,
struct quicsocket *qs);
static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
- size_t datalen, void *user_data,
+ uint64_t datalen, void *user_data,
void *stream_user_data);
static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
@@ -202,6 +210,14 @@ static int keylog_callback(gnutls_session_t session, const char *label,
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 quicsocket *qs);
@@ -395,7 +411,105 @@ static int quic_init_ssl(struct quicsocket *qs)
gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
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());
+
+ 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, (char *)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
+ }
+
+ 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, (unsigned short)strlen(hostname));
+
+ return 0;
+}
+#endif /* defined(USE_WOLFSSL) */
static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
{
@@ -691,6 +805,10 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
result = quic_set_client_cert(data, qs);
if(result)
return result;
+#elif defined(USE_WOLFSSL)
+ qs->sslctx = quic_ssl_ctx(data);
+ if(!qs->sslctx)
+ return CURLE_QUIC_CONNECT_ERROR;
#endif
if(quic_init_ssl(qs))
@@ -818,6 +936,8 @@ static void qs_disconnect(struct quicsocket *qs)
SSL_free(qs->ssl);
#elif defined(USE_GNUTLS)
gnutls_deinit(qs->ssl);
+#elif defined(USE_WOLFSSL)
+ wolfSSL_free(qs->ssl);
#endif
qs->ssl = NULL;
#ifdef USE_GNUTLS
@@ -831,6 +951,8 @@ static void qs_disconnect(struct quicsocket *qs)
ngtcp2_conn_del(qs->qconn);
#ifdef USE_OPENSSL
SSL_CTX_free(qs->sslctx);
+#elif defined(USE_WOLFSSL)
+ wolfSSL_CTX_free(qs->sslctx);
#endif
}
@@ -899,6 +1021,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
H3BUGF(infof(data, "cb_h3_stream_close CALLED"));
stream->closed = TRUE;
+ stream->error3 = app_error_code;
Curl_expire(data, 0, EXPIRE_QUIC);
/* make sure that ngh3_stream_recv is called again to complete the transfer
even if there are no more packets to be received from the server. */
@@ -1010,6 +1133,10 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
return -1;
}
}
+
+ if(stream->status_code / 100 != 1) {
+ stream->bodystarted = TRUE;
+ }
return 0;
}
@@ -1032,9 +1159,10 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
char line[14]; /* status line is always 13 characters long */
size_t ncopy;
- int status = decode_status_code(h3val.base, h3val.len);
- DEBUGASSERT(status != -1);
- ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status);
+ stream->status_code = decode_status_code(h3val.base, h3val.len);
+ DEBUGASSERT(stream->status_code != -1);
+ ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
+ stream->status_code);
result = write_data(stream, line, ncopy);
if(result) {
return -1;
@@ -1064,16 +1192,36 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
return 0;
}
-static int cb_h3_send_stop_sending(nghttp3_conn *conn, int64_t stream_id,
- uint64_t app_error_code,
- void *user_data,
- void *stream_user_data)
+static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
+ uint64_t app_error_code, void *user_data,
+ void *stream_user_data)
{
+ struct quicsocket *qs = user_data;
+ int rv;
+ (void)conn;
+ (void)stream_user_data;
+
+ rv = ngtcp2_conn_shutdown_stream_read(qs->qconn, stream_id, app_error_code);
+ if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
+ return NGTCP2_ERR_CALLBACK_FAILURE;
+ }
+
+ return 0;
+}
+
+static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
+ uint64_t app_error_code, void *user_data,
+ void *stream_user_data) {
+ struct quicsocket *qs = user_data;
+ int rv;
(void)conn;
- (void)stream_id;
- (void)app_error_code;
- (void)user_data;
(void)stream_user_data;
+
+ rv = ngtcp2_conn_shutdown_stream_write(qs->qconn, stream_id, app_error_code);
+ if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
+ return NGTCP2_ERR_CALLBACK_FAILURE;
+ }
+
return 0;
}
@@ -1088,9 +1236,9 @@ static nghttp3_callbacks ngh3_callbacks = {
NULL, /* begin_trailers */
cb_h3_recv_header,
NULL, /* end_trailers */
- cb_h3_send_stop_sending,
+ cb_h3_stop_sending,
NULL, /* end_stream */
- NULL, /* reset_stream */
+ cb_h3_reset_stream,
NULL /* shutdown */
};
@@ -1226,6 +1374,24 @@ static ssize_t ngh3_stream_recv(struct Curl_easy *data,
}
if(stream->closed) {
+ if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
+ failf(data,
+ "HTTP/3 stream %" PRId64 " was not closed cleanly: (err %" PRIu64
+ ")",
+ stream->stream3_id, stream->error3);
+ *curlcode = CURLE_HTTP3;
+ return -1;
+ }
+
+ if(!stream->bodystarted) {
+ failf(data,
+ "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
+ " all response header fields, treated as error",
+ stream->stream3_id);
+ *curlcode = CURLE_HTTP3;
+ return -1;
+ }
+
*curlcode = CURLE_OK;
return 0;
}
@@ -1237,7 +1403,7 @@ static ssize_t ngh3_stream_recv(struct Curl_easy *data,
/* this amount of data has now been acked on this stream */
static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
- size_t datalen, void *user_data,
+ uint64_t datalen, void *user_data,
void *stream_user_data)
{
struct Curl_easy *data = stream_user_data;
@@ -1375,6 +1541,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
nva[i].namelen = hreq->header[i].namelen;
nva[i].value = (unsigned char *)hreq->header[i].value;
nva[i].valuelen = hreq->header[i].valuelen;
+ nva[i].flags = NGHTTP3_NV_FLAG_NONE;
}
}
@@ -1443,6 +1610,11 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
curl_socket_t sockfd = conn->sock[sockindex];
struct HTTP *stream = data->req.p.http;
+ if(stream->closed) {
+ *curlcode = CURLE_HTTP3;
+ return -1;
+ }
+
if(!stream->h3req) {
CURLcode result = http_request(data, mem, len);
if(result) {
@@ -1519,8 +1691,14 @@ static CURLcode ng_has_connected(struct Curl_easy *data,
if(result)
return result;
infof(data, "Verified certificate just fine");
-#else
+#elif defined(USE_GNUTLS)
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
}
else
@@ -1889,22 +2067,11 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
switch(outlen) {
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
assert(ndatalen == -1);
- rv = nghttp3_conn_block_stream(qs->h3conn, stream_id);
- if(rv) {
- failf(data, "nghttp3_conn_block_stream returned error: %s\n",
- nghttp3_strerror(rv));
- return CURLE_SEND_ERROR;
- }
+ nghttp3_conn_block_stream(qs->h3conn, stream_id);
continue;
case NGTCP2_ERR_STREAM_SHUT_WR:
assert(ndatalen == -1);
- rv = nghttp3_conn_shutdown_stream_write(qs->h3conn, stream_id);
- if(rv) {
- failf(data,
- "nghttp3_conn_shutdown_stream_write returned error: %s\n",
- nghttp3_strerror(rv));
- return CURLE_SEND_ERROR;
- }
+ nghttp3_conn_shutdown_stream_write(qs->h3conn, stream_id);
continue;
case NGTCP2_ERR_WRITE_MORE:
assert(ndatalen >= 0);
diff --git a/contrib/libs/curl/lib/vquic/quiche.c b/contrib/libs/curl/lib/vquic/quiche.c
index 0755cf566a..034794f8e7 100644
--- a/contrib/libs/curl/lib/vquic/quiche.c
+++ b/contrib/libs/curl/lib/vquic/quiche.c
@@ -258,6 +258,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
struct quicsocket *qs = &conn->hequic[sockindex];
char ipbuf[40];
int port;
+ int rv;
#ifdef DEBUG_QUICHE
/* initialize debug log callback only once */
@@ -303,8 +304,16 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
if(result)
return result;
+ qs->local_addrlen = sizeof(qs->local_addr);
+ rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr,
+ &qs->local_addrlen);
+ if(rv == -1)
+ return CURLE_QUIC_CONNECT_ERROR;
+
qs->conn = quiche_conn_new_with_tls((const uint8_t *) qs->scid,
- sizeof(qs->scid), NULL, 0, addr, addrlen,
+ sizeof(qs->scid), NULL, 0,
+ (struct sockaddr *)&qs->local_addr,
+ qs->local_addrlen, addr, addrlen,
qs->cfg, qs->ssl, false);
if(!qs->conn) {
failf(data, "can't create quiche connection");
@@ -478,6 +487,8 @@ static CURLcode process_ingress(struct Curl_easy *data, int sockfd,
recv_info.from = (struct sockaddr *) &from;
recv_info.from_len = from_len;
+ recv_info.to = (struct sockaddr *) &qs->local_addr;
+ recv_info.to_len = qs->local_addrlen;
recvd = quiche_conn_recv(qs->conn, buf, recvd, &recv_info);
if(recvd == QUICHE_ERR_DONE)