gnutls: finished support for HTTPS proxies.

This commit is contained in:
Alex Rousskov
2015-11-05 08:53:29 -07:00
committed by Daniel Stenberg
parent 043c5f5c33
commit 127a7b0257
4 changed files with 85 additions and 44 deletions

View File

@@ -4767,6 +4767,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
long port = -1; long port = -1;
char *proxyuser = NULL; char *proxyuser = NULL;
char *proxypasswd = NULL; char *proxypasswd = NULL;
bool sockstype;
/* We do the proxy host string parsing here. We want the host name and the /* We do the proxy host string parsing here. We want the host name and the
* port name. Accept a protocol:// prefix * port name. Accept a protocol:// prefix
@@ -4791,10 +4792,10 @@ static CURLcode parse_proxy(struct SessionHandle *data,
else else
proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */ proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */
bool sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME || sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
proxytype == CURLPROXY_SOCKS5 || proxytype == CURLPROXY_SOCKS5 ||
proxytype == CURLPROXY_SOCKS4A || proxytype == CURLPROXY_SOCKS4A ||
proxytype == CURLPROXY_SOCKS4; proxytype == CURLPROXY_SOCKS4;
/* Is there a username and password given in this proxy url? */ /* Is there a username and password given in this proxy url? */
atsign = strchr(proxyptr, '@'); atsign = strchr(proxyptr, '@');

View File

