gtls: initial work to support HTTPS proxy

This commit is contained in:
Daniel Stenberg 2015-07-01 01:12:57 +02:00
parent 1c5997ae9d
commit cd2644fe2c

View File

@ -402,6 +402,9 @@ gtls_connect_step1(struct connectdata *conn,
const char *err = NULL;
#endif
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
if(conn->ssl[sockindex].state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
same connection */
@ -411,11 +414,11 @@ gtls_connect_step1(struct connectdata *conn,
Curl_gtls_init();
/* GnuTLS only supports SSLv3 and TLSv1 */
if(conn->ssl_config.version == CURL_SSLVERSION_SSLv2) {
if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
}
else if(conn->ssl_config.version == CURL_SSLVERSION_SSLv3)
else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)
sni = FALSE; /* SSLv3 has no SNI */
/* allocate a cred struct */
@ -449,40 +452,40 @@ gtls_connect_step1(struct connectdata *conn,
}
#endif
if(conn->ssl_config.CAfile) {
if(SSL_CONN_CONFIG(CAfile)) {
/* set the trusted CA cert bundle file */
gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
conn->ssl_config.CAfile,
SSL_CONN_CONFIG(CAfile),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)\n",
conn->ssl_config.CAfile, gnutls_strerror(rc));
if(conn->ssl_config.verifypeer)
SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
if(SSL_CONN_CONFIG(verifypeer))
return CURLE_SSL_CACERT_BADFILE;
}
else
infof(data, "found %d certificates in %s\n",
rc, conn->ssl_config.CAfile);
infof(data, "found %d certificates in %s\n", rc,
SSL_CONN_CONFIG(CAfile));
}
#ifdef HAS_CAPATH
if(conn->ssl_config.CApath) {
if(SSL_CONN_CONFIG(CApath)) {
/* set the trusted CA cert directory */
rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred,
conn->ssl_config.CApath,
SSL_CONN_CONFIG(CApath),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)\n",
conn->ssl_config.CApath, gnutls_strerror(rc));
if(data->set.ssl.primary.verifypeer)
SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
if(SSL_CONN_CONFIG(verifypeer))
return CURLE_SSL_CACERT_BADFILE;
}
else
infof(data, "found %d certificates in %s\n",
rc, conn->ssl_config.CApath);
rc, SSL_CONN_CONFIG(CApath));
}
#endif
@ -511,13 +514,13 @@ gtls_connect_step1(struct connectdata *conn,
/* convenient assign */
session = conn->ssl[sockindex].session;
if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
#ifdef ENABLE_IPV6
(0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
#endif
sni &&
(gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
strlen(conn->host.name)) < 0))
(gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
strlen(hostname)) < 0))
infof(data, "WARNING: failed to configure server name indication (SNI) "
"TLS extension\n");
@ -544,7 +547,7 @@ gtls_connect_step1(struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
switch (conn->ssl_config.version) {
switch (SSL_CONN_CONFIG(version) {
case CURL_SSLVERSION_SSLv3:
protocol_priority[0] = GNUTLS_SSL3;
break;
@ -579,7 +582,7 @@ gtls_connect_step1(struct connectdata *conn,
/* Ensure +SRP comes at the *end* of all relevant strings so that it can be
* removed if a run-time error indicates that SRP is not supported by this
* GnuTLS version */
switch (conn->ssl_config.version) {
switch (SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_SSLv3:
prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
sni = false;
@ -700,7 +703,7 @@ gtls_connect_step1(struct connectdata *conn,
gnutls_transport_set_lowat(session, 0);
#ifdef HAS_OCSP
if(data->set.ssl.primary.verifystatus) {
if(SSL_CONN_CONFIG(verifystatus)) {
rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
@ -806,8 +809,9 @@ gtls_connect_step3(struct connectdata *conn,
gnutls_datum_t proto;
#endif
CURLcode result = CURLE_OK;
gnutls_protocol_t version = gnutls_protocol_get_version(session);
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
/* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
@ -825,13 +829,13 @@ gtls_connect_step3(struct connectdata *conn,
chainp = gnutls_certificate_get_peers(session, &cert_list_size);
if(!chainp) {
if(conn->ssl_config.verifypeer ||
conn->ssl_config.verifyhost ||
if(SSL_CONN_CONFIG(verifypeer) ||
SSL_CONN_CONFIG(verifyhost) ||
data->set.ssl.issuercert) {
#ifdef USE_TLS_SRP
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
&& data->set.ssl.username != NULL
&& !conn->ssl_config.verifypeer
&& !SSL_CONN_CONFIG(verifypeer)
&& gnutls_cipher_get(session)) {
/* no peer cert, but auth is ok if we have SRP user and cipher and no
peer verify */
@ -864,7 +868,7 @@ gtls_connect_step3(struct connectdata *conn,
}
}
if(conn->ssl_config.verifypeer) {
if(SSL_CONN_CONFIG(verifypeer)) {
/* This function will try to verify the peer's certificate and return its
status (trusted, invalid etc.). The value of status should be one or
more of the gnutls_certificate_status_t enumerated elements bitwise
@ -880,10 +884,10 @@ gtls_connect_step3(struct connectdata *conn,
/* verify_status is a bitmask of gnutls_certificate_status bits */
if(verify_status & GNUTLS_CERT_INVALID) {
if(conn->ssl_config.verifypeer) {
if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server certificate verification failed. CAfile: %s "
"CRLfile: %s", conn->ssl_config.CAfile ? conn->ssl_config.CAfile:
"none",
"CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
"none",
data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
return CURLE_SSL_CACERT;
}
@ -897,7 +901,7 @@ gtls_connect_step3(struct connectdata *conn,
infof(data, "\t server certificate verification SKIPPED\n");
#ifdef HAS_OCSP
if(data->set.ssl.primary.verifystatus) {
if(SSL_CONN_CONFIG(verifystatus)) {
if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
gnutls_datum_t status_request;
gnutls_ocsp_resp_t ocsp_resp;
@ -1042,7 +1046,7 @@ gtls_connect_step3(struct connectdata *conn,
in RFC2818 (HTTPS), which takes into account wildcards, and the subject
alternative name PKIX extension. Returns non zero on success, and zero on
failure. */
rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
rc = gnutls_x509_crt_check_hostname(x509_cert, hostname);
#if GNUTLS_VERSION_NUMBER < 0x030306
/* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
addresses. */
@ -1058,10 +1062,10 @@ gtls_connect_step3(struct connectdata *conn,
int i;
int ret = 0;
if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0)
if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
addrlen = 4;
#ifdef ENABLE_IPV6
else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0)
else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0)
addrlen = 16;
#endif
@ -1086,15 +1090,18 @@ gtls_connect_step3(struct connectdata *conn,
}
#endif
if(!rc) {
if(conn->ssl_config.verifyhost) {
const char * const dispname = SSL_IS_PROXY() ?
conn->http_proxy.host.dispname : conn->host.dispname;
if(SSL_CONN_CONFIG(verifyhost)) {
failf(data, "SSL: certificate subject name (%s) does not match "
"target host name '%s'", certbuf, conn->host.dispname);
"target host name '%s'", certbuf, dispname);
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
}
else
infof(data, "\t common name: %s (does not match '%s')\n",
certbuf, conn->host.dispname);
certbuf, dispname);
}
else
infof(data, "\t common name: %s (matched)\n", certbuf);
@ -1103,7 +1110,7 @@ gtls_connect_step3(struct connectdata *conn,
certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
if(certclock == (time_t)-1) {
if(conn->ssl_config.verifypeer) {
if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server cert expiration date verify failed");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_SSL_CONNECT_ERROR;
@ -1113,7 +1120,7 @@ gtls_connect_step3(struct connectdata *conn,
}
else {
if(certclock < time(NULL)) {
if(data->set.ssl.primary.verifypeer) {
if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server certificate expiration date has passed.");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
@ -1128,7 +1135,7 @@ gtls_connect_step3(struct connectdata *conn,
certclock = gnutls_x509_crt_get_activation_time(x509_cert);
if(certclock == (time_t)-1) {
if(conn->ssl_config.verifypeer) {
if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server cert activation date verify failed");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_SSL_CONNECT_ERROR;
@ -1138,7 +1145,7 @@ gtls_connect_step3(struct connectdata *conn,
}
else {
if(certclock > time(NULL)) {
if(data->set.ssl.primary.verifypeer) {
if(SSL_CONN_CONFIG(verifypeer)) {
failf(data, "server certificate not activated yet.");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;