* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, 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
#define SLOTSIZE 13
PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
-
-PRLock * nss_initlock = NULL;
-PRLock * nss_crllock = NULL;
-struct curl_llist *nss_crl_list = NULL;
-NSSInitContext * nss_context = NULL;
-
-volatile int initialized = 0;
+static PRLock *nss_initlock = NULL;
+static PRLock *nss_crllock = NULL;
+static PRLock *nss_findslot_lock = NULL;
+static struct curl_llist *nss_crl_list = NULL;
+static NSSInitContext *nss_context = NULL;
+static volatile int initialized = 0;
typedef struct {
const char *name;
};
static const char* pem_library = "libnsspem.so";
-SECMODModule* mod = NULL;
+static SECMODModule* mod = NULL;
/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
return "unknown error";
}
-static void nss_print_error_message(struct SessionHandle *data, PRUint32 err)
+static void nss_print_error_message(struct Curl_easy *data, PRUint32 err)
{
failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
}
-static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
+static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
char *cipher_list)
{
unsigned int i;
* should be later deallocated using free(). If the OOM failure occurs, we
* return NULL, too.
*/
-static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind)
+static char* dup_nickname(struct Curl_easy *data, enum dupstring cert_kind)
{
const char *str = data->set.str[cert_kind];
const char *n;
return NULL;
}
+/* Lock/unlock wrapper for PK11_FindSlotByName() to work around race condition
+ * in nssSlot_IsTokenPresent() causing spurious SEC_ERROR_NO_TOKEN. For more
+ * details, go to <https://bugzilla.mozilla.org/1297397>.
+ */
+static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name)
+{
+ PK11SlotInfo *slot;
+ PR_Lock(nss_initlock);
+ slot = PK11_FindSlotByName(slot_name);
+ PR_Unlock(nss_initlock);
+ return slot;
+}
+
/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
* the call succeeds, append the object handle to the list of objects so that
* the object can be destroyed in Curl_nss_close(). */
if(!slot_name)
return CURLE_OUT_OF_MEMORY;
- slot = PK11_FindSlotByName(slot_name);
+ slot = nss_find_slot_by_name(slot_name);
free(slot_name);
if(!slot)
return result;
return result;
}
- slot = PK11_FindSlotByName("PEM Token #1");
+ slot = nss_find_slot_by_name("PEM Token #1");
if(!slot)
return CURLE_SSL_CERTPROBLEM;
static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
char *cert_file, char *key_file)
{
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
CURLcode result;
if(cert_file) {
unsigned int buflen;
SSLNextProtoState state;
- if(!conn->data->set.ssl_enable_npn && !conn->data->set.ssl_enable_alpn) {
+ if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) {
return;
}
PRBool *canFalseStart)
{
struct connectdata *conn = client_data;
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
SSLChannelInfo channelInfo;
SSLCipherSuiteInfo cipherInfo;
}
#endif
-static void display_cert_info(struct SessionHandle *data,
+static void display_cert_info(struct Curl_easy *data,
CERTCertificate *cert)
{
char *subject, *issuer, *common_name;
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
struct connectdata *conn = (struct connectdata *)arg;
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
PRErrorCode err = PR_GetError();
CERTCertificate *cert;
const char *pinnedpubkey)
{
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- struct SessionHandle *data = connssl->data;
+ struct Curl_easy *data = connssl->data;
CERTCertificate *cert;
if(!pinnedpubkey)
struct SECKEYPrivateKeyStr **pRetKey)
{
struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
- struct SessionHandle *data = connssl->data;
+ struct Curl_easy *data = connssl->data;
const char *nickname = connssl->client_nickname;
+ static const char pem_slotname[] = "PEM Token #1";
if(connssl->obj_clicert) {
/* use the cert/key provided by PEM reader */
- static const char pem_slotname[] = "PEM Token #1";
SECItem cert_der = { 0, NULL, 0 };
void *proto_win = SSL_RevealPinArg(sock);
struct CERTCertificateStr *cert;
struct SECKEYPrivateKeyStr *key;
- PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname);
+ PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
if(NULL == slot) {
failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
return SECFailure;
if(NULL == nickname)
nickname = "[unknown]";
+ if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
+ failf(data, "NSS: refusing previously loaded certificate from file: %s",
+ nickname);
+ return SECFailure;
+ }
+
if(NULL == *pRetKey) {
failf(data, "NSS: private key not found for certificate: %s", nickname);
return SECFailure;
}
/* data might be NULL */
-static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir)
+static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
{
NSSInitParameters initparams;
}
/* data might be NULL */
-static CURLcode nss_init(struct SessionHandle *data)
+static CURLcode nss_init(struct Curl_easy *data)
{
char *cert_dir;
struct_stat st;
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
nss_initlock = PR_NewLock();
nss_crllock = PR_NewLock();
+ nss_findslot_lock = PR_NewLock();
}
/* We will actually initialize NSS later */
}
/* data might be NULL */
-CURLcode Curl_nss_force_init(struct SessionHandle *data)
+CURLcode Curl_nss_force_init(struct Curl_easy *data)
{
CURLcode result;
if(!nss_initlock) {
PR_DestroyLock(nss_initlock);
PR_DestroyLock(nss_crllock);
+ PR_DestroyLock(nss_findslot_lock);
nss_initlock = NULL;
initialized = 0;
static CURLcode nss_load_ca_certificates(struct connectdata *conn,
int sockindex)
{
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
const char *cafile = data->set.ssl.CAfile;
const char *capath = data->set.ssl.CApath;
}
static CURLcode nss_init_sslver(SSLVersionRange *sslver,
- struct SessionHandle *data)
+ struct Curl_easy *data)
{
switch(data->set.ssl.version) {
default:
}
static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
- struct SessionHandle *data,
+ struct Curl_easy *data,
CURLcode curlerr)
{
PRErrorCode err = 0;
/* Switch the SSL socket into non-blocking mode. */
static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl,
- struct SessionHandle *data)
+ struct Curl_easy *data)
{
static PRSocketOptionData sock_opt;
sock_opt.option = PR_SockOpt_Nonblocking;
PRFileDesc *nspr_io_stub = NULL;
PRBool ssl_no_cache;
PRBool ssl_cbc_random_iv;
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
CURLcode result;
#endif
#ifdef SSL_ENABLE_NPN
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, data->set.ssl_enable_npn
- ? PR_TRUE : PR_FALSE) != SECSuccess)
+ if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
+ ? PR_TRUE : PR_FALSE) != SECSuccess)
goto error;
#endif
#ifdef SSL_ENABLE_ALPN
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, data->set.ssl_enable_alpn
- ? PR_TRUE : PR_FALSE) != SECSuccess)
+ if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
+ ? PR_TRUE : PR_FALSE) != SECSuccess)
goto error;
#endif
#endif
#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
- if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) {
+ if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) {
int cur = 0;
unsigned char protocols[128];
static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
CURLcode result = CURLE_SSL_CONNECT_ERROR;
PRUint32 timeout;
bool *done)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
const bool blocking = (done == NULL);
CURLcode result;
}
/* data might be NULL */
-int Curl_nss_seed(struct SessionHandle *data)
+int Curl_nss_seed(struct Curl_easy *data)
{
/* make sure that NSS is initialized */
return !!Curl_nss_force_init(data);
}
/* data might be NULL */
-int Curl_nss_random(struct SessionHandle *data,
+int Curl_nss_random(struct Curl_easy *data,
unsigned char *entropy,
size_t length)
{