mirror of
https://github.com/curl/curl.git
synced 2025-04-12 16:20:35 +08:00
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:
parent
dbd74baf78
commit
55807e6c05
@ -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))
|
||||
|
13
configure.ac
13
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
|
||||
|
@ -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;
|
||||
|
107
lib/cfilters.h
107
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 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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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),
|
||||
|
||||
|
@ -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 */
|
||||
|
104
lib/vtls/vtls.c
104
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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
};
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user