aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/curl/lib/vtls/rustls.c
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-04-09 00:41:32 +0300
committershadchin <shadchin@yandex-team.ru>2022-04-09 00:41:32 +0300
commit3bbb3d7e7e261716b0a83c1a35022e5d36f7875f (patch)
tree96955fafe753aad4486b22280aafe9050c508954 /contrib/libs/curl/lib/vtls/rustls.c
parentbeae089571d44f32f0edd323496377d3abe1bce6 (diff)
downloadydb-3bbb3d7e7e261716b0a83c1a35022e5d36f7875f.tar.gz
CONTRIB-2513 Update contrib/libs/curl to 7.77.0
ref:88dc545867909534adecc7502c44301cabf1a899
Diffstat (limited to 'contrib/libs/curl/lib/vtls/rustls.c')
-rw-r--r--contrib/libs/curl/lib/vtls/rustls.c271
1 files changed, 147 insertions, 124 deletions
diff --git a/contrib/libs/curl/lib/vtls/rustls.c b/contrib/libs/curl/lib/vtls/rustls.c
index 944a80e706..e9b75a5dc5 100644
--- a/contrib/libs/curl/lib/vtls/rustls.c
+++ b/contrib/libs/curl/lib/vtls/rustls.c
@@ -37,16 +37,11 @@
#include "multiif.h"
-/* Per https://www.bearssl.org/api1.html, max TLS record size plus max
- per-record overhead. */
-#define TLSBUF_SIZE (16384 + 325)
-
struct ssl_backend_data
{
const struct rustls_client_config *config;
- struct rustls_client_session *session;
+ struct rustls_connection *conn;
bool data_pending;
- uint8_t *tlsbuf;
};
/* For a given rustls_result error code, return the best-matching CURLcode. */
@@ -82,6 +77,28 @@ cr_connect(struct Curl_easy *data UNUSED_PARAM,
return CURLE_SSL_CONNECT_ERROR;
}
+static int
+read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
+{
+ ssize_t n = sread(*(int *)userdata, buf, len);
+ if(n < 0) {
+ return SOCKERRNO;
+ }
+ *out_n = n;
+ return 0;
+}
+
+static int
+write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
+{
+ ssize_t n = swrite(*(int *)userdata, buf, len);
+ if(n < 0) {
+ return SOCKERRNO;
+ }
+ *out_n = n;
+ return 0;
+}
+
/*
* On each run:
* - Read a chunk of bytes from the socket into rustls' TLS input buffer.
@@ -101,65 +118,44 @@ cr_recv(struct Curl_easy *data, int sockindex,
struct connectdata *conn = data->conn;
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
struct ssl_backend_data *const backend = connssl->backend;
- struct rustls_client_session *const session = backend->session;
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct rustls_connection *const rconn = backend->conn;
size_t n = 0;
- ssize_t tls_bytes_read = 0;
- size_t tls_bytes_processed = 0;
+ size_t tls_bytes_read = 0;
size_t plain_bytes_copied = 0;
rustls_result rresult = 0;
char errorbuf[255];
+ rustls_io_result io_error;
- tls_bytes_read = sread(sockfd, backend->tlsbuf, TLSBUF_SIZE);
- if(tls_bytes_read == 0) {
- failf(data, "connection closed without TLS close_notify alert");
+ io_error = rustls_connection_read_tls(rconn, read_cb,
+ &conn->sock[sockindex], &tls_bytes_read);
+ if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+ infof(data, "sread: EAGAIN or EWOULDBLOCK\n");
+ }
+ else if(io_error) {
+ failf(data, "reading from socket: %s", strerror(io_error));
*err = CURLE_READ_ERROR;
return -1;
}
- else if(tls_bytes_read < 0) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
- infof(data, "sread: EAGAIN or EWOULDBLOCK\n");
- *err = CURLE_AGAIN;
- return -1;
- }
- failf(data, "reading from socket: %s", strerror(SOCKERRNO));
+ else if(tls_bytes_read == 0) {
+ failf(data, "connection closed without TLS close_notify alert");
*err = CURLE_READ_ERROR;
return -1;
}
- /*
- * Now pull those bytes from the buffer into ClientSession.
- */
- DEBUGASSERT(tls_bytes_read > 0);
- while(tls_bytes_processed < (size_t)tls_bytes_read) {
- rresult = rustls_client_session_read_tls(session,
- backend->tlsbuf + tls_bytes_processed,
- tls_bytes_read - tls_bytes_processed,
- &n);
- if(rresult != RUSTLS_RESULT_OK) {
- failf(data, "error in rustls_client_session_read_tls");
- *err = CURLE_READ_ERROR;
- return -1;
- }
- else if(n == 0) {
- infof(data, "EOF from rustls_client_session_read_tls\n");
- break;
- }
+ infof(data, "cr_recv read %ld bytes from the network\n", tls_bytes_read);
- rresult = rustls_client_session_process_new_packets(session);
- if(rresult != RUSTLS_RESULT_OK) {
- rustls_error(rresult, errorbuf, sizeof(errorbuf), &n);
- failf(data, "%.*s", n, errorbuf);
- *err = map_error(rresult);
- return -1;
- }
-
- tls_bytes_processed += n;
- backend->data_pending = TRUE;
+ rresult = rustls_connection_process_new_packets(rconn);
+ if(rresult != RUSTLS_RESULT_OK) {
+ rustls_error(rresult, errorbuf, sizeof(errorbuf), &n);
+ failf(data, "%.*s", n, errorbuf);
+ *err = map_error(rresult);
+ return -1;
}
+ backend->data_pending = TRUE;
+
while(plain_bytes_copied < plainlen) {
- rresult = rustls_client_session_read(session,
+ rresult = rustls_connection_read(rconn,
(uint8_t *)plainbuf + plain_bytes_copied,
plainlen - plain_bytes_copied,
&n);
@@ -168,20 +164,21 @@ cr_recv(struct Curl_easy *data, int sockindex,
return 0;
}
else if(rresult != RUSTLS_RESULT_OK) {
- failf(data, "error in rustls_client_session_read");
+ failf(data, "error in rustls_connection_read");
*err = CURLE_READ_ERROR;
return -1;
}
else if(n == 0) {
- /* rustls returns 0 from client_session_read to mean "all currently
+ /* rustls returns 0 from connection_read to mean "all currently
available data has been read." If we bring in more ciphertext with
read_tls, more plaintext will become available. So don't tell curl
this is an EOF. Instead, say "come back later." */
- infof(data, "EOF from rustls_client_session_read\n");
+ infof(data, "cr_recv got 0 bytes of plaintext\n");
backend->data_pending = FALSE;
break;
}
else {
+ infof(data, "cr_recv copied out %ld bytes of plaintext\n", n);
plain_bytes_copied += n;
}
}
@@ -214,68 +211,50 @@ cr_send(struct Curl_easy *data, int sockindex,
struct connectdata *conn = data->conn;
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
struct ssl_backend_data *const backend = connssl->backend;
- struct rustls_client_session *const session = backend->session;
- curl_socket_t sockfd = conn->sock[sockindex];
- ssize_t n = 0;
+ struct rustls_connection *const rconn = backend->conn;
size_t plainwritten = 0;
- size_t tlslen = 0;
size_t tlswritten = 0;
+ size_t tlswritten_total = 0;
rustls_result rresult;
+ rustls_io_result io_error;
+
+ infof(data, "cr_send %ld bytes of plaintext\n", plainlen);
if(plainlen > 0) {
- rresult = rustls_client_session_write(session,
- plainbuf, plainlen, &plainwritten);
+ rresult = rustls_connection_write(rconn, plainbuf, plainlen,
+ &plainwritten);
if(rresult != RUSTLS_RESULT_OK) {
- failf(data, "error in rustls_client_session_write");
+ failf(data, "error in rustls_connection_write");
*err = CURLE_WRITE_ERROR;
return -1;
}
else if(plainwritten == 0) {
- failf(data, "EOF in rustls_client_session_write");
+ failf(data, "EOF in rustls_connection_write");
*err = CURLE_WRITE_ERROR;
return -1;
}
}
- while(rustls_client_session_wants_write(session)) {
- rresult = rustls_client_session_write_tls(
- session, backend->tlsbuf, TLSBUF_SIZE, &tlslen);
- if(rresult != RUSTLS_RESULT_OK) {
- failf(data, "error in rustls_client_session_write_tls");
- *err = CURLE_WRITE_ERROR;
+ while(rustls_connection_wants_write(rconn)) {
+ io_error = rustls_connection_write_tls(rconn, write_cb,
+ &conn->sock[sockindex], &tlswritten);
+ if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+ infof(data, "swrite: EAGAIN after %ld bytes\n", tlswritten_total);
+ *err = CURLE_AGAIN;
return -1;
}
- else if(tlslen == 0) {
- failf(data, "EOF in rustls_client_session_write_tls");
+ else if(io_error) {
+ failf(data, "writing to socket: %s", strerror(io_error));
*err = CURLE_WRITE_ERROR;
return -1;
}
-
- tlswritten = 0;
-
- while(tlswritten < tlslen) {
- n = swrite(sockfd, backend->tlsbuf + tlswritten, tlslen - tlswritten);
- if(n < 0) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
- /* Since recv is called from poll, there should be room to
- write at least some bytes before hitting EAGAIN. */
- infof(data, "swrite: EAGAIN after %ld bytes\n", tlswritten);
- DEBUGASSERT(tlswritten > 0);
- break;
- }
- failf(data, "error in swrite");
- *err = CURLE_WRITE_ERROR;
- return -1;
- }
- if(n == 0) {
- failf(data, "EOF in swrite");
- *err = CURLE_WRITE_ERROR;
- return -1;
- }
- tlswritten += n;
+ if(tlswritten == 0) {
+ failf(data, "EOF in swrite");
+ *err = CURLE_WRITE_ERROR;
+ return -1;
}
-
- DEBUGASSERT(tlswritten <= tlslen);
+ infof(data, "cr_send wrote %ld bytes to network\n", tlswritten);
+ tlswritten_total += tlswritten;
}
return plainwritten;
@@ -310,7 +289,7 @@ static CURLcode
cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
struct ssl_backend_data *const backend)
{
- struct rustls_client_session *session = backend->session;
+ struct rustls_connection *rconn = backend->conn;
struct rustls_client_config_builder *config_builder = NULL;
const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
@@ -318,19 +297,26 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
char errorbuf[256];
size_t errorlen;
int result;
-
- backend->tlsbuf = calloc(TLSBUF_SIZE, 1);
- if(backend->tlsbuf == NULL) {
- return CURLE_OUT_OF_MEMORY;
- }
+ rustls_slice_bytes alpn[2] = {
+ { (const uint8_t *)ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH },
+ { (const uint8_t *)ALPN_H2, ALPN_H2_LENGTH },
+ };
config_builder = rustls_client_config_builder_new();
+#ifdef USE_HTTP2
+ infof(data, "offering ALPN for HTTP/1.1 and HTTP/2\n");
+ rustls_client_config_builder_set_protocols(config_builder, alpn, 2);
+#else
+ infof(data, "offering ALPN for HTTP/1.1 only\n");
+ rustls_client_config_builder_set_protocols(config_builder, alpn, 1);
+#endif
if(!verifypeer) {
rustls_client_config_builder_dangerous_set_certificate_verifier(
- config_builder, cr_verify_none, NULL);
+ config_builder, cr_verify_none);
/* rustls doesn't support IP addresses (as of 0.19.0), and will reject
- * sessions created with an IP address, even when certificate verification
- * is turned off. Set a placeholder hostname and disable SNI. */
+ * connections created with an IP address, even when certificate
+ * verification is turned off. Set a placeholder hostname and disable
+ * SNI. */
if(cr_hostname_is_ip(hostname)) {
rustls_client_config_builder_set_enable_sni(config_builder, false);
hostname = "example.invalid";
@@ -357,18 +343,51 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
}
backend->config = rustls_client_config_builder_build(config_builder);
- DEBUGASSERT(session == NULL);
- result = rustls_client_session_new(
- backend->config, hostname, &session);
+ DEBUGASSERT(rconn == NULL);
+ result = rustls_client_connection_new(backend->config, hostname, &rconn);
if(result != RUSTLS_RESULT_OK) {
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
- failf(data, "failed to create client session: %.*s", errorlen, errorbuf);
+ failf(data, "rustls_client_connection_new: %.*s", errorlen, errorbuf);
return CURLE_COULDNT_CONNECT;
}
- backend->session = session;
+ rustls_connection_set_userdata(rconn, backend);
+ backend->conn = rconn;
return CURLE_OK;
}
+static void
+cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
+ const struct rustls_connection *rconn)
+{
+ const uint8_t *protocol = NULL;
+ size_t len = 0;
+
+ rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
+ if(NULL == protocol) {
+ infof(data, "ALPN, server did not agree to a protocol\n");
+ return;
+ }
+
+#ifdef USE_HTTP2
+ if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) {
+ infof(data, "ALPN, negotiated h2\n");
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ }
+ else
+#endif
+ if(len == ALPN_HTTP_1_1_LENGTH &&
+ 0 == memcmp(ALPN_HTTP_1_1, protocol, len)) {
+ infof(data, "ALPN, negotiated http/1.1\n");
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
+ else {
+ infof(data, "ALPN, negotiated an unrecognized protocol\n");
+ }
+
+ Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
+}
+
static CURLcode
cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
int sockindex, bool *done)
@@ -376,7 +395,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_backend_data *const backend = connssl->backend;
- struct rustls_client_session *session = NULL;
+ struct rustls_connection *rconn = NULL;
CURLcode tmperr = CURLE_OK;
int result;
int what;
@@ -393,7 +412,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
connssl->state = ssl_connection_negotiating;
}
- session = backend->session;
+ rconn = backend->conn;
/* Read/write data until the handshake is done or the socket would block. */
for(;;) {
@@ -404,18 +423,21 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
* then becomes true when we first write data, then becomes false again
* once the handshake is done.
*/
- if(!rustls_client_session_is_handshaking(session)) {
+ if(!rustls_connection_is_handshaking(rconn)) {
infof(data, "Done handshaking\n");
/* Done with the handshake. Set up callbacks to send/receive data. */
connssl->state = ssl_connection_complete;
+
+ cr_set_negotiated_alpn(data, conn, rconn);
+
conn->recv[sockindex] = cr_recv;
conn->send[sockindex] = cr_send;
*done = TRUE;
return CURLE_OK;
}
- wants_read = rustls_client_session_wants_read(session);
- wants_write = rustls_client_session_wants_write(session);
+ wants_read = rustls_connection_wants_read(rconn);
+ wants_write = rustls_connection_wants_write(rconn);
DEBUGASSERT(wants_read || wants_write);
writefd = wants_write?sockfd:CURL_SOCKET_BAD;
readfd = wants_read?sockfd:CURL_SOCKET_BAD;
@@ -439,7 +461,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
/* socket is readable or writable */
if(wants_write) {
- infof(data, "ClientSession wants us to write_tls.\n");
+ infof(data, "rustls_connection wants us to write_tls.\n");
cr_send(data, sockindex, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
infof(data, "writing would block\n");
@@ -451,7 +473,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
}
if(wants_read) {
- infof(data, "ClientSession wants us to read_tls.\n");
+ infof(data, "rustls_connection wants us to read_tls.\n");
cr_recv(data, sockindex, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
@@ -482,13 +504,13 @@ cr_getsock(struct connectdata *conn, curl_socket_t *socks)
struct ssl_connect_data *const connssl = &conn->ssl[FIRSTSOCKET];
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
struct ssl_backend_data *const backend = connssl->backend;
- struct rustls_client_session *session = backend->session;
+ struct rustls_connection *rconn = backend->conn;
- if(rustls_client_session_wants_write(session)) {
+ if(rustls_connection_wants_write(rconn)) {
socks[0] = sockfd;
return GETSOCK_WRITESOCK(0);
}
- if(rustls_client_session_wants_read(session)) {
+ if(rustls_connection_wants_read(rconn)) {
socks[0] = sockfd;
return GETSOCK_READSOCK(0);
}
@@ -501,7 +523,7 @@ cr_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
{
struct ssl_backend_data *backend = connssl->backend;
- return &backend->session;
+ return &backend->conn;
}
static void
@@ -513,21 +535,20 @@ cr_close(struct Curl_easy *data, struct connectdata *conn,
CURLcode tmperr = CURLE_OK;
ssize_t n = 0;
- if(backend->session) {
- rustls_client_session_send_close_notify(backend->session);
+ if(backend->conn) {
+ rustls_connection_send_close_notify(backend->conn);
n = cr_send(data, sockindex, NULL, 0, &tmperr);
if(n < 0) {
failf(data, "error sending close notify: %d", tmperr);
}
- rustls_client_session_free(backend->session);
- backend->session = NULL;
+ rustls_connection_free(backend->conn);
+ backend->conn = NULL;
}
if(backend->config) {
rustls_client_config_free(backend->config);
backend->config = NULL;
}
- free(backend->tlsbuf);
}
const struct Curl_ssl Curl_ssl_rustls = {
@@ -554,7 +575,9 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- NULL /* sha256sum */
+ NULL, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif /* USE_RUSTLS */