NSS: Full backend support for HTTPS proxies
Also adjusts SSL_IS_PROXY() to work correctly without requiring sockindex.
This commit is contained in:
parent
cd2644fe2c
commit
68a7d38aa0
133
lib/vtls/nss.c
133
lib/vtls/nss.c
@ -547,6 +547,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
|
||||
SECStatus status;
|
||||
CURLcode result;
|
||||
struct ssl_connect_data *ssl = conn->ssl;
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
(void)sockindex; /* unused */
|
||||
|
||||
@ -564,8 +565,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
|
||||
SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
|
||||
PK11_IsPresent(slot);
|
||||
|
||||
status = PK11_Authenticate(slot, PR_TRUE,
|
||||
conn->data->set.ssl.key_passwd);
|
||||
status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
|
||||
PK11_FreeSlot(slot);
|
||||
|
||||
return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
|
||||
@ -644,7 +644,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
|
||||
struct connectdata *conn = (struct connectdata *)arg;
|
||||
|
||||
#ifdef SSL_ENABLE_OCSP_STAPLING
|
||||
if(conn->ssl_config.verifystatus) {
|
||||
if(SSL_CONN_CONFIG(verifystatus)) {
|
||||
SECStatus cacheResult;
|
||||
|
||||
const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
|
||||
@ -670,7 +670,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!conn->ssl_config.verifypeer) {
|
||||
if(!SSL_CONN_CONFIG(verifypeer)) {
|
||||
infof(conn->data, "skipping SSL peer certificate verification\n");
|
||||
return SECSuccess;
|
||||
}
|
||||
@ -890,9 +890,12 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
|
||||
CERTCertificate *cert;
|
||||
|
||||
/* remember the cert verification result */
|
||||
data->set.ssl.certverifyresult = err;
|
||||
if(SSL_IS_PROXY())
|
||||
data->set.proxy_ssl.certverifyresult = err;
|
||||
else
|
||||
data->set.ssl.certverifyresult = err;
|
||||
|
||||
if(err == SSL_ERROR_BAD_CERT_DOMAIN && !conn->ssl_config.verifyhost)
|
||||
if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
|
||||
/* we are asked not to verify the host name */
|
||||
return SECSuccess;
|
||||
|
||||
@ -1328,19 +1331,9 @@ Curl_nss_check_cxn(struct connectdata *conn)
|
||||
return -1; /* connection status unknown */
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when an SSL connection is closed.
|
||||
*/
|
||||
void Curl_nss_close(struct connectdata *conn, int sockindex)
|
||||
static void nss_close(struct ssl_connect_data *connssl)
|
||||
{
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
|
||||
if(connssl->handle) {
|
||||
/* NSS closes the socket we previously handed to it, so we must mark it
|
||||
as closed to avoid double close */
|
||||
fake_sclose(conn->sock[sockindex]);
|
||||
conn->sock[sockindex] = CURL_SOCKET_BAD;
|
||||
|
||||
if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL))
|
||||
/* A server might require different authentication based on the
|
||||
* particular path being requested by the client. To support this
|
||||
@ -1360,6 +1353,25 @@ void Curl_nss_close(struct connectdata *conn, int sockindex)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when an SSL connection is closed.
|
||||
*/
|
||||
void Curl_nss_close(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
|
||||
|
||||
if(connssl->handle || connssl_proxy->handle) {
|
||||
/* NSS closes the socket we previously handed to it, so we must mark it
|
||||
as closed to avoid double close */
|
||||
fake_sclose(conn->sock[sockindex]);
|
||||
conn->sock[sockindex] = CURL_SOCKET_BAD;
|
||||
}
|
||||
|
||||
nss_close(connssl);
|
||||
nss_close(connssl_proxy);
|
||||
}
|
||||
|
||||
/* return true if NSS can provide error code (and possibly msg) for the
|
||||
error */
|
||||
static bool is_nss_error(CURLcode err)
|
||||
@ -1398,8 +1410,8 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
const char *cafile = conn->ssl_config.CAfile;
|
||||
const char *capath = conn->ssl_config.CApath;
|
||||
const char *cafile = SSL_CONN_CONFIG(CAfile);
|
||||
const char *capath = SSL_CONN_CONFIG(CApath);
|
||||
|
||||
if(cafile) {
|
||||
CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
|
||||
@ -1447,9 +1459,10 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
|
||||
}
|
||||
|
||||
static CURLcode nss_init_sslver(SSLVersionRange *sslver,
|
||||
struct SessionHandle *data)
|
||||
struct SessionHandle *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
switch (conn->ssl_config.version) {
|
||||
switch (SSL_CONN_CONFIG(version)) {
|
||||
default:
|
||||
case CURL_SSLVERSION_DEFAULT:
|
||||
case CURL_SSLVERSION_TLSv1:
|
||||
@ -1550,6 +1563,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
curl_socket_t sockfd = conn->sock[sockindex];
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
CURLcode result;
|
||||
bool second_layer = FALSE;
|
||||
|
||||
SSLVersionRange sslver = {
|
||||
SSL_LIBRARY_VERSION_TLS_1_0, /* min */
|
||||
@ -1608,18 +1622,18 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
goto error;
|
||||
|
||||
/* do not use SSL cache if disabled or we are not going to verify peer */
|
||||
ssl_no_cache = (conn->ssl_config.sessionid && conn->ssl_config.verifypeer) ?
|
||||
PR_FALSE : PR_TRUE;
|
||||
ssl_no_cache = (data->set.general_ssl.sessionid
|
||||
&& SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
|
||||
if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
|
||||
goto error;
|
||||
|
||||
/* enable/disable the requested SSL version(s) */
|
||||
if(nss_init_sslver(&sslver, data) != CURLE_OK)
|
||||
if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
|
||||
goto error;
|
||||
if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
|
||||
goto error;
|
||||
|
||||
ssl_cbc_random_iv = !data->set.ssl.enable_beast;
|
||||
ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
|
||||
#ifdef SSL_CBC_RANDOM_IV
|
||||
/* unless the user explicitly asks to allow the protocol vulnerability, we
|
||||
use the work-around */
|
||||
@ -1631,14 +1645,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
|
||||
#endif
|
||||
|
||||
if(conn->ssl_config.cipher_list) {
|
||||
if(set_ciphers(data, model, conn->ssl_config.cipher_list) != SECSuccess) {
|
||||
if(SSL_CONN_CONFIG(cipher_list)) {
|
||||
if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
|
||||
result = CURLE_SSL_CIPHER;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if(!conn->ssl_config.verifypeer && conn->ssl_config.verifyhost)
|
||||
if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
|
||||
infof(data, "warning: ignoring value of ssl.verifyhost\n");
|
||||
|
||||
/* bypass the default SSL_AuthCertificate() hook in case we do not want to
|
||||
@ -1646,14 +1660,19 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
|
||||
goto error;
|
||||
|
||||
data->set.ssl.certverifyresult=0; /* not checked yet */
|
||||
/* not checked yet */
|
||||
if(SSL_IS_PROXY())
|
||||
data->set.proxy_ssl.certverifyresult = 0;
|
||||
else
|
||||
data->set.ssl.certverifyresult = 0;
|
||||
|
||||
if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
|
||||
goto error;
|
||||
|
||||
if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess)
|
||||
goto error;
|
||||
|
||||
if(conn->ssl_config.verifypeer) {
|
||||
if(SSL_CONN_CONFIG(verifypeer)) {
|
||||
const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
|
||||
if(rv) {
|
||||
result = rv;
|
||||
@ -1661,24 +1680,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
}
|
||||
}
|
||||
|
||||
if(data->set.ssl.CRLfile) {
|
||||
const CURLcode rv = nss_load_crl(data->set.ssl.CRLfile);
|
||||
if(SSL_SET_OPTION(CRLfile)) {
|
||||
const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile));
|
||||
if(rv) {
|
||||
result = rv;
|
||||
goto error;
|
||||
}
|
||||
infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile);
|
||||
infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile));
|
||||
}
|
||||
|
||||
if(data->set.ssl.cert) {
|
||||
char *nickname = dup_nickname(data, data->set.ssl.cert);
|
||||
if(SSL_SET_OPTION(cert)) {
|
||||
char *nickname = dup_nickname(data, SSL_SET_OPTION(cert));
|
||||
if(nickname) {
|
||||
/* we are not going to use libnsspem.so to read the client cert */
|
||||
connssl->obj_clicert = NULL;
|
||||
}
|
||||
else {
|
||||
CURLcode rv = cert_stuff(conn, sockindex, data->set.ssl.cert,
|
||||
data->set.ssl.key);
|
||||
CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert),
|
||||
SSL_SET_OPTION(key));
|
||||
if(rv) {
|
||||
/* failf() is already done in cert_stuff() */
|
||||
result = rv;
|
||||
@ -1698,15 +1717,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* wrap OS file descriptor by NSPR's file descriptor abstraction */
|
||||
nspr_io = PR_ImportTCPSocket(sockfd);
|
||||
if(!nspr_io)
|
||||
goto error;
|
||||
if(conn->proxy_ssl[sockindex].use) {
|
||||
DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
|
||||
DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL);
|
||||
nspr_io = conn->proxy_ssl[sockindex].handle;
|
||||
second_layer = TRUE;
|
||||
}
|
||||
else {
|
||||
/* wrap OS file descriptor by NSPR's file descriptor abstraction */
|
||||
nspr_io = PR_ImportTCPSocket(sockfd);
|
||||
if(!nspr_io)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* create our own NSPR I/O layer */
|
||||
nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
|
||||
if(!nspr_io_stub) {
|
||||
PR_Close(nspr_io);
|
||||
if(!second_layer)
|
||||
PR_Close(nspr_io);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1715,7 +1743,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
|
||||
/* push our new layer to the NSPR I/O stack */
|
||||
if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
|
||||
PR_Close(nspr_io);
|
||||
if(!second_layer)
|
||||
PR_Close(nspr_io);
|
||||
PR_Close(nspr_io_stub);
|
||||
goto error;
|
||||
}
|
||||
@ -1723,7 +1752,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
/* import our model socket onto the current I/O stack */
|
||||
connssl->handle = SSL_ImportFD(model, nspr_io);
|
||||
if(!connssl->handle) {
|
||||
PR_Close(nspr_io);
|
||||
if(!second_layer)
|
||||
PR_Close(nspr_io);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1731,12 +1761,12 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
model = NULL;
|
||||
|
||||
/* This is the password associated with the cert that we're using */
|
||||
if(data->set.ssl.key_passwd) {
|
||||
SSL_SetPKCS11PinArg(connssl->handle, data->set.ssl.key_passwd);
|
||||
if(SSL_SET_OPTION(key_passwd)) {
|
||||
SSL_SetPKCS11PinArg(connssl->handle, SSL_SET_OPTION(key_passwd));
|
||||
}
|
||||
|
||||
#ifdef SSL_ENABLE_OCSP_STAPLING
|
||||
if(data->set.ssl.verifystatus) {
|
||||
if(SSL_CONN_CONFIG(verifystatus)) {
|
||||
if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
|
||||
!= SECSuccess)
|
||||
goto error;
|
||||
@ -1793,7 +1823,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
|
||||
/* Force handshake on next I/O */
|
||||
SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
|
||||
|
||||
SSL_SetURL(connssl->handle, conn->host.name);
|
||||
SSL_SetURL(connssl->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
|
||||
conn->host.name);
|
||||
|
||||
return CURLE_OK;
|
||||
|
||||
@ -1810,6 +1841,8 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
|
||||
struct SessionHandle *data = conn->data;
|
||||
CURLcode result = CURLE_SSL_CONNECT_ERROR;
|
||||
PRUint32 timeout;
|
||||
long * const certverifyresult = SSL_IS_PROXY() ?
|
||||
&data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
|
||||
|
||||
/* check timeout situation */
|
||||
const long time_left = Curl_timeleft(data, NULL, TRUE);
|
||||
@ -1825,9 +1858,9 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
|
||||
if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
|
||||
/* blocking direction is updated by nss_update_connecting_state() */
|
||||
return CURLE_AGAIN;
|
||||
else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
|
||||
else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
else if(conn->data->set.ssl.certverifyresult!=0)
|
||||
else if(*certverifyresult != 0)
|
||||
result = CURLE_SSL_CACERT;
|
||||
goto error;
|
||||
}
|
||||
|
@ -308,7 +308,7 @@ ssl_connect_init_proxy(struct connectdata *conn, int sockindex) {
|
||||
DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
|
||||
if(ssl_connection_complete == conn->ssl[sockindex].state &&
|
||||
!conn->proxy_ssl[sockindex].use) {
|
||||
#ifdef USE_OPENSSL
|
||||
#if defined(USE_OPENSSL) || defined(USE_NSS)
|
||||
conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
|
||||
memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
|
||||
#else
|
||||
|
@ -48,7 +48,9 @@
|
||||
/* set of helper macros for the backends to access the correct fields. For the
|
||||
proxy or for the remote host - to properly support HTTPS proxy */
|
||||
|
||||
#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype)
|
||||
#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \
|
||||
ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \
|
||||
CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
|
||||
#define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \
|
||||
data->set.ssl.var)
|
||||
#define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \
|
||||
|
Loading…
x
Reference in New Issue
Block a user