tls: backends use connection filters for IO, enabling HTTPS-proxy

- OpenSSL (and compatible)
 - BearSSL
 - gnutls
 - mbedtls
 - rustls
 - schannel
 - secure-transport
 - wolfSSL (v5.0.0 and newer)

 This leaves only the following without HTTPS-proxy support:
 - gskit
 - nss
 - wolfSSL (versions earlier than v5.0.0)

Closes #9962
This commit is contained in:
Stefan Eissing 2022-11-25 14:06:43 +01:00 committed by Daniel Stenberg
parent dbd74baf78
commit 55807e6c05
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
22 changed files with 793 additions and 422 deletions

View File

@ -1463,7 +1463,10 @@ _add_if("TLS-SRP" USE_TLS_SRP)
_add_if("HTTP2" USE_NGHTTP2)
_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE)
_add_if("MultiSSL" CURL_WITH_MULTI_SSL)
_add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS))
# TODO wolfSSL only support this from v5.0.0 onwards
_add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS
OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
USE_MBEDTLS OR USE_SECTRANSP))
_add_if("unicode" ENABLE_UNICODE)
_add_if("threadsafe" HAVE_ATOMIC OR (WIN32 AND
HAVE_WIN32_WINNT GREATER_EQUAL 0x600))

View File

@ -4387,8 +4387,17 @@ fi
dnl if not explicitly turned off, HTTPS-proxy comes with some TLS backends
if test "x$https_proxy" != "xno"; then
if test "x$OPENSSL_ENABLED" = "x1" -o "x$GNUTLS_ENABLED" = "x1" \
-o "x$NSS_ENABLED" = "x1"; then
if test "x$OPENSSL_ENABLED" = "x1" \
-o "x$GNUTLS_ENABLED" = "x1" \
-o "x$NSS_ENABLED" = "x1" \
-o "x$SECURETRANSPORT_ENABLED" = "x1" \
-o "x$RUSTLS_ENABLED" = "x1" \
-o "x$BEARSSL_ENABLED" = "x1" \
-o "x$SCHANNEL_ENABLED" = "x1" \
-o "x$GNUTLS_ENABLED" = "x1" \
-o "x$MBEDTLS_ENABLED" = "x1"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPS-proxy"
elif test "x$WOLFSSL_ENABLED" = "x1" -a "x$WOLFSSL_FULL_BIO" = "x1"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPS-proxy"
fi
fi

View File

