summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--configure.ac13
-rw-r--r--lib/cfilters.c31
-rw-r--r--lib/cfilters.h115
-rw-r--r--lib/connect.c10
-rw-r--r--lib/ftp.c2
-rw-r--r--lib/http_proxy.c8
-rw-r--r--lib/imap.c2
-rw-r--r--lib/pop3.c2
-rw-r--r--lib/smtp.c2
-rw-r--r--lib/vtls/bearssl.c26
-rw-r--r--lib/vtls/gtls.c97
-rw-r--r--lib/vtls/mbedtls.c50
-rw-r--r--lib/vtls/openssl.c270
-rw-r--r--lib/vtls/rustls.c76
-rw-r--r--lib/vtls/schannel.c44
-rw-r--r--lib/vtls/sectransp.c151
-rw-r--r--lib/vtls/vtls.c104
-rw-r--r--lib/vtls/vtls.h12
-rw-r--r--lib/vtls/vtls_int.h13
-rw-r--r--lib/vtls/wolfssl.c179
-rw-r--r--m4/curl-wolfssl.m49
22 files changed, 796 insertions, 425 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 13aff5f4b..ce03d4bda 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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))
diff --git a/configure.ac b/configure.ac
index 8f161254b..bfbf828f0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/lib/cfilters.c b/lib/cfilters.c
index 2d04390c1..bcb33da77 100644
--- a/lib/cfilters.c
+++ b/lib/cfilters.c
@@ -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;
diff --git a/lib/cfilters.h b/lib/cfilters.h
index c339e4651..4b81b42e6 100644
--- a/lib/cfilters.h
+++ b/lib/cfilters.h
@@ -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 bool Curl_cf_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_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 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 int Curl_cft_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks);
+
+typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data);
+
+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_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_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
@@ -238,6 +244,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.
*/
diff --git a/lib/connect.c b/lib/connect.c
index 9ec664ef5..6cb945971 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -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);
}
diff --git a/lib/ftp.c b/lib/ftp.c
index c07bafe17..8f0ac2e69 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -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 */
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index 0519c8ea8..e30730aca 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -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;
}
diff --git a/lib/imap.c b/lib/imap.c
index a462ff042..95689c9d1 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -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;
diff --git a/lib/pop3.c b/lib/pop3.c
index e94d7e5cb..c5ad07aa0 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -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;
diff --git a/lib/smtp.c b/lib/smtp.c
index 085faf9e3..1c29fab37 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -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;
diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c
index 3ec8c0acd..d9c0ce0ee 100644
--- a/lib/vtls/bearssl.c
+++ b/lib/vtls/bearssl.c
@@ -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 */
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index 787d04a6b..b55b707d1 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -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;
-static ssize_t gtls_pull(void *s, void *buf, size_t len)
-{
- curl_socket_t sock = *(curl_socket_t *)s;
- ssize_t ret = sread(sock, buf, len);
- return ret;
+ 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_push_ssl(void *s, const void *buf, size_t len)
+static ssize_t gtls_pull(void *s, void *buf, size_t blen)
{
- return gnutls_record_send((gnutls_session_t) s, buf, len);
-}
+ 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_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;
}
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
index f919a842e..e131ac06c 100644
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
@@ -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),
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index a6bd294de..8d93d41e2 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -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;
}
diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c
index 36cc08207..27f4ec8d8 100644
--- a/lib/vtls/rustls.c
+++ b/lib/vtls/rustls.c
@@ -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 */
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index ef9a66382..7eab9542a 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -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),
diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c
index 78076f623..ab7965465 100644
--- a/lib/vtls/sectransp.c
+++ b/lib/vtls/sectransp.c
@@ -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;
-
- DEBUGASSERT(backend);
- sock = backend->ssl_sockfd;
- *dataLength = 0;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result;
+ OSStatus ortn = noErr;
- 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 */
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index 197624632..303efc39d 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -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)
{
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index a3601babd..ca7a96096 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -166,14 +166,6 @@ CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data,
#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.
* Otherwise it returns the config of the first (highest) one that is
@@ -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
diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h
index 90d737d7f..e2dc34f1d 100644
--- a/lib/vtls/vtls_int.h
+++ b/lib/vtls/vtls_int.h
@@ -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. */
};
diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c
index a622d63d8..aaac828ab 100644
--- a/lib/vtls/wolfssl.c
+++ b/lib/vtls/wolfssl.c
@@ -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();
@@ -1201,6 +1369,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,
sizeof(struct ssl_backend_data),
diff --git a/m4/curl-wolfssl.m4 b/m4/curl-wolfssl.m4
index d66c97935..0872bcb78 100644
--- a/m4/curl-wolfssl.m4
+++ b/m4/curl-wolfssl.m4
@@ -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