Skip to content

Commit

Permalink
TLS backends using connection filters for IO, enabling HTTPS-proxy.
Browse files Browse the repository at this point in the history
            - OpenSSL (and compatible)
            - BearSSL
            - gnutls
            - mbedtls
            - rustls
            - schannel
            - secure-transport
            - wolfSSL (v5.0.0 and newer)

            This leaves the only the following without HTTPS-proxy support:
            - gskit
            - nss
            - wolfSSL (versions earlier than v5.0.0)
  • Loading branch information
icing committed Nov 28, 2022
1 parent eb559c8 commit 38f391f
Show file tree
Hide file tree
Showing 22 changed files with 796 additions and 425 deletions.
5 changes: 4 additions & 1 deletion CMakeLists.txt
Expand Up @@ -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))
Expand Down
13 changes: 11 additions & 2 deletions configure.ac
Expand Up @@ -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
Expand Down
31 changes: 27 additions & 4 deletions lib/cfilters.c
Expand Up @@ -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;
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
115 changes: 64 additions & 51 deletions lib/cfilters.h
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
10 changes: 0 additions & 10 deletions lib/connect.c
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/ftp.c
Expand Up @@ -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 */
Expand Down
8 changes: 0 additions & 8 deletions lib/http_proxy.c
Expand Up @@ -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:
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -1098,8 +1092,6 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
cf->connected = TRUE;
tunnel_free(cf, data);
}
DEBUGF(infof(data, CFMSG(cf, "connect(block=%d) -> %d, done=%d"),
blocking, result, *done));
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/imap.c
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion lib/pop3.c
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion lib/smtp.c
Expand Up @@ -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;
Expand Down

0 comments on commit 38f391f

Please sign in to comment.