@ -134,7 +134,6 @@ void Curl_conn_cf_discard_all(struct Curl_easy *data,
struct Curl_cfilter *cfn, *cf = conn->cfilter[index];
if(cf) {
DEBUGF(infof(data, CMSGI(conn, index, "Curl_conn_cf_discard_all()")));
conn->cfilter[index] = NULL;
while(cf) {
cfn = cf->next;
@ -153,7 +152,6 @@ void Curl_conn_close(struct Curl_easy *data, int index)
/* it is valid to call that without filters being present */
cf = data->conn->cfilter[index];
if(cf) {
DEBUGF(infof(data, DMSGI(data, index, "close()")));
cf->cft->close(cf, data);
}
}
@ -261,6 +259,18 @@ void Curl_conn_cf_discard(struct Curl_cfilter *cf, struct Curl_easy *data)
free(cf);
}
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
return cf->cft->do_send(cf, data, buf, len, err);
}
ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
return cf->cft->do_recv(cf, data, buf, len, err);
}
CURLcode Curl_conn_setup(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
@ -384,6 +394,21 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
return FALSE;
}
bool Curl_conn_is_ssl(struct Curl_easy *data, int sockindex)
{
struct Curl_cfilter *cf = data->conn? data->conn->cfilter[sockindex] : NULL;
(void)data;
for(; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_SSL)
return TRUE;
if(cf->cft->flags & CF_TYPE_IP_CONNECT)
return FALSE;
}
return FALSE;
}
bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
{
struct Curl_cfilter *cf;
@ -427,7 +452,6 @@ void Curl_conn_attach_data(struct connectdata *conn,
for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
cf = conn->cfilter[i];
if(cf) {
DEBUGF(infof(data, DMSGI(data, i, "attach_data()")));
while(cf) {
cf->cft->attach_data(cf, data);
cf = cf->next;
@ -445,7 +469,6 @@ void Curl_conn_detach_data(struct connectdata *conn,
for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
cf = conn->cfilter[i];
if(cf) {
DEBUGF(infof(data, DMSGI(data, i, "detach_data()")));
while(cf) {
cf->cft->detach_data(cf, data);
cf = cf->next;

View File

@ -33,20 +33,20 @@ struct connectdata;
/* Callback to destroy resources held by this filter instance.
* Implementations MUST NOT chain calls to cf->next.
*/
typedef void Curl_cf_destroy_this(struct Curl_cfilter *cf,
struct Curl_easy *data);
typedef void Curl_cft_destroy_this(struct Curl_cfilter *cf,
struct Curl_easy *data);
/* Setup the connection for `data`, using destination `remotehost`.
*/
typedef CURLcode Curl_cf_setup(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct Curl_dns_entry *remotehost);
typedef void Curl_cf_close(struct Curl_cfilter *cf,
struct Curl_easy *data);
typedef CURLcode Curl_cft_setup(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct Curl_dns_entry *remotehost);
typedef void Curl_cft_close(struct Curl_cfilter *cf,
struct Curl_easy *data);
typedef CURLcode Curl_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking, bool *done);
typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking, bool *done);
/* Return the hostname and port the connection goes to.
* This may change with the connection state of filters when tunneling
@ -59,40 +59,40 @@ typedef CURLcode Curl_cf_connect(struct Curl_cfilter *cf,
* this is owned by the connection.
* @param pport on return, contains the port number
*/
typedef void Curl_cf_get_host(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char **phost,
const char **pdisplay_host,
int *pport);
typedef void Curl_cft_get_host(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char **phost,
const char **pdisplay_host,
int *pport);
/* Filters may return sockets and fdset flags they are waiting for.
* The passes array has room for up to MAX_SOCKSPEREASYHANDLE sockets.
* @return read/write fdset for index in socks
* or GETSOCK_BLANK when nothing to wait on
*/
typedef int Curl_cf_get_select_socks(struct Curl_cfilter *cf,
struct Curl_easy *data,
curl_socket_t *socks);
typedef int Curl_cft_get_select_socks(struct Curl_cfilter *cf,
struct Curl_easy *data,
curl_socket_t *socks);
typedef bool Curl_cf_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
typedef ssize_t Curl_cf_send(struct Curl_cfilter *cf,
struct Curl_easy *data, /* transfer */
const void *buf, /* data to write */
size_t len, /* max amount to write */
CURLcode *err); /* error to return */
typedef ssize_t Curl_cft_send(struct Curl_cfilter *cf,
struct Curl_easy *data, /* transfer */
const void *buf, /* data to write */
size_t len, /* amount to write */
CURLcode *err); /* error to return */
typedef ssize_t Curl_cf_recv(struct Curl_cfilter *cf,
struct Curl_easy *data, /* transfer */
char *buf, /* store data here */
size_t len, /* max amount to read */
CURLcode *err); /* error to return */
typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf,
struct Curl_easy *data, /* transfer */
char *buf, /* store data here */
size_t len, /* amount to read */
CURLcode *err); /* error to return */
typedef void Curl_cf_attach_data(struct Curl_cfilter *cf,
struct Curl_easy *data);
typedef void Curl_cf_detach_data(struct Curl_cfilter *cf,
struct Curl_easy *data);
typedef void Curl_cft_attach_data(struct Curl_cfilter *cf,
struct Curl_easy *data);
typedef void Curl_cft_detach_data(struct Curl_cfilter *cf,
struct Curl_easy *data);
/**
* The easy handle `data` is being detached (no longer served)
@ -108,19 +108,19 @@ void Curl_conn_detach(struct connectdata *conn, struct Curl_easy *data);
/* A connection filter type, e.g. specific implementation. */
struct Curl_cftype {
const char *name; /* name of the filter type */
long flags; /* flags of filter type */
Curl_cf_destroy_this *destroy; /* destroy resources of this cf */
Curl_cf_setup *setup; /* setup for a connection */
Curl_cf_connect *connect; /* establish connection */
Curl_cf_close *close; /* close conn */
Curl_cf_get_host *get_host; /* host filter talks to */
Curl_cf_get_select_socks *get_select_socks;/* sockets to select on */
Curl_cf_data_pending *has_data_pending;/* conn has data pending */
Curl_cf_send *do_send; /* send data */
Curl_cf_recv *do_recv; /* receive data */
Curl_cf_attach_data *attach_data; /* data is being handled here */
Curl_cf_detach_data *detach_data; /* data is no longer handled here */
const char *name; /* name of the filter type */
long flags; /* flags of filter type */
Curl_cft_destroy_this *destroy; /* destroy resources of this cf */
Curl_cft_setup *setup; /* setup for a connection */
Curl_cft_connect *connect; /* establish connection */
Curl_cft_close *close; /* close conn */
Curl_cft_get_host *get_host; /* host filter talks to */
Curl_cft_get_select_socks *get_select_socks;/* sockets to select on */
Curl_cft_data_pending *has_data_pending;/* conn has data pending */
Curl_cft_send *do_send; /* send data */
Curl_cft_recv *do_recv; /* receive data */
Curl_cft_attach_data *attach_data; /* data is being handled here */
Curl_cft_detach_data *detach_data; /* data is no longer handled here */
};
/* A connection filter instance, e.g. registered at a connection */
@ -198,6 +198,12 @@ void Curl_conn_cf_discard_all(struct Curl_easy *data,
*/
void Curl_conn_cf_discard(struct Curl_cfilter *cf, struct Curl_easy *data);
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err);
ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err);
#define CURL_CF_SSL_DEFAULT -1
#define CURL_CF_SSL_DISABLE 0
#define CURL_CF_SSL_ENABLE 1
@ -237,6 +243,13 @@ bool Curl_conn_is_connected(struct connectdata *conn, int sockindex);
*/
bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex);
/**
* Determine if the connection is using SSL to the remote host
* (or will be once connected). This will return FALSE, if SSL
* is only used in proxying and not for the tunnel itself.
*/
bool Curl_conn_is_ssl(struct Curl_easy *data, int sockindex);
/**
* Close the filter chain at `sockindex` for connection `data->conn`.
* Filters remain in place and may be connected again afterwards.

View File

@ -1690,8 +1690,6 @@ static CURLcode socket_cf_connect(struct Curl_cfilter *cf,
result = Curl_connecthost(data, conn, ctx->remotehost);
if(!result)
ctx->state = SCFST_WAITING;
DEBUGF(infof(data, CFMSG(cf, "connect(INIT) -> %d, done=%d"),
result, *done));
break;
case SCFST_WAITING:
result = is_connected(data, conn, sockindex, done);
@ -1704,13 +1702,9 @@ static CURLcode socket_cf_connect(struct Curl_cfilter *cf,
ctx->state = SCFST_DONE;
cf->connected = TRUE;
}
DEBUGF(infof(data, CFMSG(cf, "connect(WAIT) -> %d, done=%d"),
result, *done));
break;
case SCFST_DONE:
*done = TRUE;
DEBUGF(infof(data, CFMSG(cf, "connect(DONE) -> %d, done=%d"),
result, *done));
break;
}
return result;
@ -1783,8 +1777,6 @@ static ssize_t socket_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
{
ssize_t nwritten;
nwritten = Curl_send_plain(data, cf->sockindex, buf, len, err);
DEBUGF(infof(data, CFMSG(cf, "send(len=%ld) -> %ld, err=%d"),
len, nwritten, *err));
return nwritten;
}
@ -1793,7 +1785,6 @@ static ssize_t socket_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
{
ssize_t nread;
nread = Curl_recv_plain(data, cf->sockindex, buf, len, err);
DEBUGF(infof(data, CFMSG(cf, "recv() -> %ld"), nread));
return nread;
}
@ -1802,7 +1793,6 @@ static void socket_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
struct socket_cf_ctx *state = cf->ctx;
(void)data;
DEBUGF(infof(data, CFMSG(cf, "destroy()")));
if(cf->connected) {
socket_cf_close(cf, data);
}

View File

@ -2742,7 +2742,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
if((ftpcode == 234) || (ftpcode == 334)) {
/* this was BLOCKING, keep it so for now */
bool done;
if(!Curl_ssl_conn_is_ssl(data, FIRSTSOCKET)) {
if(!Curl_conn_is_ssl(data, FIRSTSOCKET)) {
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
if(result) {
/* we failed and bail out */

View File

@ -172,8 +172,6 @@ static void tunnel_go_state(struct Curl_cfilter *cf,
{
if(ts->tunnel_state == new_state)
return;
DEBUGF(infof(data, CFMSG(cf, "tunnel %p go_state %d -> %d"),
ts, ts->tunnel_state, new_state));
/* leaving this one */
switch(ts->tunnel_state) {
case TUNNEL_CONNECT:
@ -488,7 +486,6 @@ static CURLcode recv_CONNECT_resp(struct Curl_easy *data,
#define SELECT_OK 0
#define SELECT_ERROR 1
DEBUGF(infof(data, "CONNECT: recv response, keepon=%d", ts->keepon));
error = SELECT_OK;
*done = FALSE;
@ -642,7 +639,6 @@ static CURLcode recv_CONNECT_resp(struct Curl_easy *data,
}
}
else {
DEBUGF(infof(data, "CONNECT: no end of response headers"));
ts->keepon = KEEPON_DONE;
}
@ -1085,8 +1081,6 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
cf->ctx = ts;
}
DEBUGF(infof(data, CFMSG(cf, "connect(%s:%d, state=%d)"),
ts->hostname, ts->remote_port, ts->tunnel_state));
result = CONNECT(cf, data, ts);
if(result)
goto out;
@ -1098,8 +1092,6 @@ out:
cf->connected = TRUE;
tunnel_free(cf, data);
}
DEBUGF(infof(data, CFMSG(cf, "connect(block=%d) -> %d, done=%d"),
blocking, result, *done));
return result;
}

View File

@ -476,7 +476,7 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
struct imap_conn *imapc = &conn->proto.imapc;
CURLcode result;
if(!Curl_ssl_conn_is_ssl(data, FIRSTSOCKET)) {
if(!Curl_conn_is_ssl(data, FIRSTSOCKET)) {
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
if(result)
goto out;

View File

@ -371,7 +371,7 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
struct pop3_conn *pop3c = &conn->proto.pop3c;
CURLcode result;
if(!Curl_ssl_conn_is_ssl(data, FIRSTSOCKET)) {
if(!Curl_conn_is_ssl(data, FIRSTSOCKET)) {
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
if(result)
goto out;

View File

@ -398,7 +398,7 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
struct smtp_conn *smtpc = &conn->proto.smtpc;
CURLcode result;
if(!Curl_ssl_conn_is_ssl(data, FIRSTSOCKET)) {
if(!Curl_conn_is_ssl(data, FIRSTSOCKET)) {
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
if(result)
goto out;

View File

@ -764,11 +764,11 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
{
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
unsigned state;
unsigned char *buf;
size_t len;
ssize_t ret;
CURLcode result;
int err;
DEBUGASSERT(backend);
@ -807,31 +807,21 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
return CURLE_OK;
if(state & BR_SSL_SENDREC) {
buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
ret = swrite(sockfd, buf, len);
if(ret == -1) {
if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
if(connssl->state != ssl_connection_complete)
connssl->connecting_state = ssl_connect_2_writing;
return CURLE_AGAIN;
}
return CURLE_WRITE_ERROR;
ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
if(ret <= 0) {
return result;
}
br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
}
else if(state & BR_SSL_RECVREC) {
buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
ret = sread(sockfd, buf, len);
ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
return CURLE_READ_ERROR;
}
if(ret == -1) {
if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
if(connssl->state != ssl_connection_complete)
connssl->connecting_state = ssl_connect_2_reading;
return CURLE_AGAIN;
}
return CURLE_READ_ERROR;
if(ret <= 0) {
return result;
}
br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
}
@ -1183,7 +1173,7 @@ static CURLcode bearssl_sha256sum(const unsigned char *input,
const struct Curl_ssl Curl_ssl_bearssl = {
{ CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX,
SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
Curl_none_init, /* init */

View File

@ -92,28 +92,40 @@ struct ssl_backend_data {
#endif
};
static ssize_t gtls_push(void *s, const void *buf, size_t len)
static ssize_t gtls_push(void *s, const void *buf, size_t blen)
{
curl_socket_t sock = *(curl_socket_t *)s;
ssize_t ret = swrite(sock, buf, len);
return ret;
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
struct Curl_easy *data = connssl->call_data;
ssize_t nwritten;
CURLcode result;
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
if(nwritten < 0) {
gnutls_transport_set_errno(connssl->backend->session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nwritten = -1;
}
return nwritten;
}
static ssize_t gtls_pull(void *s, void *buf, size_t len)
static ssize_t gtls_pull(void *s, void *buf, size_t blen)
{
curl_socket_t sock = *(curl_socket_t *)s;
ssize_t ret = sread(sock, buf, len);
return ret;
}
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
struct Curl_easy *data = connssl->call_data;
ssize_t nread;
CURLcode result;
static ssize_t gtls_push_ssl(void *s, const void *buf, size_t len)
{
return gnutls_record_send((gnutls_session_t) s, buf, len);
}
static ssize_t gtls_pull_ssl(void *s, void *buf, size_t len)
{
return gnutls_record_recv((gnutls_session_t) s, buf, len);
DEBUGASSERT(data);
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
if(nread < 0) {
gnutls_transport_set_errno(connssl->backend->session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nread = -1;
}
return nread;
}
/* gtls_init()
@ -419,9 +431,6 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
const char *hostname = connssl->hostname;
long * const certverifyresult = &ssl_config->certverifyresult;
const char *tls13support;
struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
struct ssl_connect_data *connssl_next = cf_ssl_next?
cf_ssl_next->ctx : NULL;
CURLcode result;
DEBUGASSERT(backend);
@ -720,18 +729,10 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
if(connssl_next) {
DEBUGASSERT(connssl_next->backend);
transport_ptr = connssl_next->backend;
gnutls_transport_push = gtls_push_ssl;
gnutls_transport_pull = gtls_pull_ssl;
}
else {
/* file descriptor for the socket */
transport_ptr = &cf->conn->sock[cf->sockindex];
gnutls_transport_push = gtls_push;
gnutls_transport_pull = gtls_pull;
}
/* push/pull through filter chain */
transport_ptr = cf;
gnutls_transport_push = gtls_push;
gnutls_transport_pull = gtls_pull;
/* set the connection handle */
gnutls_transport_set_ptr(session, transport_ptr);
@ -1352,20 +1353,25 @@ gtls_connect_common(struct Curl_cfilter *cf,
bool nonblocking,
bool *done)
{
int rc;
struct ssl_connect_data *connssl = cf->ctx;
int rc;
CURLcode result = CURLE_OK;
/* Initiate the connection, if not already done */
if(ssl_connect_1 == connssl->connecting_state) {
rc = gtls_connect_step1(cf, data);
if(rc)
return rc;
if(rc) {
result = rc;
goto out;
}
}
rc = handshake(cf, data, TRUE, nonblocking);
if(rc)
if(rc) {
/* handshake() sets its own error message with failf() */
return rc;
result = rc;
goto out;
}
/* Finish connecting once the handshake is done */
if(ssl_connect_1 == connssl->connecting_state) {
@ -1374,13 +1380,16 @@ gtls_connect_common(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
session = backend->session;
rc = Curl_gtls_verifyserver(cf, data, session);
if(rc)
return rc;
if(rc) {
result = rc;
goto out;
}
}
out:
*done = ssl_connect_1 == connssl->connecting_state;
return CURLE_OK;
return result;
}
static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf,
@ -1570,7 +1579,8 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
ret = gnutls_record_recv(backend->session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
return -1;
ret = -1;
goto out;
}
if(ret == GNUTLS_E_REHANDSHAKE) {
@ -1582,7 +1592,8 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
*curlcode = result;
else
*curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
return -1;
ret = -1;
goto out;
}
if(ret < 0) {
@ -1590,9 +1601,11 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
(int)ret, gnutls_strerror((int)ret));
*curlcode = CURLE_RECV_ERROR;
return -1;
ret = -1;
goto out;
}
out:
return ret;
}

View File

@ -156,6 +156,46 @@ static void mbed_debug(void *context, int level, const char *f_name,
#else
#endif
static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen)
{
struct Curl_cfilter *cf = bio;
struct ssl_connect_data *connssl = cf->ctx;
struct Curl_easy *data = connssl->call_data;
ssize_t nwritten;
CURLcode result;
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result);
/* DEBUGF(infof(data, CFMSG(cf, "bio_cf_out_write(len=%d) -> %d, err=%d"),
blen, (int)nwritten, result)); */
if(nwritten < 0 && CURLE_AGAIN == result) {
nwritten = MBEDTLS_ERR_SSL_WANT_WRITE;
}
return (int)nwritten;
}
static int bio_cf_read(void *bio, unsigned char *buf, size_t blen)
{
struct Curl_cfilter *cf = bio;
struct ssl_connect_data *connssl = cf->ctx;
struct Curl_easy *data = connssl->call_data;
ssize_t nread;
CURLcode result;
DEBUGASSERT(data);
/* OpenSSL catches this case, so should we. */
if(!buf)
return 0;
nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result);
/* DEBUGF(infof(data, CFMSG(cf, "bio_cf_in_read(len=%d) -> %d, err=%d"),
blen, (int)nread, result)); */
if(nread < 0 && CURLE_AGAIN == result) {
nread = MBEDTLS_ERR_SSL_WANT_READ;
}
return (int)nread;
}
/*
* profile
*/
@ -551,9 +591,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
&backend->ctr_drbg);
mbedtls_ssl_set_bio(&backend->ssl, &cf->conn->sock[cf->sockindex],
mbedtls_net_send,
mbedtls_net_recv,
mbedtls_ssl_set_bio(&backend->ssl, cf, bio_cf_write, bio_cf_read,
NULL /* rev_timeout() */);
mbedtls_ssl_conf_ciphersuites(&backend->config,
@ -902,7 +940,6 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
(void)data;
DEBUGASSERT(backend);
ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
if(ret < 0) {
@ -924,8 +961,8 @@ static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
char buf[32];
(void) data;
(void)data;
DEBUGASSERT(backend);
/* Maybe the server has already sent a close notify alert.
@ -1229,7 +1266,8 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
SSLSUPP_PINNEDPUBKEY |
SSLSUPP_SSL_CTX,
SSLSUPP_SSL_CTX |
SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),

View File

@ -635,6 +635,166 @@ CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
#ifdef USE_OPENSSL
#if USE_PRE_1_1_API
#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
#define BIO_set_init(x,v) ((x)->init=(v))
#define BIO_get_data(x) ((x)->ptr)
#define BIO_set_data(x,v) ((x)->ptr=(v))
#endif
#define BIO_get_shutdown(x) ((x)->shutdown)
#define BIO_set_shutdown(x,v) ((x)->shutdown=(v))
#endif /* USE_PRE_1_1_API */
static int bio_cf_create(BIO *bio)
{
BIO_set_shutdown(bio, 1);
BIO_set_init(bio, 1);
#if USE_PRE_1_1_API
bio->num = -1;
#endif
BIO_set_data(bio, NULL);
return 1;
}
static int bio_cf_destroy(BIO *bio)
{
if(!bio)
return 0;
return 1;
}
static long bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
long ret = 1;
(void)cf;
(void)ptr;
switch(cmd) {
case BIO_CTRL_GET_CLOSE:
ret = (long)BIO_get_shutdown(bio);
break;
case BIO_CTRL_SET_CLOSE:
BIO_set_shutdown(bio, (int)num);
break;
case BIO_CTRL_FLUSH:
/* we do no delayed writes, but if we ever would, this
* needs to trigger it. */
ret = 1;
break;
case BIO_CTRL_DUP:
ret = 1;
break;
#ifdef BIO_CTRL_EOF
case BIO_CTRL_EOF:
/* EOF has been reached on input? */
return (!cf->next || !cf->next->connected);
#endif
default:
ret = 0;
break;
}
return ret;
}
static int bio_cf_out_write(BIO *bio, const char *buf, int blen)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
struct Curl_easy *data = connssl->call_data;
ssize_t nwritten;
CURLcode result = CURLE_SEND_ERROR;
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
/* DEBUGF(infof(data, CFMSG(cf, "bio_cf_out_write(len=%d) -> %d, err=%d"),
blen, (int)nwritten, result)); */
BIO_clear_retry_flags(bio);
if(nwritten < 0) {
if(CURLE_AGAIN == result) {
BIO_set_retry_write(bio);
nwritten = 0;
}
else {
nwritten = -1;
}
}
return (int)nwritten;
}
static int bio_cf_in_read(BIO *bio, char *buf, int blen)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
struct Curl_easy *data = connssl->call_data;
ssize_t nread;
CURLcode result = CURLE_RECV_ERROR;
DEBUGASSERT(data);
/* OpenSSL catches this case, so should we. */
if(!buf)
return 0;
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
/* DEBUGF(infof(data, CFMSG(cf, "bio_cf_in_read(len=%d) -> %d, err=%d"),
blen, (int)nread, result)); */
BIO_clear_retry_flags(bio);
if(nread < 0) {
if(CURLE_AGAIN == result) {
BIO_set_retry_read(bio);
nread = 0;
}
else {
nread = -1;
}
}
return (int)nread;
}
static BIO_METHOD *bio_cf_method = NULL;
#if USE_PRE_1_1_API
static BIO_METHOD bio_cf_meth_1_0 = {
BIO_TYPE_MEM,
"OpenSSL CF BIO",
bio_cf_out_write,
bio_cf_in_read,
NULL, /* puts is never called */
NULL, /* gets is never called */
bio_cf_ctrl,
bio_cf_create,
bio_cf_destroy,
NULL
};
static void bio_cf_init_methods(void)
{
bio_cf_method = &bio_cf_meth_1_0;
}
#define bio_cf_free_methods() Curl_nop_stmt
#else
static void bio_cf_init_methods(void)
{
bio_cf_method = BIO_meth_new(BIO_TYPE_MEM, "OpenSSL CF BIO");
BIO_meth_set_write(bio_cf_method, &bio_cf_out_write);
BIO_meth_set_read(bio_cf_method, &bio_cf_in_read);
BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl);
BIO_meth_set_create(bio_cf_method, &bio_cf_create);
BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy);
}
static void bio_cf_free_methods(void)
{
BIO_meth_free(bio_cf_method);
}
#endif
static bool ossl_attach_data(struct Curl_cfilter *cf,
struct Curl_easy *data);
@ -1602,6 +1762,7 @@ static int ossl_init(void)
OpenSSL_add_all_algorithms();
#endif
bio_cf_init_methods();
Curl_tls_keylog_open();
/* Initialize the extra data indexes */
@ -1647,6 +1808,7 @@ static void ossl_cleanup(void)
#endif
Curl_tls_keylog_close();
bio_cf_free_methods();
}
/*
@ -1803,21 +1965,17 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
if(backend->handle) {
char buf[32];
set_logger(connssl, data);
/*
* The conn->sock[0] socket is passed to openssl with SSL_set_fd(). Make
* sure the socket is not closed before calling OpenSSL functions that
* will use it.
*/
DEBUGASSERT(cf->conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD);
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)SSL_read(backend->handle, buf, (int)sizeof(buf));
if(cf->next && cf->next->connected) {
char buf[32];
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)SSL_read(backend->handle, buf, (int)sizeof(buf));
(void)SSL_shutdown(backend->handle);
SSL_set_connect_state(backend->handle);
(void)SSL_shutdown(backend->handle);
SSL_set_connect_state(backend->handle);
}
SSL_free(backend->handle);
backend->handle = NULL;
@ -2032,6 +2190,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
int port;
size_t hostlen;
(void)conn;
Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &dispname, &port);
hostlen = strlen(hostname);
@ -3311,17 +3470,12 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
CURLcode result = CURLE_OK;
char *ciphers;
SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
struct ssl_connect_data *connssl = cf->ctx;
ctx_option_t ctx_options = 0;
void *ssl_sessionid = NULL;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
#ifndef CURL_DISABLE_PROXY
struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
struct ssl_connect_data *connssl_next = cf_ssl_next?
cf_ssl_next->ctx : NULL;
#endif
BIO *bio;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
bool sni;
@ -3382,7 +3536,12 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
DEBUGASSERT(!backend->ctx);
if(backend->ctx) {
/* This happens when an error was encountered before in this
* step and we are called to do it again. Get rid of any leftover
* from the previous call. */
ossl_close(cf, data);
}
backend->ctx = SSL_CTX_new(req_method);
if(!backend->ctx) {
@ -3707,24 +3866,12 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
Curl_ssl_sessionid_unlock(data);
}
#ifndef CURL_DISABLE_PROXY
if(connssl_next) {
BIO *const bio = BIO_new(BIO_f_ssl());
DEBUGASSERT(connssl_next->backend);
DEBUGASSERT(ssl_connection_complete == connssl_next->state);
DEBUGASSERT(connssl_next->backend->handle != NULL);
DEBUGASSERT(bio != NULL);
BIO_set_ssl(bio, connssl_next->backend->handle, FALSE);
SSL_set_bio(backend->handle, bio, bio);
}
else
#endif
if(!SSL_set_fd(backend->handle, (int)sockfd)) {
/* pass the raw socket into the SSL layers */
failf(data, "SSL: SSL_set_fd failed: %s",
ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
bio = BIO_new(bio_cf_method);
if(!bio)
return CURLE_OUT_OF_MEMORY;
BIO_set_data(bio, cf);
SSL_set_bio(backend->handle, bio, bio);
connssl->connecting_state = ssl_connect_2;
@ -4205,7 +4352,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
bool nonblocking,
bool *done)
{
CURLcode result;
CURLcode result = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
int what;
@ -4228,7 +4375,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
result = ossl_connect_step1(cf, data);
if(result)
return result;
goto out;
}
while(ssl_connect_2 == connssl->connecting_state ||
@ -4241,7 +4388,8 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
if(timeout_ms < 0) {
/* no need to continue if time already is up */
failf(data, "SSL connection timeout");
return CURLE_OPERATION_TIMEDOUT;
result = CURLE_OPERATION_TIMEDOUT;
goto out;
}
/* if ssl is expecting something, check if it's available. */
@ -4258,16 +4406,19 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
return CURLE_SSL_CONNECT_ERROR;
result = CURLE_SSL_CONNECT_ERROR;
goto out;
}
if(0 == what) {
if(nonblocking) {
*done = FALSE;
return CURLE_OK;
result = CURLE_OK;
goto out;
}
/* timeout */
failf(data, "SSL connection timeout");
return CURLE_OPERATION_TIMEDOUT;
result = CURLE_OPERATION_TIMEDOUT;
goto out;
}
/* socket is readable or writable */
}
@ -4283,14 +4434,14 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
ssl_connect_2_writing == connssl->connecting_state)))
return result;
goto out;
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
result = ossl_connect_step3(cf, data);
if(result)
return result;
goto out;
}
if(ssl_connect_done == connssl->connecting_state) {
@ -4303,7 +4454,8 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
/* Reset our connect state machine */
connssl->connecting_state = ssl_connect_1;
return CURLE_OK;
out:
return result;
}
static CURLcode ossl_connect_nonblocking(struct Curl_cfilter *cf,
@ -4377,7 +4529,8 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
should be called again later. This is basically an EWOULDBLOCK
equivalent. */
*curlcode = CURLE_AGAIN;
return -1;
rc = -1;
goto out;
case SSL_ERROR_SYSCALL:
{
int sockerr = SOCKERRNO;
@ -4393,7 +4546,8 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
error_buffer, sockerr);
*curlcode = CURLE_SEND_ERROR;
return -1;
rc = -1;
goto out;
}
case SSL_ERROR_SSL: {
/* A failure in the SSL library occurred, usually a protocol error.
@ -4415,17 +4569,21 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
failf(data, "SSL_write() error: %s",
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
*curlcode = CURLE_SEND_ERROR;
return -1;
rc = -1;
goto out;
}
default:
/* a true error */
failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
SSL_ERROR_to_str(err), SOCKERRNO);
*curlcode = CURLE_SEND_ERROR;
return -1;
rc = -1;
goto out;
}
}
*curlcode = CURLE_OK;
out:
return (ssize_t)rc; /* number of bytes */
}
@ -4451,6 +4609,7 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
set_logger(connssl, data);
nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
if(nread <= 0) {
/* failed SSL_read */
int err = SSL_get_error(backend->handle, (int)nread);
@ -4469,7 +4628,8 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
case SSL_ERROR_WANT_WRITE:
/* there's data pending, re-invoke SSL_read() */
*curlcode = CURLE_AGAIN;
return -1;
nread = -1;
goto out;
default:
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
value/errno" */
@ -4490,7 +4650,8 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
error_buffer, sockerr);
*curlcode = CURLE_RECV_ERROR;
return -1;
nread = -1;
goto out;
}
/* For debug builds be a little stricter and error on any
SSL_ERROR_SYSCALL. For example a server may have closed the connection
@ -4513,11 +4674,14 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
" (Fatal because this is a curl debug build)",
error_buffer, sockerr);
*curlcode = CURLE_RECV_ERROR;
return -1;
nread = -1;
goto out;
}
#endif
}
}
out:
return nread;
}

View File

@ -81,26 +81,47 @@ cr_connect(struct Curl_cfilter *cf UNUSED_PARAM,
return CURLE_SSL_CONNECT_ERROR;
}
struct io_ctx {
struct Curl_cfilter *cf;
struct Curl_easy *data;
};
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;
struct io_ctx *io_ctx = userdata;
CURLcode result;
int ret = 0;
ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
(char *)buf, len, &result);
if(nread < 0) {
nread = 0;
if(CURLE_AGAIN == result)
ret = EAGAIN;
else
ret = EINVAL;
}
*out_n = n;
return 0;
*out_n = (int)nread;
return ret;
}
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;
struct io_ctx *io_ctx = userdata;
CURLcode result;
int ret = 0;
ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
(const char *)buf, len, &result);
if(nwritten < 0) {
nwritten = 0;
if(CURLE_AGAIN == result)
ret = EAGAIN;
else
ret = EINVAL;
}
*out_n = n;
return 0;
*out_n = (int)nwritten;
return ret;
}
/*
@ -122,6 +143,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
struct ssl_connect_data *const connssl = cf->ctx;
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
struct io_ctx io_ctx;
size_t n = 0;
size_t tls_bytes_read = 0;
@ -133,10 +155,13 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(backend);
rconn = backend->conn;
io_error = rustls_connection_read_tls(rconn, read_cb,
&cf->conn->sock[cf->sockindex], &tls_bytes_read);
io_ctx.cf = cf;
io_ctx.data = data;
io_error = rustls_connection_read_tls(rconn, read_cb, &io_ctx,
&tls_bytes_read);
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
infof(data, "sread: EAGAIN or EWOULDBLOCK");
infof(data, CFMSG(cf, "cr_recv: EAGAIN or EWOULDBLOCK"));
}
else if(io_error) {
char buffer[STRERROR_LEN];
@ -146,7 +171,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return -1;
}
infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read);
infof(data, CFMSG(cf, "cr_recv: read %ld TLS bytes"), tls_bytes_read);
rresult = rustls_connection_process_new_packets(rconn);
if(rresult != RUSTLS_RESULT_OK) {
@ -164,7 +189,8 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
plainlen - plain_bytes_copied,
&n);
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
infof(data, "cr_recv got PLAINTEXT_EMPTY. will try again later.");
infof(data, CFMSG(cf, "cr_recv: got PLAINTEXT_EMPTY. "
"will try again later."));
backend->data_pending = FALSE;
break;
}
@ -181,7 +207,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
break;
}
else {
infof(data, "cr_recv copied out %ld bytes of plaintext", n);
infof(data, CFMSG(cf, "cr_recv: got %ld plain bytes"), n);
plain_bytes_copied += n;
}
}
@ -222,6 +248,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
struct ssl_connect_data *const connssl = cf->ctx;
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
struct io_ctx io_ctx;
size_t plainwritten = 0;
size_t tlswritten = 0;
size_t tlswritten_total = 0;
@ -231,7 +258,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(backend);
rconn = backend->conn;
infof(data, "cr_send %ld bytes of plaintext", plainlen);
infof(data, CFMSG(cf, "cr_send: %ld plain bytes"), plainlen);
if(plainlen > 0) {
rresult = rustls_connection_write(rconn, plainbuf, plainlen,
@ -248,11 +275,15 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
}
io_ctx.cf = cf;
io_ctx.data = data;
while(rustls_connection_wants_write(rconn)) {
io_error = rustls_connection_write_tls(rconn, write_cb,
&cf->conn->sock[cf->sockindex], &tlswritten);
io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
&tlswritten);
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
infof(data, "swrite: EAGAIN after %ld bytes", tlswritten_total);
infof(data, CFMSG(cf, "cr_send: EAGAIN after %ld bytes"),
tlswritten_total);
*err = CURLE_AGAIN;
return -1;
}
@ -268,7 +299,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
*err = CURLE_WRITE_ERROR;
return -1;
}
infof(data, "cr_send wrote %ld bytes to network", tlswritten);
infof(data, CFMSG(cf, "cr_send: wrote %ld TLS bytes"), tlswritten);
tlswritten_total += tlswritten;
}
@ -606,7 +637,8 @@ static size_t cr_version(char *buffer, size_t size)
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */
SSLSUPP_TLS13_CIPHERSUITES,
SSLSUPP_TLS13_CIPHERSUITES |
SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
Curl_none_init, /* init */

