diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2022-09-21 14:47:18 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2022-09-21 14:47:18 +0300 |
commit | f904cb56d9b1584ffcc28e53dec706fe1dc15d6f (patch) | |
tree | fe2764cc64c10b674559b367741a172323b52bcd /contrib/libs/curl/lib/vquic | |
parent | 37a16126ac62d0af47b33d50c786b9adc009f6f3 (diff) | |
download | ydb-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.c | 34 | ||||
-rw-r--r-- | contrib/libs/curl/lib/vquic/ngtcp2.c | 223 | ||||
-rw-r--r-- | contrib/libs/curl/lib/vquic/quiche.c | 13 |
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) |