Skip to content
Permalink
Browse files

nss: remove the BACKEND define kludge

  • Loading branch information
bagder committed Mar 18, 2020
1 parent 89865c1 commit 259d62c7c087c64e7b670fe69912350b8528e4f8
Showing with 62 additions and 51 deletions.
  1. +62 −51 lib/vtls/nss.c
@@ -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
* you should have received as part of this distribution. The terms
@@ -87,8 +87,6 @@ struct ssl_backend_data {
PK11GenericObject *obj_clicert;
};

#define BACKEND connssl->backend

static PRLock *nss_initlock = NULL;
static PRLock *nss_crllock = 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;
char *slot_name = aprintf("PEM Token #%d", slot_id);
struct ssl_backend_data *backend = connssl->backend;
if(!slot_name)
return CURLE_OUT_OF_MEMORY;

@@ -495,14 +494,14 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl,
if(!obj)
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);
return CURLE_OUT_OF_MEMORY;
}

if(!cacert && CKO_CERTIFICATE == obj_class)
/* store reference to a client certificate */
BACKEND->obj_clicert = obj;
backend->obj_clicert = obj;

return CURLE_OK;
}
@@ -1084,15 +1083,16 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
const char *pinnedpubkey)
{
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;

if(!pinnedpubkey)
/* no pinned public key specified */
return CURLE_OK;

/* get peer certificate */
cert = SSL_PeerCertificate(BACKEND->handle);
cert = SSL_PeerCertificate(backend->handle);
if(cert) {
/* extract public key from peer certificate */
SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
@@ -1136,11 +1136,12 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
struct SECKEYPrivateKeyStr **pRetKey)
{
struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
struct Curl_easy *data = BACKEND->data;
const char *nickname = BACKEND->client_nickname;
struct ssl_backend_data *backend = connssl->backend;
struct Curl_easy *data = backend->data;
const char *nickname = backend->client_nickname;
static const char pem_slotname[] = "PEM Token #1";

if(BACKEND->obj_clicert) {
if(backend->obj_clicert) {
/* use the cert/key provided by PEM reader */
SECItem cert_der = { 0, NULL, 0 };
void *proto_win = SSL_RevealPinArg(sock);
@@ -1153,7 +1154,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
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) {
failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
PK11_FreeSlot(slot);
@@ -1503,11 +1504,12 @@ static void Curl_nss_cleanup(void)
static int Curl_nss_check_cxn(struct connectdata *conn)
{
struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
struct ssl_backend_data *backend = connssl->backend;
int rc;
char buf;

rc =
PR_Recv(BACKEND->handle, (void *)&buf, 1, PR_MSG_PEEK,
PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK,
PR_SecondsToInterval(1));
if(rc > 0)
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)
{
/* before the cleanup, check whether we are using a client certificate */
const bool client_cert = (BACKEND->client_nickname != NULL)
|| (BACKEND->obj_clicert != NULL);
struct ssl_backend_data *backend = connssl->backend;
const bool client_cert = (backend->client_nickname != NULL)
|| (backend->obj_clicert != NULL);

free(BACKEND->client_nickname);
BACKEND->client_nickname = NULL;
free(backend->client_nickname);
backend->client_nickname = NULL;

/* destroy all NSS objects in order to avoid failure of NSS shutdown */
Curl_llist_destroy(&BACKEND->obj_list, NULL);
BACKEND->obj_clicert = NULL;
Curl_llist_destroy(&backend->obj_list, NULL);
backend->obj_clicert = NULL;

if(BACKEND->handle) {
if(backend->handle) {
if(client_cert)
/* A server might require different authentication based on the
* particular path being requested by the client. To support this
* scenario, we must ensure that a connection will never reuse the
* authentication data from a previous connection. */
SSL_InvalidateSession(BACKEND->handle);
SSL_InvalidateSession(backend->handle);

PR_Close(BACKEND->handle);
BACKEND->handle = NULL;
PR_Close(backend->handle);
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_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
as closed to avoid double close */
fake_sclose(conn->sock[sockindex]);
conn->sock[sockindex] = CURL_SOCKET_BAD;
}

if(BACKEND->handle)
if(backend->handle)
/* nss_close(connssl) will transitively close also
connssl_proxy->backend->handle if both are used. Clear it to avoid
a double close leading to crash. */
@@ -1773,6 +1777,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
CURLcode curlerr)
{
PRErrorCode err = 0;
struct ssl_backend_data *backend = connssl->backend;

if(is_nss_error(curlerr)) {
/* read NSPR error code */
@@ -1788,7 +1793,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
}

/* cleanup on connection failure */
Curl_llist_destroy(&BACKEND->obj_list, NULL);
Curl_llist_destroy(&backend->obj_list, NULL);

return curlerr;
}
@@ -1799,10 +1804,11 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
bool blocking)
{
static PRSocketOptionData sock_opt;
struct ssl_backend_data *backend = connssl->backend;
sock_opt.option = PR_SockOpt_Nonblocking;
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 CURLE_OK;
@@ -1818,6 +1824,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
CURLcode result;
bool second_layer = FALSE;
SSLVersionRange sslver_supported;
@@ -1835,10 +1842,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
#endif
};

BACKEND->data = data;
backend->data = data;

/* 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);
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));
if(nickname) {
/* we are not going to use libnsspem.so to read the client cert */
BACKEND->obj_clicert = NULL;
backend->obj_clicert = NULL;
}
else {
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 */
BACKEND->client_nickname = nickname;
backend->client_nickname = nickname;
}
else
BACKEND->client_nickname = NULL;
backend->client_nickname = NULL;

if(SSL_GetClientAuthDataHook(model, SelectClientCert,
(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 */
BACKEND->handle = SSL_ImportFD(model, nspr_io);
if(!BACKEND->handle) {
backend->handle = SSL_ImportFD(model, nspr_io);
if(!backend->handle) {
if(!second_layer)
PR_Close(nspr_io);
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 */
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
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)
goto error;
}
#endif

#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)
goto error;
#endif

#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)
goto error;
#endif

#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
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)
goto error;

if(SSL_SetCanFalseStartCallback(BACKEND->handle, CanFalseStartCallback,
if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
conn) != SECSuccess)
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);
cur += ALPN_HTTP_1_1_LENGTH;

if(SSL_SetNextProtoNego(BACKEND->handle, protocols, cur) != SECSuccess)
if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess)
goto error;
}
#endif


/* Force handshake on next I/O */
if(SSL_ResetHandshake(BACKEND->handle, /* asServer */ PR_FALSE)
if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE)
!= SECSuccess)
goto error;

/* 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)
goto error;

/* 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)
!= SECSuccess)
goto error;
@@ -2116,6 +2123,7 @@ static CURLcode nss_setup_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_backend_data *backend = connssl->backend;
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_SSL_CONNECT_ERROR;
PRUint32 timeout;
@@ -2136,7 +2144,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)

/* Force the handshake now */
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)
/* blocking direction is updated by nss_update_connecting_state() */
return CURLE_AGAIN;
@@ -2147,7 +2155,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
goto error;
}

result = display_conn_info(conn, BACKEND->handle);
result = display_conn_info(conn, backend->handle);
if(result)
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));
if(nickname) {
/* 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);
}

@@ -2260,13 +2268,14 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
ssize_t rc;

/* The SelectClientCert() hook uses this for infof() and failf() but the
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) {
PRInt32 err = PR_GetError();
if(err == PR_WOULD_BLOCK_ERROR)
@@ -2297,13 +2306,14 @@ static ssize_t nss_recv(struct connectdata *conn, /* connection data */
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
ssize_t nread;

/* The SelectClientCert() hook uses this for infof() and failf() but the
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);
if(nread < 0) {
/* 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,
CURLINFO info UNUSED_PARAM)
{
struct ssl_backend_data *backend = connssl->backend;
(void)info;
return BACKEND->handle;
return backend->handle;
}

const struct Curl_ssl Curl_ssl_nss = {

0 comments on commit 259d62c

Please sign in to comment.
You can’t perform that action at this time.