View File

@ -1313,8 +1313,9 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
"sending %lu bytes.", outbuf.cbBuffer));
/* send initial handshake data which is now stored in output buffer */
result = Curl_write_plain(data, cf->conn->sock[cf->sockindex],
outbuf.pvBuffer, outbuf.cbBuffer, &written);
written = Curl_conn_cf_send(cf->next, data,
outbuf.pvBuffer, outbuf.cbBuffer,
&result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send initial handshake data: "
@ -1411,12 +1412,12 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
for(;;) {
if(doread) {
/* read encrypted handshake data from socket */
result = Curl_read_plain(data, cf->conn->sock[cf->sockindex],
nread = Curl_conn_cf_recv(cf->next, data,
(char *) (backend->encdata_buffer +
backend->encdata_offset),
backend->encdata_length -
backend->encdata_offset,
&nread);
&result);
if(result == CURLE_AGAIN) {
if(connssl->connecting_state != ssl_connect_2_writing)
connssl->connecting_state = ssl_connect_2_reading;
@ -1500,9 +1501,9 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
"sending %lu bytes.", outbuf[i].cbBuffer));
/* send handshake token to server */
result = Curl_write_plain(data, cf->conn->sock[cf->sockindex],
outbuf[i].pvBuffer, outbuf[i].cbBuffer,
&written);
written = Curl_conn_cf_send(cf->next, data,
outbuf[i].pvBuffer, outbuf[i].cbBuffer,
&result);
if((result != CURLE_OK) ||
(outbuf[i].cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send next handshake data: "
@ -1964,7 +1965,6 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
ssize_t written = -1;
size_t data_len = 0;
unsigned char *ptr = NULL;
struct connectdata *conn = cf->conn;
struct ssl_connect_data *connssl = cf->ctx;
SecBuffer outbuf[4];
SecBufferDesc outbuf_desc;
@ -2073,8 +2073,9 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
/* socket is writable */
result = Curl_write_plain(data, conn->sock[cf->sockindex],
ptr + written, len - written, &this_write);
this_write = Curl_conn_cf_send(cf->next, data,
ptr + written, len - written,
&result);
if(result == CURLE_AGAIN)
continue;
else if(result != CURLE_OK) {
@ -2185,19 +2186,19 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
backend->encdata_offset, backend->encdata_length));
/* read encrypted data from socket */
*err = Curl_read_plain(data, cf->conn->sock[cf->sockindex],
(char *)(backend->encdata_buffer +
nread = Curl_conn_cf_recv(cf->next, data,
(char *)(backend->encdata_buffer +
backend->encdata_offset),
size, &nread);
size, err);
if(*err) {
nread = -1;
if(*err == CURLE_AGAIN)
DEBUGF(infof(data,
"schannel: Curl_read_plain returned CURLE_AGAIN"));
"schannel: recv returned CURLE_AGAIN"));
else if(*err == CURLE_RECV_ERROR)
infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR");
infof(data, "schannel: recv returned CURLE_RECV_ERROR");
else
infof(data, "schannel: Curl_read_plain returned error %d", *err);
infof(data, "schannel: recv returned error %d", *err);
}
else if(nread == 0) {
backend->recv_connection_closed = true;
@ -2546,11 +2547,9 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
/* send close message which is in output buffer */
ssize_t written;
result = Curl_write_plain(data, cf->conn->sock[cf->sockindex],
outbuf.pvBuffer, outbuf.cbBuffer,
&written);
ssize_t written = Curl_conn_cf_send(cf->next, data,
outbuf.pvBuffer, outbuf.cbBuffer,
&result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
infof(data, "schannel: failed to send close msg: %s"
@ -2767,7 +2766,8 @@ const struct Curl_ssl Curl_ssl_schannel = {
SSLSUPP_CAINFO_BLOB |
#endif
SSLSUPP_PINNEDPUBKEY |
SSLSUPP_TLS13_CIPHERSUITES,
SSLSUPP_TLS13_CIPHERSUITES |
SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),

View File

@ -142,7 +142,6 @@
struct ssl_backend_data {
SSLContextRef ssl_ctx;
curl_socket_t ssl_sockfd;
bool ssl_direction; /* true if writing, false if reading */
size_t ssl_write_buffered_length;
};
@ -825,113 +824,62 @@ static const unsigned char ecDsaSecp384r1SpkiHeader[] = {
#endif /* SECTRANSP_PINNEDPUBKEY_V1 */
#endif /* SECTRANSP_PINNEDPUBKEY */
/* The following two functions were ripped from Apple sample code,
* with some modifications: */
static OSStatus SocketRead(SSLConnectionRef connection,
void *data, /* owned by
* caller, data
* RETURNED */
size_t *dataLength) /* IN/OUT */
static OSStatus bio_cf_in_read(SSLConnectionRef connection,
void *buf,
size_t *dataLength) /* IN/OUT */
{
size_t bytesToGo = *dataLength;
size_t initLen = bytesToGo;
UInt8 *currData = (UInt8 *)data;
struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
int sock;
struct Curl_easy *data = connssl->call_data;
ssize_t nread;
CURLcode result;
OSStatus rtn = noErr;
size_t bytesRead;
ssize_t rrtn;
int theErr;
DEBUGASSERT(backend);
sock = backend->ssl_sockfd;
*dataLength = 0;
for(;;) {
bytesRead = 0;
rrtn = read(sock, currData, bytesToGo);
if(rrtn <= 0) {
/* this is guesswork... */
theErr = errno;
if(rrtn == 0) { /* EOF = server hung up */
/* the framework will turn this into errSSLClosedNoNotify */
rtn = errSSLClosedGraceful;
}
else /* do the switch */
switch(theErr) {
case ENOENT:
/* connection closed */
rtn = errSSLClosedGraceful;
break;
case ECONNRESET:
rtn = errSSLClosedAbort;
break;
case EAGAIN:
rtn = errSSLWouldBlock;
backend->ssl_direction = false;
break;
default:
rtn = ioErr;
break;
}
break;
}
else {
bytesRead = rrtn;
}
bytesToGo -= bytesRead;
currData += bytesRead;
if(bytesToGo == 0) {
/* filled buffer with incoming data, done */
break;
DEBUGASSERT(data);
nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result);
if(nread < 0) {
switch(result) {
case CURLE_OK:
case CURLE_AGAIN:
rtn = errSSLWouldBlock;
backend->ssl_direction = false;
break;
default:
rtn = ioErr;
break;
}
nread = 0;
}
*dataLength = initLen - bytesToGo;
*dataLength = nread;
return rtn;
}
static OSStatus SocketWrite(SSLConnectionRef connection,
const void *data,
size_t *dataLength) /* IN/OUT */
static OSStatus bio_cf_out_write(SSLConnectionRef connection,
const void *buf,
size_t *dataLength) /* IN/OUT */
{
size_t bytesSent = 0;
struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
int sock;
ssize_t length;
size_t dataLen = *dataLength;
const UInt8 *dataPtr = (UInt8 *)data;
OSStatus ortn;
int theErr;
struct Curl_easy *data = connssl->call_data;
ssize_t nwritten;
CURLcode result;
OSStatus ortn = noErr;
DEBUGASSERT(backend);
sock = backend->ssl_sockfd;
*dataLength = 0;
do {
length = write(sock,
(char *)dataPtr + bytesSent,
dataLen - bytesSent);
} while((length > 0) &&
( (bytesSent += length) < dataLen) );
if(length <= 0) {
theErr = errno;
if(theErr == EAGAIN) {
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result);
if(nwritten <= 0) {
if(result == CURLE_AGAIN) {
ortn = errSSLWouldBlock;
backend->ssl_direction = true;
}
else {
ortn = ioErr;
}
nwritten = 0;
}
else {
ortn = noErr;
}
*dataLength = bytesSent;
*dataLength = nwritten;
return ortn;
}
@ -1666,7 +1614,6 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
@ -2132,18 +2079,13 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
}
}
err = SSLSetIOFuncs(backend->ssl_ctx, SocketRead, SocketWrite);
err = SSLSetIOFuncs(backend->ssl_ctx, bio_cf_in_read, bio_cf_out_write);
if(err != noErr) {
failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
}
/* pass the raw socket into the SSL layers */
/* We need to store the FD in a constant memory address, because
* SSLSetConnection() will not copy that address. I've found that
* conn->sock[sockindex] may change on its own. */
backend->ssl_sockfd = sockfd;
err = SSLSetConnection(backend->ssl_ctx, connssl);
err = SSLSetConnection(backend->ssl_ctx, cf);
if(err != noErr) {
failf(data, "SSL: SSLSetConnection() failed: %d", err);
return CURLE_SSL_CONNECT_ERROR;
@ -3185,7 +3127,6 @@ static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
backend->ssl_ctx = NULL;
}
backend->ssl_sockfd = 0;
}
static int sectransp_shutdown(struct Curl_cfilter *cf,
@ -3198,6 +3139,7 @@ static int sectransp_shutdown(struct Curl_cfilter *cf,
int rc;
char buf[120];
int loop = 10; /* avoid getting stuck */
CURLcode result;
DEBUGASSERT(backend);
@ -3231,12 +3173,10 @@ static int sectransp_shutdown(struct Curl_cfilter *cf,
/* Something to read, let's do it and hope that it is the close
notify alert from the server. No way to SSL_Read now, so use read(). */
nread = read(cf->conn->sock[cf->sockindex], buf, sizeof(buf));
nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
if(nread < 0) {
char buffer[STRERROR_LEN];
failf(data, "read: %s",
Curl_strerror(errno, buffer, sizeof(buffer)));
failf(data, "read: %s", curl_easy_strerror(result));
rc = -1;
}
@ -3494,10 +3434,9 @@ const struct Curl_ssl Curl_ssl_sectransp = {
SSLSUPP_CAINFO_BLOB |
SSLSUPP_CERTINFO |
#ifdef SECTRANSP_PINNEDPUBKEY
SSLSUPP_PINNEDPUBKEY,
#else
0,
SSLSUPP_PINNEDPUBKEY |
#endif /* SECTRANSP_PINNEDPUBKEY */
SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
@ -3511,7 +3450,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
Curl_none_cert_status_request, /* cert_status_request */
sectransp_connect, /* connect */
sectransp_connect_nonblocking, /* connect_nonblocking */
Curl_ssl_get_select_socks, /* getsock */
Curl_ssl_get_select_socks, /* getsock */
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */

View File

@ -297,11 +297,12 @@ static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data)
{
struct ssl_connect_data *ctx;
(void)data;
ctx = calloc(1, sizeof(*ctx));
if(!ctx)
return NULL;
ctx->backend = calloc(1, Curl_ssl_get_backend_data_size(data));
ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data);
if(!ctx->backend) {
free(ctx);
return NULL;
@ -317,6 +318,13 @@ static void cf_ctx_free(struct ssl_connect_data *ctx)
}
}
static void cf_ctx_set_data(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
if(cf->ctx)
((struct ssl_connect_data *)cf->ctx)->call_data = data;
}
static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
@ -1467,29 +1475,19 @@ static void reinit_hostname(struct Curl_cfilter *cf)
static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
cf_ctx_set_data(cf, data);
cf_close(cf, data);
cf_ctx_free(cf->ctx);
}
static CURLcode ssl_cf_setup(struct Curl_cfilter *cf,
struct Curl_easy *data,
const struct Curl_dns_entry *remotehost)
{
CURLcode result;
result = cf->next->cft->setup(cf->next, data, remotehost);
if(result)
return result;
/* TODO our setup */
return result;
cf->ctx = NULL;
}
static void ssl_cf_close(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
cf_ctx_set_data(cf, data);
cf_close(cf, data);
cf->next->cft->close(cf->next, data);
cf_ctx_set_data(cf, NULL);
}
static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
@ -1504,6 +1502,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
cf_ctx_set_data(cf, data);
(void)connssl;
DEBUGASSERT(data->conn);
DEBUGASSERT(data->conn == cf->conn);
@ -1512,7 +1511,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
result = cf->next->cft->connect(cf->next, data, blocking, done);
if(result || !*done)
return result;
goto out;
/* TODO: right now we do not fully control when hostname is set,
* assign it on each connect call. */
@ -1533,15 +1532,23 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
DEBUGASSERT(connssl->state == ssl_connection_complete);
}
out:
cf_ctx_set_data(cf, NULL);
return result;
}
static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
bool result;
cf_ctx_set_data(cf, (struct Curl_easy *)data);
if(cf->ctx && Curl_ssl->data_pending(cf, data))
return TRUE;
return cf->next->cft->has_data_pending(cf->next, data);
result = TRUE;
else
result = cf->next->cft->has_data_pending(cf->next, data);
cf_ctx_set_data(cf, NULL);
return result;
}
static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
@ -1551,9 +1558,9 @@ static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
ssize_t nwritten;
*err = CURLE_OK;
cf_ctx_set_data(cf, data);
nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
DEBUGF(infof(data, CFMSG(cf, "send(len=%ld) -> %ld, code=%d"),
len, nwritten, *err));
cf_ctx_set_data(cf, NULL);
return nwritten;
}
@ -1564,9 +1571,9 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
ssize_t nread;
*err = CURLE_OK;
cf_ctx_set_data(cf, data);
nread = Curl_ssl->recv_plain(cf, data, buf, len, err);
DEBUGF(infof(data, CFMSG(cf, "recv -> %ld, code=%d"),
nread, *err));
cf_ctx_set_data(cf, NULL);
return nread;
}
@ -1574,20 +1581,21 @@ static int ssl_cf_get_select_socks(struct Curl_cfilter *cf,
struct Curl_easy *data,
curl_socket_t *socks)
{
/* TODO, this needs to work for other than SOCKETFIRST filters
* and also nested filters. Needs change of implementations.
* What we really want to know if the SSL implementation wants
* to READ or WRITE or needs nothing.
*/
(void)data;
return Curl_ssl->get_select_socks(cf, data, socks);
int result;
cf_ctx_set_data(cf, data);
result = Curl_ssl->get_select_socks(cf, data, socks);
cf_ctx_set_data(cf, NULL);
return result;
}
static void ssl_cf_attach_data(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
if(Curl_ssl->attach_data) {
cf_ctx_set_data(cf, data);
Curl_ssl->attach_data(cf, data);
cf_ctx_set_data(cf, NULL);
}
}
@ -1595,7 +1603,9 @@ static void ssl_cf_detach_data(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
if(Curl_ssl->detach_data) {
cf_ctx_set_data(cf, data);
Curl_ssl->detach_data(cf, data);
cf_ctx_set_data(cf, NULL);
}
}
@ -1603,7 +1613,7 @@ static const struct Curl_cftype cft_ssl = {
"SSL",
CF_TYPE_SSL,
ssl_cf_destroy,
ssl_cf_setup,
Curl_cf_def_setup,
ssl_cf_connect,
ssl_cf_close,
Curl_cf_def_get_host,
@ -1619,7 +1629,7 @@ static const struct Curl_cftype cft_ssl_proxy = {
"SSL-PROXY",
CF_TYPE_SSL,
ssl_cf_destroy,
ssl_cf_setup,
Curl_cf_def_setup,
ssl_cf_connect,
ssl_cf_close,
Curl_cf_def_get_host,
@ -1691,12 +1701,6 @@ out:
#endif /* !CURL_DISABLE_PROXY */
size_t Curl_ssl_get_backend_data_size(struct Curl_easy *data)
{
(void)data;
return Curl_ssl->sizeof_ssl_backend_data;
}
bool Curl_ssl_supports(struct Curl_easy *data, int option)
{
(void)data;
@ -1706,15 +1710,19 @@ bool Curl_ssl_supports(struct Curl_easy *data, int option)
void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
CURLINFO info, int n)
{
void *result = NULL;
(void)n;
if(data->conn) {
struct Curl_cfilter *cf;
/* get first filter in chain, if any is present */
cf = Curl_ssl_cf_get_ssl(data->conn->cfilter[sockindex]);
if(cf)
return Curl_ssl->get_internals(cf->ctx, info);
if(cf) {
cf_ctx_set_data(cf, data);
result = Curl_ssl->get_internals(cf->ctx, info);
cf_ctx_set_data(cf, NULL);
}
}
return NULL;
return result;
}
bool Curl_ssl_use(struct connectdata *conn, int sockindex)
@ -1722,22 +1730,6 @@ bool Curl_ssl_use(struct connectdata *conn, int sockindex)
return Curl_ssl_cf_get_ssl(conn->cfilter[sockindex]) != NULL;
}
bool Curl_ssl_conn_is_ssl(struct Curl_easy *data,
int sockindex)
{
struct Curl_cfilter *cf = data->conn? data->conn->cfilter[sockindex] : NULL;
/* TODO: this is an inomplete check. We might skip filters here that
* tunnel/transform and only use SSL for part of the connection.
*/
(void)data;
for(; cf; cf = cf->next) {
if(cf->cft == &cft_ssl)
return TRUE;
}
return FALSE;
}
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
int sockindex)
{

View File

@ -165,14 +165,6 @@ CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data,
int sockindex);
#endif /* !CURL_DISABLE_PROXY */
/**
* Return TRUE iff the filter chain `sockindex` at connection `conn`
* is using/prepared for SSL encryption. This tests the presence of the
* necessary filters and not their connectedness.
*/
bool Curl_ssl_conn_is_ssl(struct Curl_easy *data,
int sockindex);
/**
* Get the SSL configuration that is used on the connection.
* This returns NULL if no SSL is configured.
@ -216,8 +208,6 @@ bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option);
void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
CURLINFO info, int n);
size_t Curl_ssl_get_backend_data_size(struct Curl_easy *data);
bool Curl_ssl_use(struct connectdata *conn, int sockindex);
#else /* if not USE_SSL */
@ -238,9 +228,7 @@ bool Curl_ssl_use(struct connectdata *conn, int sockindex);
#define Curl_ssl_false_start(a) FALSE
#define Curl_ssl_get_internals(a,b,c,d) NULL
#define Curl_ssl_supports(a,b) FALSE
#define Curl_ssl_get_backend_data_size(a) 0
#define Curl_ssl_use(a,b) FALSE
#define Curl_ssl_conn_is_ssl(a,b) FALSE
#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
#define Curl_ssl_cfilter_proxy_add(a,b,c) CURLE_NOT_BUILT_IN
#define Curl_ssl_get_config(a,b) NULL

View File

@ -33,10 +33,15 @@
struct ssl_connect_data {
ssl_connection_state state;
ssl_connect_state connecting_state;
const char *hostname;
const char *dispname;
int port;
struct ssl_backend_data *backend;
const char *hostname; /* hostnaem for verification */
const char *dispname; /* display version of hostname */
int port; /* remote port at origin */
struct ssl_backend_data *backend; /* vtls backend specific props */
struct Curl_easy *call_data; /* data handle used in current call,
* same as paramter passed, but available
* here for backend internal callbacks
* that need it. NULLed after at the
* end of each vtls filter invcocation. */
};

View File

@ -85,9 +85,16 @@
#endif
#endif
#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
#define USE_BIO_CHAIN
#else
#undef USE_BIO_CHAIN
#endif
struct ssl_backend_data {
SSL_CTX* ctx;
SSL* handle;
CURLcode io_result;
};
#ifdef OPENSSL_EXTRA
@ -239,6 +246,139 @@ static const struct group_name_map gnm[] = {
};
#endif
#ifdef USE_BIO_CHAIN
static int bio_cf_create(WOLFSSL_BIO *bio)
{
wolfSSL_BIO_set_shutdown(bio, 1);
wolfSSL_BIO_set_init(bio, 1);
wolfSSL_BIO_set_data(bio, NULL);
return 1;
}
static int bio_cf_destroy(WOLFSSL_BIO *bio)
{
if(!bio)
return 0;
return 1;
}
static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
long ret = 1;
(void)cf;
(void)ptr;
switch(cmd) {
case BIO_CTRL_GET_CLOSE:
ret = (long)wolfSSL_BIO_get_shutdown(bio);
break;
case BIO_CTRL_SET_CLOSE:
wolfSSL_BIO_set_shutdown(bio, (int)num);
break;
case BIO_CTRL_FLUSH:
/* we do no delayed writes, but if we ever would, this
* needs to trigger it. */
ret = 1;
break;
case BIO_CTRL_DUP:
ret = 1;
break;
#ifdef BIO_CTRL_EOF
case BIO_CTRL_EOF:
/* EOF has been reached on input? */
return (!cf->next || !cf->next->connected);
#endif
default:
ret = 0;
break;
}
return ret;
}
static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
struct Curl_easy *data = connssl->call_data;
ssize_t nwritten;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
wolfSSL_BIO_clear_retry_flags(bio);
/* wolfSSL is limited in error handling and SSL_read() will
* return WANT_READ, even though retry was not indicated by
* the installed BIO. */
connssl->backend->io_result = result;
if(nwritten < 0) {
if(CURLE_AGAIN == result) {
BIO_set_retry_read(bio);
nwritten = 0;
}
else {
nwritten = -1;
}
}
return (int)nwritten;
}
static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
struct Curl_easy *data = connssl->call_data;
ssize_t nread;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
/* OpenSSL catches this case, so should we. */
if(!buf)
return 0;
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
wolfSSL_BIO_clear_retry_flags(bio);
/* wolfSSL is limited in error handling and SSL_read() will
* return WANT_READ, even though retry was not indicated by
* the installed BIO. */
connssl->backend->io_result = result;
if(nread < 0) {
if(CURLE_AGAIN == result) {
BIO_set_retry_read(bio);
nread = 0;
}
else {
nread = -1;
}
}
return (int)nread;
}
static WOLFSSL_BIO_METHOD *bio_cf_method = NULL;
static void bio_cf_init_methods(void)
{
bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
wolfSSL_BIO_meth_set_write(bio_cf_method, &bio_cf_out_write);
wolfSSL_BIO_meth_set_read(bio_cf_method, &bio_cf_in_read);
wolfSSL_BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl);
wolfSSL_BIO_meth_set_create(bio_cf_method, &bio_cf_create);
wolfSSL_BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy);
}
static void bio_cf_free_methods(void)
{
wolfSSL_BIO_meth_free(bio_cf_method);
}
#else /* USE_BIO_CHAIN */
#define bio_cf_init_methods() Curl_nop_stmt
#define bio_cf_free_methods() Curl_nop_stmt
#endif /* !USE_BIO_CHAIN */
/*
* This function loads all the client/CA certificates and CRLs. Setup the TLS
* layer and do all necessary magic.
@ -252,7 +392,6 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
SSL_METHOD* req_method = NULL;
curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
#ifdef HAVE_LIBOQS
word16 oqsAlg = 0;
size_t idx = 0;
@ -578,11 +717,24 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
Curl_ssl_sessionid_unlock(data);
}
#ifdef USE_BIO_CHAIN
{
WOLFSSL_BIO *bio;
bio = BIO_new(bio_cf_method);
if(!bio)
return CURLE_OUT_OF_MEMORY;
wolfSSL_BIO_set_data(bio, cf);
wolfSSL_set_bio(backend->handle, bio, bio);
}
#else /* USE_BIO_CHAIN */
/* pass the raw socket into the SSL layer */
if(!SSL_set_fd(backend->handle, (int)sockfd)) {
if(!SSL_set_fd(backend->handle, (int)cf->conn->sock[cf->sockindex])) {
failf(data, "SSL: SSL_set_fd failed");
return CURLE_SSL_CONNECT_ERROR;
}
#endif /* !USE_BIO_CHAIN */
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
@ -642,7 +794,10 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
int detail = SSL_get_error(backend->handle, ret);
if(SSL_ERROR_WANT_READ == detail) {
if(backend->io_result != CURLE_OK && backend->io_result != CURLE_AGAIN) {
return backend->io_result;
}
else if(SSL_ERROR_WANT_READ == detail) {
connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
@ -870,6 +1025,10 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
if(rc <= 0) {
int err = SSL_get_error(backend->handle, rc);
if(backend->io_result != CURLE_OK && backend->io_result != CURLE_AGAIN) {
*curlcode = backend->io_result;
return -1;
}
switch(err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
@ -932,6 +1091,10 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
if(nread <= 0) {
int err = SSL_get_error(backend->handle, nread);
if(backend->io_result != CURLE_OK && backend->io_result != CURLE_AGAIN) {
*curlcode = backend->io_result;
return -1;
}
switch(err) {
case SSL_ERROR_ZERO_RETURN: /* no more data */
break;
@ -972,15 +1135,20 @@ static size_t wolfssl_version(char *buffer, size_t size)
static int wolfssl_init(void)
{
int ret;
#ifdef OPENSSL_EXTRA
Curl_tls_keylog_open();
#endif
return (wolfSSL_Init() == SSL_SUCCESS);
ret = (wolfSSL_Init() == SSL_SUCCESS);
bio_cf_init_methods();
return ret;
}
static void wolfssl_cleanup(void)
{
bio_cf_free_methods();
wolfSSL_Cleanup();
#ifdef OPENSSL_EXTRA
Curl_tls_keylog_close();
@ -1200,6 +1368,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#ifdef KEEP_PEER_CERT
SSLSUPP_PINNEDPUBKEY |
#endif
#ifdef USE_BIO_CHAIN
SSLSUPP_HTTPS_PROXY |
#endif
SSLSUPP_SSL_CTX,

View File

@ -143,6 +143,15 @@ if test "x$OPT_WOLFSSL" != xno; then
]
)
dnl if this symbol is present, we can make use of BIO filter chains
AC_CHECK_FUNC(wolfSSL_BIO_set_shutdown,
[
AC_DEFINE(HAVE_WOLFSSL_FULL_BIO, 1,
[if you have wolfSSL_BIO_set_shutdown])
WOLFSSL_FULL_BIO=1
]
)
if test -n "$wolfssllibpath"; then
dnl when shared libs were found in a path that the run-time
dnl linker doesn't search through, we need to add it to