mirror of
https://github.com/moparisthebest/curl
synced 2024-12-25 09:38:54 -05:00
rustls: switch read_tls and write_tls to callbacks
And update to 0.6.0, including a rename from session to connection for many fields. Closes #7071
This commit is contained in:
parent
98770344b2
commit
a62e6435f4
@ -125,7 +125,7 @@ jobs:
|
|||||||
- libbrotli-dev
|
- libbrotli-dev
|
||||||
- libzstd-dev
|
- libzstd-dev
|
||||||
- env:
|
- env:
|
||||||
- T=debug-rustls RUSTLS_VERSION="v0.5.0" C="--with-rustls=$HOME/crust"
|
- T=debug-rustls RUSTLS_VERSION="v0.6.0" C="--with-rustls=$HOME/crust"
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
<<: *common_apt
|
<<: *common_apt
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
[Rustls is a TLS backend written in Rust.](https://docs.rs/rustls/). Curl can
|
[Rustls is a TLS backend written in Rust.](https://docs.rs/rustls/). Curl can
|
||||||
be built to use it as an alternative to OpenSSL or other TLS backends. We use
|
be built to use it as an alternative to OpenSSL or other TLS backends. We use
|
||||||
the [crustls C bindings](https://github.com/abetterinternet/crustls/). This
|
the [crustls C bindings](https://github.com/abetterinternet/crustls/). This
|
||||||
version of curl depends on version v0.5.0 of crustls.
|
version of curl depends on version v0.6.0 of crustls.
|
||||||
|
|
||||||
# Building with rustls
|
# Building with rustls
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ First, [install Rust](https://rustup.rs/).
|
|||||||
Next, check out, build, and install the appropriate version of crustls:
|
Next, check out, build, and install the appropriate version of crustls:
|
||||||
|
|
||||||
% cargo install cbindgen
|
% cargo install cbindgen
|
||||||
% git clone https://github.com/abetterinternet/crustls/ -b v0.5.0
|
% git clone https://github.com/abetterinternet/crustls/ -b v0.6.0
|
||||||
% cd crustls
|
% cd crustls
|
||||||
% make
|
% make
|
||||||
% make DESTDIR=${HOME}/crustls-built/ install
|
% make DESTDIR=${HOME}/crustls-built/ install
|
||||||
|
@ -37,16 +37,11 @@
|
|||||||
|
|
||||||
#include "multiif.h"
|
#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
|
struct ssl_backend_data
|
||||||
{
|
{
|
||||||
const struct rustls_client_config *config;
|
const struct rustls_client_config *config;
|
||||||
struct rustls_client_session *session;
|
struct rustls_connection *conn;
|
||||||
bool data_pending;
|
bool data_pending;
|
||||||
uint8_t *tlsbuf;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For a given rustls_result error code, return the best-matching CURLcode. */
|
/* 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;
|
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:
|
* On each run:
|
||||||
* - Read a chunk of bytes from the socket into rustls' TLS input buffer.
|
* - Read a chunk of bytes from the socket into rustls' TLS input buffer.
|
||||||
@ -101,55 +118,33 @@ cr_recv(struct Curl_easy *data, int sockindex,
|
|||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
|
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
|
||||||
struct ssl_backend_data *const backend = connssl->backend;
|
struct ssl_backend_data *const backend = connssl->backend;
|
||||||
struct rustls_client_session *const session = backend->session;
|
struct rustls_connection *const rconn = backend->conn;
|
||||||
curl_socket_t sockfd = conn->sock[sockindex];
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
ssize_t tls_bytes_read = 0;
|
size_t tls_bytes_read = 0;
|
||||||
size_t tls_bytes_processed = 0;
|
|
||||||
size_t plain_bytes_copied = 0;
|
size_t plain_bytes_copied = 0;
|
||||||
rustls_result rresult = 0;
|
rustls_result rresult = 0;
|
||||||
char errorbuf[255];
|
char errorbuf[255];
|
||||||
|
rustls_io_result io_error;
|
||||||
|
|
||||||
tls_bytes_read = sread(sockfd, backend->tlsbuf, TLSBUF_SIZE);
|
io_error = rustls_connection_read_tls(rconn, read_cb,
|
||||||
if(tls_bytes_read == 0) {
|
&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) {
|
||||||
failf(data, "connection closed without TLS close_notify alert");
|
failf(data, "connection closed without TLS close_notify alert");
|
||||||
*err = CURLE_READ_ERROR;
|
*err = CURLE_READ_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if(tls_bytes_read < 0) {
|
|
||||||
if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
|
|
||||||
infof(data, "sread: EAGAIN or EWOULDBLOCK\n");
|
|
||||||
/* There is no data in the socket right now, but there could still be
|
|
||||||
some data in the rustls session, so we need to read from it below. */
|
|
||||||
tls_bytes_read = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
failf(data, "reading from socket: %s", strerror(SOCKERRNO));
|
|
||||||
*err = CURLE_READ_ERROR;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
infof(data, "cr_recv read %ld bytes from the network\n", tls_bytes_read);
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
rresult = rustls_client_session_process_new_packets(session);
|
rresult = rustls_connection_process_new_packets(rconn);
|
||||||
if(rresult != RUSTLS_RESULT_OK) {
|
if(rresult != RUSTLS_RESULT_OK) {
|
||||||
rustls_error(rresult, errorbuf, sizeof(errorbuf), &n);
|
rustls_error(rresult, errorbuf, sizeof(errorbuf), &n);
|
||||||
failf(data, "%.*s", n, errorbuf);
|
failf(data, "%.*s", n, errorbuf);
|
||||||
@ -157,12 +152,10 @@ cr_recv(struct Curl_easy *data, int sockindex,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls_bytes_processed += n;
|
|
||||||
backend->data_pending = TRUE;
|
backend->data_pending = TRUE;
|
||||||
}
|
|
||||||
|
|
||||||
while(plain_bytes_copied < plainlen) {
|
while(plain_bytes_copied < plainlen) {
|
||||||
rresult = rustls_client_session_read(session,
|
rresult = rustls_connection_read(rconn,
|
||||||
(uint8_t *)plainbuf + plain_bytes_copied,
|
(uint8_t *)plainbuf + plain_bytes_copied,
|
||||||
plainlen - plain_bytes_copied,
|
plainlen - plain_bytes_copied,
|
||||||
&n);
|
&n);
|
||||||
@ -171,20 +164,21 @@ cr_recv(struct Curl_easy *data, int sockindex,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if(rresult != RUSTLS_RESULT_OK) {
|
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;
|
*err = CURLE_READ_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if(n == 0) {
|
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
|
available data has been read." If we bring in more ciphertext with
|
||||||
read_tls, more plaintext will become available. So don't tell curl
|
read_tls, more plaintext will become available. So don't tell curl
|
||||||
this is an EOF. Instead, say "come back later." */
|
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;
|
backend->data_pending = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
infof(data, "cr_recv copied out %ld bytes of plaintext\n", n);
|
||||||
plain_bytes_copied += n;
|
plain_bytes_copied += n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,68 +211,50 @@ cr_send(struct Curl_easy *data, int sockindex,
|
|||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
|
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
|
||||||
struct ssl_backend_data *const backend = connssl->backend;
|
struct ssl_backend_data *const backend = connssl->backend;
|
||||||
struct rustls_client_session *const session = backend->session;
|
struct rustls_connection *const rconn = backend->conn;
|
||||||
curl_socket_t sockfd = conn->sock[sockindex];
|
|
||||||
ssize_t n = 0;
|
|
||||||
size_t plainwritten = 0;
|
size_t plainwritten = 0;
|
||||||
size_t tlslen = 0;
|
|
||||||
size_t tlswritten = 0;
|
size_t tlswritten = 0;
|
||||||
|
size_t tlswritten_total = 0;
|
||||||
rustls_result rresult;
|
rustls_result rresult;
|
||||||
|
rustls_io_result io_error;
|
||||||
|
|
||||||
|
infof(data, "cr_send %ld bytes of plaintext\n", plainlen);
|
||||||
|
|
||||||
if(plainlen > 0) {
|
if(plainlen > 0) {
|
||||||
rresult = rustls_client_session_write(session,
|
rresult = rustls_connection_write(rconn, plainbuf, plainlen,
|
||||||
plainbuf, plainlen, &plainwritten);
|
&plainwritten);
|
||||||
if(rresult != RUSTLS_RESULT_OK) {
|
if(rresult != RUSTLS_RESULT_OK) {
|
||||||
failf(data, "error in rustls_client_session_write");
|
failf(data, "error in rustls_connection_write");
|
||||||
*err = CURLE_WRITE_ERROR;
|
*err = CURLE_WRITE_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if(plainwritten == 0) {
|
else if(plainwritten == 0) {
|
||||||
failf(data, "EOF in rustls_client_session_write");
|
failf(data, "EOF in rustls_connection_write");
|
||||||
*err = CURLE_WRITE_ERROR;
|
*err = CURLE_WRITE_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(rustls_client_session_wants_write(session)) {
|
while(rustls_connection_wants_write(rconn)) {
|
||||||
rresult = rustls_client_session_write_tls(
|
io_error = rustls_connection_write_tls(rconn, write_cb,
|
||||||
session, backend->tlsbuf, TLSBUF_SIZE, &tlslen);
|
&conn->sock[sockindex], &tlswritten);
|
||||||
if(rresult != RUSTLS_RESULT_OK) {
|
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
|
||||||
failf(data, "error in rustls_client_session_write_tls");
|
infof(data, "swrite: EAGAIN after %ld bytes\n", tlswritten_total);
|
||||||
|
*err = CURLE_AGAIN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if(io_error) {
|
||||||
|
failf(data, "writing to socket: %s", strerror(io_error));
|
||||||
*err = CURLE_WRITE_ERROR;
|
*err = CURLE_WRITE_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if(tlslen == 0) {
|
if(tlswritten == 0) {
|
||||||
failf(data, "EOF in rustls_client_session_write_tls");
|
|
||||||
*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");
|
failf(data, "EOF in swrite");
|
||||||
*err = CURLE_WRITE_ERROR;
|
*err = CURLE_WRITE_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
tlswritten += n;
|
infof(data, "cr_send wrote %ld bytes to network\n", tlswritten);
|
||||||
}
|
tlswritten_total += tlswritten;
|
||||||
|
|
||||||
DEBUGASSERT(tlswritten <= tlslen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return plainwritten;
|
return plainwritten;
|
||||||
@ -313,7 +289,7 @@ static CURLcode
|
|||||||
cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
|
cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
|
||||||
struct ssl_backend_data *const backend)
|
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;
|
struct rustls_client_config_builder *config_builder = NULL;
|
||||||
const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
|
const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
|
||||||
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
||||||
@ -326,11 +302,6 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
{ (const uint8_t *)ALPN_H2, ALPN_H2_LENGTH },
|
{ (const uint8_t *)ALPN_H2, ALPN_H2_LENGTH },
|
||||||
};
|
};
|
||||||
|
|
||||||
backend->tlsbuf = calloc(TLSBUF_SIZE, 1);
|
|
||||||
if(!backend->tlsbuf) {
|
|
||||||
return CURLE_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
config_builder = rustls_client_config_builder_new();
|
config_builder = rustls_client_config_builder_new();
|
||||||
#ifdef USE_HTTP2
|
#ifdef USE_HTTP2
|
||||||
infof(data, "offering ALPN for HTTP/1.1 and HTTP/2\n");
|
infof(data, "offering ALPN for HTTP/1.1 and HTTP/2\n");
|
||||||
@ -341,10 +312,11 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
#endif
|
#endif
|
||||||
if(!verifypeer) {
|
if(!verifypeer) {
|
||||||
rustls_client_config_builder_dangerous_set_certificate_verifier(
|
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
|
/* rustls doesn't support IP addresses (as of 0.19.0), and will reject
|
||||||
* sessions created with an IP address, even when certificate verification
|
* connections created with an IP address, even when certificate
|
||||||
* is turned off. Set a placeholder hostname and disable SNI. */
|
* verification is turned off. Set a placeholder hostname and disable
|
||||||
|
* SNI. */
|
||||||
if(cr_hostname_is_ip(hostname)) {
|
if(cr_hostname_is_ip(hostname)) {
|
||||||
rustls_client_config_builder_set_enable_sni(config_builder, false);
|
rustls_client_config_builder_set_enable_sni(config_builder, false);
|
||||||
hostname = "example.invalid";
|
hostname = "example.invalid";
|
||||||
@ -371,26 +343,26 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
backend->config = rustls_client_config_builder_build(config_builder);
|
backend->config = rustls_client_config_builder_build(config_builder);
|
||||||
DEBUGASSERT(session == NULL);
|
DEBUGASSERT(rconn == NULL);
|
||||||
result = rustls_client_session_new(
|
result = rustls_client_connection_new(backend->config, hostname, &rconn);
|
||||||
backend->config, hostname, &session);
|
|
||||||
if(result != RUSTLS_RESULT_OK) {
|
if(result != RUSTLS_RESULT_OK) {
|
||||||
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
|
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;
|
return CURLE_COULDNT_CONNECT;
|
||||||
}
|
}
|
||||||
backend->session = session;
|
rustls_connection_set_userdata(rconn, backend);
|
||||||
|
backend->conn = rconn;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
|
cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
|
||||||
const struct rustls_client_session *session)
|
const struct rustls_connection *rconn)
|
||||||
{
|
{
|
||||||
const uint8_t *protocol = NULL;
|
const uint8_t *protocol = NULL;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
rustls_client_session_get_alpn_protocol(session, &protocol, &len);
|
rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
|
||||||
if(NULL == protocol) {
|
if(NULL == protocol) {
|
||||||
infof(data, "ALPN, server did not agree to a protocol\n");
|
infof(data, "ALPN, server did not agree to a protocol\n");
|
||||||
return;
|
return;
|
||||||
@ -423,7 +395,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
|
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
|
||||||
curl_socket_t sockfd = conn->sock[sockindex];
|
curl_socket_t sockfd = conn->sock[sockindex];
|
||||||
struct ssl_backend_data *const backend = connssl->backend;
|
struct ssl_backend_data *const backend = connssl->backend;
|
||||||
struct rustls_client_session *session = NULL;
|
struct rustls_connection *rconn = NULL;
|
||||||
CURLcode tmperr = CURLE_OK;
|
CURLcode tmperr = CURLE_OK;
|
||||||
int result;
|
int result;
|
||||||
int what;
|
int what;
|
||||||
@ -440,7 +412,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
connssl->state = ssl_connection_negotiating;
|
connssl->state = ssl_connection_negotiating;
|
||||||
}
|
}
|
||||||
|
|
||||||
session = backend->session;
|
rconn = backend->conn;
|
||||||
|
|
||||||
/* Read/write data until the handshake is done or the socket would block. */
|
/* Read/write data until the handshake is done or the socket would block. */
|
||||||
for(;;) {
|
for(;;) {
|
||||||
@ -451,12 +423,12 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
* then becomes true when we first write data, then becomes false again
|
* then becomes true when we first write data, then becomes false again
|
||||||
* once the handshake is done.
|
* once the handshake is done.
|
||||||
*/
|
*/
|
||||||
if(!rustls_client_session_is_handshaking(session)) {
|
if(!rustls_connection_is_handshaking(rconn)) {
|
||||||
infof(data, "Done handshaking\n");
|
infof(data, "Done handshaking\n");
|
||||||
/* Done with the handshake. Set up callbacks to send/receive data. */
|
/* Done with the handshake. Set up callbacks to send/receive data. */
|
||||||
connssl->state = ssl_connection_complete;
|
connssl->state = ssl_connection_complete;
|
||||||
|
|
||||||
cr_set_negotiated_alpn(data, conn, session);
|
cr_set_negotiated_alpn(data, conn, rconn);
|
||||||
|
|
||||||
conn->recv[sockindex] = cr_recv;
|
conn->recv[sockindex] = cr_recv;
|
||||||
conn->send[sockindex] = cr_send;
|
conn->send[sockindex] = cr_send;
|
||||||
@ -464,8 +436,8 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
wants_read = rustls_client_session_wants_read(session);
|
wants_read = rustls_connection_wants_read(rconn);
|
||||||
wants_write = rustls_client_session_wants_write(session);
|
wants_write = rustls_connection_wants_write(rconn);
|
||||||
DEBUGASSERT(wants_read || wants_write);
|
DEBUGASSERT(wants_read || wants_write);
|
||||||
writefd = wants_write?sockfd:CURL_SOCKET_BAD;
|
writefd = wants_write?sockfd:CURL_SOCKET_BAD;
|
||||||
readfd = wants_read?sockfd:CURL_SOCKET_BAD;
|
readfd = wants_read?sockfd:CURL_SOCKET_BAD;
|
||||||
@ -489,7 +461,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
/* socket is readable or writable */
|
/* socket is readable or writable */
|
||||||
|
|
||||||
if(wants_write) {
|
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);
|
cr_send(data, sockindex, NULL, 0, &tmperr);
|
||||||
if(tmperr == CURLE_AGAIN) {
|
if(tmperr == CURLE_AGAIN) {
|
||||||
infof(data, "writing would block\n");
|
infof(data, "writing would block\n");
|
||||||
@ -501,7 +473,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(wants_read) {
|
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);
|
cr_recv(data, sockindex, NULL, 0, &tmperr);
|
||||||
if(tmperr == CURLE_AGAIN) {
|
if(tmperr == CURLE_AGAIN) {
|
||||||
@ -532,13 +504,13 @@ cr_getsock(struct connectdata *conn, curl_socket_t *socks)
|
|||||||
struct ssl_connect_data *const connssl = &conn->ssl[FIRSTSOCKET];
|
struct ssl_connect_data *const connssl = &conn->ssl[FIRSTSOCKET];
|
||||||
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
|
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
|
||||||
struct ssl_backend_data *const backend = connssl->backend;
|
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;
|
socks[0] = sockfd;
|
||||||
return GETSOCK_WRITESOCK(0);
|
return GETSOCK_WRITESOCK(0);
|
||||||
}
|
}
|
||||||
if(rustls_client_session_wants_read(session)) {
|
if(rustls_connection_wants_read(rconn)) {
|
||||||
socks[0] = sockfd;
|
socks[0] = sockfd;
|
||||||
return GETSOCK_READSOCK(0);
|
return GETSOCK_READSOCK(0);
|
||||||
}
|
}
|
||||||
@ -551,7 +523,7 @@ cr_get_internals(struct ssl_connect_data *connssl,
|
|||||||
CURLINFO info UNUSED_PARAM)
|
CURLINFO info UNUSED_PARAM)
|
||||||
{
|
{
|
||||||
struct ssl_backend_data *backend = connssl->backend;
|
struct ssl_backend_data *backend = connssl->backend;
|
||||||
return &backend->session;
|
return &backend->conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -563,21 +535,20 @@ cr_close(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
CURLcode tmperr = CURLE_OK;
|
CURLcode tmperr = CURLE_OK;
|
||||||
ssize_t n = 0;
|
ssize_t n = 0;
|
||||||
|
|
||||||
if(backend->session) {
|
if(backend->conn) {
|
||||||
rustls_client_session_send_close_notify(backend->session);
|
rustls_connection_send_close_notify(backend->conn);
|
||||||
n = cr_send(data, sockindex, NULL, 0, &tmperr);
|
n = cr_send(data, sockindex, NULL, 0, &tmperr);
|
||||||
if(n < 0) {
|
if(n < 0) {
|
||||||
failf(data, "error sending close notify: %d", tmperr);
|
failf(data, "error sending close notify: %d", tmperr);
|
||||||
}
|
}
|
||||||
|
|
||||||
rustls_client_session_free(backend->session);
|
rustls_connection_free(backend->conn);
|
||||||
backend->session = NULL;
|
backend->conn = NULL;
|
||||||
}
|
}
|
||||||
if(backend->config) {
|
if(backend->config) {
|
||||||
rustls_client_config_free(backend->config);
|
rustls_client_config_free(backend->config);
|
||||||
backend->config = NULL;
|
backend->config = NULL;
|
||||||
}
|
}
|
||||||
free(backend->tlsbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct Curl_ssl Curl_ssl_rustls = {
|
const struct Curl_ssl Curl_ssl_rustls = {
|
||||||
|
@ -70,7 +70,7 @@ if test "x$OPT_RUSTLS" != xno; then
|
|||||||
CPPFLAGS="$CPPFLAGS $addcflags"
|
CPPFLAGS="$CPPFLAGS $addcflags"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_CHECK_LIB(crustls, rustls_client_session_read,
|
AC_CHECK_LIB(crustls, rustls_connection_read,
|
||||||
[
|
[
|
||||||
AC_DEFINE(USE_RUSTLS, 1, [if rustls is enabled])
|
AC_DEFINE(USE_RUSTLS, 1, [if rustls is enabled])
|
||||||
AC_SUBST(USE_RUSTLS, [1])
|
AC_SUBST(USE_RUSTLS, [1])
|
||||||
|
@ -60,7 +60,7 @@ test325 test326 test327 test328 test329 test330 test331 test332 test333 \
|
|||||||
test334 test335 test336 test337 test338 test339 test340 test341 test342 \
|
test334 test335 test336 test337 test338 test339 test340 test341 test342 \
|
||||||
test343 test344 test345 test346 test347 test348 test349 test350 test351 \
|
test343 test344 test345 test346 test347 test348 test349 test350 test351 \
|
||||||
test352 test353 test354 test355 test356 test357 test358 test359 test360 \
|
test352 test353 test354 test355 test356 test357 test358 test359 test360 \
|
||||||
test361 test362 test363 \
|
test361 test362 test363 test364 \
|
||||||
\
|
\
|
||||||
test393 test394 test395 test396 test397 \
|
test393 test394 test395 test396 test397 \
|
||||||
\
|
\
|
||||||
|
51
tests/data/test364
Normal file
51
tests/data/test364
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<testcase>
|
||||||
|
<info>
|
||||||
|
<keywords>
|
||||||
|
HTTPS
|
||||||
|
HTTPS PUT
|
||||||
|
</keywords>
|
||||||
|
</info>
|
||||||
|
# Server-side
|
||||||
|
<reply>
|
||||||
|
<data>
|
||||||
|
HTTP/1.0 200 OK swsclose
|
||||||
|
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
Server: test-server/fake
|
||||||
|
|
||||||
|
blablabla
|
||||||
|
</data>
|
||||||
|
</reply>
|
||||||
|
|
||||||
|
# Client-side
|
||||||
|
<client>
|
||||||
|
<features>
|
||||||
|
SSL
|
||||||
|
</features>
|
||||||
|
<server>
|
||||||
|
https
|
||||||
|
</server>
|
||||||
|
<name>
|
||||||
|
HTTPS PUT of small file
|
||||||
|
</name>
|
||||||
|
<command>
|
||||||
|
-k https://%HOSTIP:%HTTPSPORT/we/want/%TESTNUMBER -T log/test%TESTNUMBER.txt
|
||||||
|
</command>
|
||||||
|
<file name="log/test%TESTNUMBER.txt">
|
||||||
|
%repeat[200 x banana]%
|
||||||
|
</file>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
# Verify data after the test has been "shot"
|
||||||
|
<verify>
|
||||||
|
<protocol>
|
||||||
|
PUT /we/want/%TESTNUMBER HTTP/1.1
|
||||||
|
Host: %HOSTIP:%HTTPSPORT
|
||||||
|
User-Agent: curl/%VERSION
|
||||||
|
Accept: */*
|
||||||
|
Content-Length: 1201
|
||||||
|
Expect: 100-continue
|
||||||
|
|
||||||
|
%repeat[200 x banana]%
|
||||||
|
</protocol>
|
||||||
|
</verify>
|
||||||
|
</testcase>
|
Loading…
Reference in New Issue
Block a user