1
0
mirror of https://github.com/moparisthebest/curl synced 2024-11-17 23:15:08 -05:00

nss: remove the BACKEND define kludge

This commit is contained in:
Daniel Stenberg 2020-03-18 23:12:58 +01:00
parent 89865c149d
commit 259d62c7c0
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -87,8 +87,6 @@ struct ssl_backend_data {
PK11GenericObject *obj_clicert; PK11GenericObject *obj_clicert;
}; };
#define BACKEND connssl->backend
static PRLock *nss_initlock = NULL; static PRLock *nss_initlock = NULL;
static PRLock *nss_crllock = NULL; static PRLock *nss_crllock = NULL;
static PRLock *nss_findslot_lock = NULL; static PRLock *nss_findslot_lock = NULL;
@ -462,6 +460,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl,
const int slot_id = (cacert) ? 0 : 1; const int slot_id = (cacert) ? 0 : 1;
char *slot_name = aprintf("PEM Token #%d", slot_id); char *slot_name = aprintf("PEM Token #%d", slot_id);
struct ssl_backend_data *backend = connssl->backend;
if(!slot_name) if(!slot_name)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -495,14 +494,14 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl,
if(!obj) if(!obj)
return result; return result;
if(insert_wrapped_ptr(&BACKEND->obj_list, obj) != CURLE_OK) { if(insert_wrapped_ptr(&backend->obj_list, obj) != CURLE_OK) {
PK11_DestroyGenericObject(obj); PK11_DestroyGenericObject(obj);
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
if(!cacert && CKO_CERTIFICATE == obj_class) if(!cacert && CKO_CERTIFICATE == obj_class)
/* store reference to a client certificate */ /* store reference to a client certificate */
BACKEND->obj_clicert = obj; backend->obj_clicert = obj;
return CURLE_OK; return CURLE_OK;
} }
@ -1084,7 +1083,8 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
const char *pinnedpubkey) const char *pinnedpubkey)
{ {
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
struct Curl_easy *data = BACKEND->data; struct ssl_backend_data *backend = connssl->backend;
struct Curl_easy *data = backend->data;
CERTCertificate *cert; CERTCertificate *cert;
if(!pinnedpubkey) if(!pinnedpubkey)
@ -1092,7 +1092,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
return CURLE_OK; return CURLE_OK;
/* get peer certificate */ /* get peer certificate */
cert = SSL_PeerCertificate(BACKEND->handle); cert = SSL_PeerCertificate(backend->handle);
if(cert) { if(cert) {
/* extract public key from peer certificate */ /* extract public key from peer certificate */
SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert); SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
@ -1136,11 +1136,12 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
struct SECKEYPrivateKeyStr **pRetKey) struct SECKEYPrivateKeyStr **pRetKey)
{ {
struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
struct Curl_easy *data = BACKEND->data; struct ssl_backend_data *backend = connssl->backend;
const char *nickname = BACKEND->client_nickname; struct Curl_easy *data = backend->data;
const char *nickname = backend->client_nickname;
static const char pem_slotname[] = "PEM Token #1"; static const char pem_slotname[] = "PEM Token #1";
if(BACKEND->obj_clicert) { if(backend->obj_clicert) {
/* use the cert/key provided by PEM reader */ /* use the cert/key provided by PEM reader */
SECItem cert_der = { 0, NULL, 0 }; SECItem cert_der = { 0, NULL, 0 };
void *proto_win = SSL_RevealPinArg(sock); void *proto_win = SSL_RevealPinArg(sock);
@ -1153,7 +1154,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
return SECFailure; return SECFailure;
} }
if(PK11_ReadRawAttribute(PK11_TypeGeneric, BACKEND->obj_clicert, CKA_VALUE, if(PK11_ReadRawAttribute(PK11_TypeGeneric, backend->obj_clicert, CKA_VALUE,
&cert_der) != SECSuccess) { &cert_der) != SECSuccess) {
failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
PK11_FreeSlot(slot); PK11_FreeSlot(slot);
@ -1503,11 +1504,12 @@ static void Curl_nss_cleanup(void)
static int Curl_nss_check_cxn(struct connectdata *conn) static int Curl_nss_check_cxn(struct connectdata *conn)
{ {
struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
struct ssl_backend_data *backend = connssl->backend;
int rc; int rc;
char buf; char buf;
rc = rc =
PR_Recv(BACKEND->handle, (void *)&buf, 1, PR_MSG_PEEK, PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK,
PR_SecondsToInterval(1)); PR_SecondsToInterval(1));
if(rc > 0) if(rc > 0)
return 1; /* connection still in place */ return 1; /* connection still in place */
@ -1521,26 +1523,27 @@ static int Curl_nss_check_cxn(struct connectdata *conn)
static void nss_close(struct ssl_connect_data *connssl) static void nss_close(struct ssl_connect_data *connssl)
{ {
/* before the cleanup, check whether we are using a client certificate */ /* before the cleanup, check whether we are using a client certificate */
const bool client_cert = (BACKEND->client_nickname != NULL) struct ssl_backend_data *backend = connssl->backend;
|| (BACKEND->obj_clicert != NULL); const bool client_cert = (backend->client_nickname != NULL)
|| (backend->obj_clicert != NULL);
free(BACKEND->client_nickname); free(backend->client_nickname);
BACKEND->client_nickname = NULL; backend->client_nickname = NULL;
/* destroy all NSS objects in order to avoid failure of NSS shutdown */ /* destroy all NSS objects in order to avoid failure of NSS shutdown */
Curl_llist_destroy(&BACKEND->obj_list, NULL); Curl_llist_destroy(&backend->obj_list, NULL);
BACKEND->obj_clicert = NULL; backend->obj_clicert = NULL;
if(BACKEND->handle) { if(backend->handle) {
if(client_cert) if(client_cert)
/* A server might require different authentication based on the /* A server might require different authentication based on the
* particular path being requested by the client. To support this * particular path being requested by the client. To support this
* scenario, we must ensure that a connection will never reuse the * scenario, we must ensure that a connection will never reuse the
* authentication data from a previous connection. */ * authentication data from a previous connection. */
SSL_InvalidateSession(BACKEND->handle); SSL_InvalidateSession(backend->handle);
PR_Close(BACKEND->handle); PR_Close(backend->handle);
BACKEND->handle = NULL; backend->handle = NULL;
} }
} }
@ -1551,15 +1554,16 @@ static void Curl_nss_close(struct connectdata *conn, int sockindex)
{ {
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex]; struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
if(BACKEND->handle || connssl_proxy->backend->handle) { if(backend->handle || connssl_proxy->backend->handle) {
/* NSS closes the socket we previously handed to it, so we must mark it /* NSS closes the socket we previously handed to it, so we must mark it
as closed to avoid double close */ as closed to avoid double close */
fake_sclose(conn->sock[sockindex]); fake_sclose(conn->sock[sockindex]);
conn->sock[sockindex] = CURL_SOCKET_BAD; conn->sock[sockindex] = CURL_SOCKET_BAD;
} }
if(BACKEND->handle) if(backend->handle)
/* nss_close(connssl) will transitively close also /* nss_close(connssl) will transitively close also
connssl_proxy->backend->handle if both are used. Clear it to avoid connssl_proxy->backend->handle if both are used. Clear it to avoid
a double close leading to crash. */ a double close leading to crash. */
@ -1773,6 +1777,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
CURLcode curlerr) CURLcode curlerr)
{ {
PRErrorCode err = 0; PRErrorCode err = 0;
struct ssl_backend_data *backend = connssl->backend;
if(is_nss_error(curlerr)) { if(is_nss_error(curlerr)) {
/* read NSPR error code */ /* read NSPR error code */
@ -1788,7 +1793,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
} }
/* cleanup on connection failure */ /* cleanup on connection failure */
Curl_llist_destroy(&BACKEND->obj_list, NULL); Curl_llist_destroy(&backend->obj_list, NULL);
return curlerr; return curlerr;
} }
@ -1799,10 +1804,11 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
bool blocking) bool blocking)
{ {
static PRSocketOptionData sock_opt; static PRSocketOptionData sock_opt;
struct ssl_backend_data *backend = connssl->backend;
sock_opt.option = PR_SockOpt_Nonblocking; sock_opt.option = PR_SockOpt_Nonblocking;
sock_opt.value.non_blocking = !blocking; sock_opt.value.non_blocking = !blocking;
if(PR_SetSocketOption(BACKEND->handle, &sock_opt) != PR_SUCCESS) if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS)
return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
return CURLE_OK; return CURLE_OK;
@ -1818,6 +1824,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[sockindex]; curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
CURLcode result; CURLcode result;
bool second_layer = FALSE; bool second_layer = FALSE;
SSLVersionRange sslver_supported; SSLVersionRange sslver_supported;
@ -1835,10 +1842,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
#endif #endif
}; };
BACKEND->data = data; backend->data = data;
/* list of all NSS objects we need to destroy in Curl_nss_close() */ /* list of all NSS objects we need to destroy in Curl_nss_close() */
Curl_llist_init(&BACKEND->obj_list, nss_destroy_object); Curl_llist_init(&backend->obj_list, nss_destroy_object);
PR_Lock(nss_initlock); PR_Lock(nss_initlock);
result = nss_init(conn->data); result = nss_init(conn->data);
@ -1960,7 +1967,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
char *nickname = dup_nickname(data, SSL_SET_OPTION(cert)); char *nickname = dup_nickname(data, SSL_SET_OPTION(cert));
if(nickname) { if(nickname) {
/* we are not going to use libnsspem.so to read the client cert */ /* we are not going to use libnsspem.so to read the client cert */
BACKEND->obj_clicert = NULL; backend->obj_clicert = NULL;
} }
else { else {
CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert), CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert),
@ -1973,10 +1980,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
} }
/* store the nickname for SelectClientCert() called during handshake */ /* store the nickname for SelectClientCert() called during handshake */
BACKEND->client_nickname = nickname; backend->client_nickname = nickname;
} }
else else
BACKEND->client_nickname = NULL; backend->client_nickname = NULL;
if(SSL_GetClientAuthDataHook(model, SelectClientCert, if(SSL_GetClientAuthDataHook(model, SelectClientCert,
(void *)connssl) != SECSuccess) { (void *)connssl) != SECSuccess) {
@ -2017,8 +2024,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
} }
/* import our model socket onto the current I/O stack */ /* import our model socket onto the current I/O stack */
BACKEND->handle = SSL_ImportFD(model, nspr_io); backend->handle = SSL_ImportFD(model, nspr_io);
if(!BACKEND->handle) { if(!backend->handle) {
if(!second_layer) if(!second_layer)
PR_Close(nspr_io); PR_Close(nspr_io);
goto error; goto error;
@ -2029,36 +2036,36 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
/* This is the password associated with the cert that we're using */ /* This is the password associated with the cert that we're using */
if(SSL_SET_OPTION(key_passwd)) { if(SSL_SET_OPTION(key_passwd)) {
SSL_SetPKCS11PinArg(BACKEND->handle, SSL_SET_OPTION(key_passwd)); SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd));
} }
#ifdef SSL_ENABLE_OCSP_STAPLING #ifdef SSL_ENABLE_OCSP_STAPLING
if(SSL_CONN_CONFIG(verifystatus)) { if(SSL_CONN_CONFIG(verifystatus)) {
if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
!= SECSuccess) != SECSuccess)
goto error; goto error;
} }
#endif #endif
#ifdef SSL_ENABLE_NPN #ifdef SSL_ENABLE_NPN
if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
? PR_TRUE : PR_FALSE) != SECSuccess) ? PR_TRUE : PR_FALSE) != SECSuccess)
goto error; goto error;
#endif #endif
#ifdef SSL_ENABLE_ALPN #ifdef SSL_ENABLE_ALPN
if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
? PR_TRUE : PR_FALSE) != SECSuccess) ? PR_TRUE : PR_FALSE) != SECSuccess)
goto error; goto error;
#endif #endif
#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
if(data->set.ssl.falsestart) { if(data->set.ssl.falsestart) {
if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_FALSE_START, PR_TRUE) if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
!= SECSuccess) != SECSuccess)
goto error; goto error;
if(SSL_SetCanFalseStartCallback(BACKEND->handle, CanFalseStartCallback, if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
conn) != SECSuccess) conn) != SECSuccess)
goto error; goto error;
} }
@ -2082,24 +2089,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
cur += ALPN_HTTP_1_1_LENGTH; cur += ALPN_HTTP_1_1_LENGTH;
if(SSL_SetNextProtoNego(BACKEND->handle, protocols, cur) != SECSuccess) if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess)
goto error; goto error;
} }
#endif #endif
/* Force handshake on next I/O */ /* Force handshake on next I/O */
if(SSL_ResetHandshake(BACKEND->handle, /* asServer */ PR_FALSE) if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE)
!= SECSuccess) != SECSuccess)
goto error; goto error;
/* propagate hostname to the TLS layer */ /* propagate hostname to the TLS layer */
if(SSL_SetURL(BACKEND->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : if(SSL_SetURL(backend->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name) != SECSuccess) conn->host.name) != SECSuccess)
goto error; goto error;
/* prevent NSS from re-using the session for a different hostname */ /* prevent NSS from re-using the session for a different hostname */
if(SSL_SetSockPeerID(BACKEND->handle, SSL_IS_PROXY() ? if(SSL_SetSockPeerID(backend->handle, SSL_IS_PROXY() ?
conn->http_proxy.host.name : conn->host.name) conn->http_proxy.host.name : conn->host.name)
!= SECSuccess) != SECSuccess)
goto error; goto error;
@ -2116,6 +2123,7 @@ error:
static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
{ {
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
CURLcode result = CURLE_SSL_CONNECT_ERROR; CURLcode result = CURLE_SSL_CONNECT_ERROR;
PRUint32 timeout; PRUint32 timeout;
@ -2136,7 +2144,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
/* Force the handshake now */ /* Force the handshake now */
timeout = PR_MillisecondsToInterval((PRUint32) time_left); timeout = PR_MillisecondsToInterval((PRUint32) time_left);
if(SSL_ForceHandshakeWithTimeout(BACKEND->handle, timeout) != SECSuccess) { if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) {
if(PR_GetError() == PR_WOULD_BLOCK_ERROR) if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
/* blocking direction is updated by nss_update_connecting_state() */ /* blocking direction is updated by nss_update_connecting_state() */
return CURLE_AGAIN; return CURLE_AGAIN;
@ -2147,7 +2155,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
goto error; goto error;
} }
result = display_conn_info(conn, BACKEND->handle); result = display_conn_info(conn, backend->handle);
if(result) if(result)
goto error; goto error;
@ -2156,7 +2164,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
if(nickname) { if(nickname) {
/* we support only nicknames in case of issuercert for now */ /* we support only nicknames in case of issuercert for now */
ret = check_issuer_cert(BACKEND->handle, nickname); ret = check_issuer_cert(backend->handle, nickname);
free(nickname); free(nickname);
} }
@ -2260,13 +2268,14 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */
CURLcode *curlcode) CURLcode *curlcode)
{ {
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
ssize_t rc; ssize_t rc;
/* The SelectClientCert() hook uses this for infof() and failf() but the /* The SelectClientCert() hook uses this for infof() and failf() but the
handle stored in nss_setup_connect() could have already been freed. */ handle stored in nss_setup_connect() could have already been freed. */
BACKEND->data = conn->data; backend->data = conn->data;
rc = PR_Send(BACKEND->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT); rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
if(rc < 0) { if(rc < 0) {
PRInt32 err = PR_GetError(); PRInt32 err = PR_GetError();
if(err == PR_WOULD_BLOCK_ERROR) if(err == PR_WOULD_BLOCK_ERROR)
@ -2297,13 +2306,14 @@ static ssize_t nss_recv(struct connectdata *conn, /* connection data */
CURLcode *curlcode) CURLcode *curlcode)
{ {
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
ssize_t nread; ssize_t nread;
/* The SelectClientCert() hook uses this for infof() and failf() but the /* The SelectClientCert() hook uses this for infof() and failf() but the
handle stored in nss_setup_connect() could have already been freed. */ handle stored in nss_setup_connect() could have already been freed. */
BACKEND->data = conn->data; backend->data = conn->data;
nread = PR_Recv(BACKEND->handle, buf, (int)buffersize, 0, nread = PR_Recv(backend->handle, buf, (int)buffersize, 0,
PR_INTERVAL_NO_WAIT); PR_INTERVAL_NO_WAIT);
if(nread < 0) { if(nread < 0) {
/* failed SSL read */ /* failed SSL read */
@ -2407,8 +2417,9 @@ static bool Curl_nss_false_start(void)
static void *Curl_nss_get_internals(struct ssl_connect_data *connssl, static void *Curl_nss_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM) CURLINFO info UNUSED_PARAM)
{ {
struct ssl_backend_data *backend = connssl->backend;
(void)info; (void)info;
return BACKEND->handle; return backend->handle;
} }
const struct Curl_ssl Curl_ssl_nss = { const struct Curl_ssl Curl_ssl_nss = {