@@ -170,6 +170,16 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
return ret; return ret;
} }
static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len)
{
return gnutls_record_send((gnutls_session_t) s, buf, len);
}
static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len)
{
return gnutls_record_recv((gnutls_session_t) s, buf, len);
}
/* Curl_gtls_init() /* Curl_gtls_init()
* *
* Global GnuTLS init, called from Curl_ssl_init(). This calls functions that * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
@@ -372,6 +382,9 @@ gtls_connect_step1(struct connectdata *conn,
void *ssl_sessionid; void *ssl_sessionid;
size_t ssl_idsize; size_t ssl_idsize;
bool sni = TRUE; /* default is SNI enabled */ bool sni = TRUE; /* default is SNI enabled */
void *transport_ptr = NULL;
gnutls_push_func gnutls_transport_push = NULL;
gnutls_pull_func gnutls_transport_pull = NULL;
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
struct in6_addr addr; struct in6_addr addr;
#else #else
@@ -429,8 +442,8 @@ gtls_connect_step1(struct connectdata *conn,
} }
#ifdef USE_TLS_SRP #ifdef USE_TLS_SRP
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
rc = gnutls_srp_allocate_client_credentials( rc = gnutls_srp_allocate_client_credentials(
&conn->ssl[sockindex].srp_client_cred); &conn->ssl[sockindex].srp_client_cred);
@@ -442,8 +455,8 @@ gtls_connect_step1(struct connectdata *conn,
rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex]. rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
srp_client_cred, srp_client_cred,
data->set.ssl.username, SSL_SET_OPTION(username),
data->set.ssl.password); SSL_SET_OPTION(password));
if(rc != GNUTLS_E_SUCCESS) { if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_srp_set_client_cred() failed: %s", failf(data, "gnutls_srp_set_client_cred() failed: %s",
gnutls_strerror(rc)); gnutls_strerror(rc));
@@ -489,19 +502,19 @@ gtls_connect_step1(struct connectdata *conn,
} }
#endif #endif
if(data->set.ssl.CRLfile) { if(SSL_SET_OPTION(CRLfile)) {
/* set the CRL list file */ /* set the CRL list file */
rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
data->set.ssl.CRLfile, SSL_SET_OPTION(CRLfile),
GNUTLS_X509_FMT_PEM); GNUTLS_X509_FMT_PEM);
if(rc < 0) { if(rc < 0) {
failf(data, "error reading crl file %s (%s)", failf(data, "error reading crl file %s (%s)",
data->set.ssl.CRLfile, gnutls_strerror(rc)); SSL_SET_OPTION(CRLfile), gnutls_strerror(rc));
return CURLE_SSL_CRL_BADFILE; return CURLE_SSL_CRL_BADFILE;
} }
else else
infof(data, "found %d CRL in %s\n", infof(data, "found %d CRL in %s\n",
rc, data->set.ssl.CRLfile); rc, SSL_SET_OPTION(CRLfile));
} }
/* Initialize TLS session as a client */ /* Initialize TLS session as a client */
@@ -541,7 +554,7 @@ gtls_connect_step1(struct connectdata *conn,
if(rc != GNUTLS_E_SUCCESS) if(rc != GNUTLS_E_SUCCESS)
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
if(data->set.ssl.cipher_list != NULL) { if(SSL_CONN_CONFIG(cipher_list) != NULL) {
failf(data, "can't pass a custom cipher list to older GnuTLS" failf(data, "can't pass a custom cipher list to older GnuTLS"
" versions"); " versions");
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
@@ -657,13 +670,13 @@ gtls_connect_step1(struct connectdata *conn,
} }
#endif #endif
if(data->set.ssl.cert) { if(SSL_SET_OPTION(cert)) {
if(gnutls_certificate_set_x509_key_file( if(gnutls_certificate_set_x509_key_file(
conn->ssl[sockindex].cred, conn->ssl[sockindex].cred,
data->set.ssl.cert, SSL_SET_OPTION(cert),
data->set.ssl.key ? SSL_SET_OPTION(key) ?
data->set.ssl.key : data->set.ssl.cert, SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
do_file_type(data->set.ssl.cert_type) ) != do_file_type(SSL_SET_OPTION(cert_type)) ) !=
GNUTLS_E_SUCCESS) { GNUTLS_E_SUCCESS) {
failf(data, "error reading X.509 key or certificate file"); failf(data, "error reading X.509 key or certificate file");
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
@@ -672,7 +685,7 @@ gtls_connect_step1(struct connectdata *conn,
#ifdef USE_TLS_SRP #ifdef USE_TLS_SRP
/* put the credentials to the current session */ /* put the credentials to the current session */
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
conn->ssl[sockindex].srp_client_cred); conn->ssl[sockindex].srp_client_cred);
if(rc != GNUTLS_E_SUCCESS) { if(rc != GNUTLS_E_SUCCESS) {
@@ -691,13 +704,24 @@ gtls_connect_step1(struct connectdata *conn,
} }
} }
/* set the connection handle (file descriptor for the socket) */ if(conn->proxy_ssl[sockindex].use) {
gnutls_transport_set_ptr(session, transport_ptr = conn->proxy_ssl[sockindex].session;
GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex])); gnutls_transport_push = Curl_gtls_push_ssl;
gnutls_transport_pull = Curl_gtls_pull_ssl;
}
else {
/* file descriptor for the socket */
transport_ptr = GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]);
gnutls_transport_push = Curl_gtls_push;
gnutls_transport_pull = Curl_gtls_pull;
}
/* set the connection handle */
gnutls_transport_set_ptr(session, transport_ptr);
/* register callback functions to send and receive data. */ /* register callback functions to send and receive data. */
gnutls_transport_set_push_function(session, Curl_gtls_push); gnutls_transport_set_push_function(session, gnutls_transport_push);
gnutls_transport_set_pull_function(session, Curl_gtls_pull); gnutls_transport_set_pull_function(session, gnutls_transport_pull);
/* lowat must be set to zero when using custom push and pull functions. */ /* lowat must be set to zero when using custom push and pull functions. */
gnutls_transport_set_lowat(session, 0); gnutls_transport_set_lowat(session, 0);
@@ -833,8 +857,8 @@ gtls_connect_step3(struct connectdata *conn,
SSL_CONN_CONFIG(verifyhost) || SSL_CONN_CONFIG(verifyhost) ||
data->set.ssl.issuercert) { data->set.ssl.issuercert) {
#ifdef USE_TLS_SRP #ifdef USE_TLS_SRP
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
&& data->set.ssl.username != NULL && SSL_SET_OPTION(username) != NULL
&& !SSL_CONN_CONFIG(verifypeer) && !SSL_CONN_CONFIG(verifypeer)
&& gnutls_cipher_get(session)) { && gnutls_cipher_get(session)) {
/* no peer cert, but auth is ok if we have SRP user and cipher and no /* no peer cert, but auth is ok if we have SRP user and cipher and no
@@ -888,7 +912,7 @@ gtls_connect_step3(struct connectdata *conn,
failf(data, "server certificate verification failed. CAfile: %s " failf(data, "server certificate verification failed. CAfile: %s "
"CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
"none", "none",
data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none"); SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none");
return CURLE_SSL_CACERT; return CURLE_SSL_CACERT;
} }
else else
@@ -1344,6 +1368,20 @@ Curl_gtls_connect(struct connectdata *conn,
return CURLE_OK; return CURLE_OK;
} }
bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex)
{
bool res = FALSE;
if(conn->ssl[connindex].session &&
0 != gnutls_record_check_pending(conn->ssl[connindex].session))
res = TRUE;
if(conn->proxy_ssl[connindex].session &&
0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session))
res = TRUE;
return res;
}
static ssize_t gtls_send(struct connectdata *conn, static ssize_t gtls_send(struct connectdata *conn,
int sockindex, int sockindex,
const void *mem, const void *mem,
@@ -1363,29 +1401,29 @@ static ssize_t gtls_send(struct connectdata *conn,
return rc; return rc;
} }
static void close_one(struct connectdata *conn, static void close_one(struct ssl_connect_data *ssl)
int idx)
{ {
if(conn->ssl[idx].session) { if(ssl->session) {
gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR); gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR);
gnutls_deinit(conn->ssl[idx].session); gnutls_deinit(ssl->session);
conn->ssl[idx].session = NULL; ssl->session = NULL;
} }
if(conn->ssl[idx].cred) { if(ssl->cred) {
gnutls_certificate_free_credentials(conn->ssl[idx].cred); gnutls_certificate_free_credentials(ssl->cred);
conn->ssl[idx].cred = NULL; ssl->cred = NULL;
} }
#ifdef USE_TLS_SRP #ifdef USE_TLS_SRP
if(conn->ssl[idx].srp_client_cred) { if(ssl->srp_client_cred) {
gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred); gnutls_srp_free_client_credentials(ssl->srp_client_cred);
conn->ssl[idx].srp_client_cred = NULL; ssl->srp_client_cred = NULL;
} }
#endif #endif
} }
void Curl_gtls_close(struct connectdata *conn, int sockindex) void Curl_gtls_close(struct connectdata *conn, int sockindex)
{ {
close_one(conn, sockindex); close_one(&conn->ssl[sockindex]);
close_one(&conn->proxy_ssl[sockindex]);
} }
/* /*
@@ -1451,8 +1489,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
#ifdef USE_TLS_SRP #ifdef USE_TLS_SRP
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
&& data->set.ssl.username != NULL) && SSL_SET_OPTION(username) != NULL)
gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred); gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
#endif #endif

View File

@@ -34,6 +34,8 @@ CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
int sockindex, int sockindex,
bool *done); bool *done);
bool Curl_gtls_data_pending(const struct connectdata *conn,
int connindex);
/* close a SSL connection */ /* close a SSL connection */
void Curl_gtls_close(struct connectdata *conn, int sockindex); void Curl_gtls_close(struct connectdata *conn, int sockindex);
@@ -74,7 +76,7 @@ bool Curl_gtls_cert_status_request(void);
#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) #define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
#define curlssl_version Curl_gtls_version #define curlssl_version Curl_gtls_version
#define curlssl_check_cxn(x) ((void)x, -1) #define curlssl_check_cxn(x) ((void)x, -1)
#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) #define curlssl_data_pending(x,y) Curl_gtls_data_pending(x,y)
#define curlssl_random(x,y,z) Curl_gtls_random(x,y,z) #define curlssl_random(x,y,z) Curl_gtls_random(x,y,z)
#define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d) #define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d)
#define curlssl_cert_status_request() Curl_gtls_cert_status_request() #define curlssl_cert_status_request() Curl_gtls_cert_status_request()

View File

@@ -308,7 +308,7 @@ ssl_connect_init_proxy(struct connectdata *conn, int sockindex) {
DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]); DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
if(ssl_connection_complete == conn->ssl[sockindex].state && if(ssl_connection_complete == conn->ssl[sockindex].state &&
!conn->proxy_ssl[sockindex].use) { !conn->proxy_ssl[sockindex].use) {
#if defined(USE_OPENSSL) || defined(USE_NSS) #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_NSS)
conn->proxy_ssl[sockindex] = conn->ssl[sockindex]; conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex])); memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
#else #else