void PORT_ArenaUnmark(PLArenaPool *arena, void *mark) { #ifdef THREADMARK PORTArenaPool *pool = (PORTArenaPool *)arena; if (ARENAPOOL_MAGIC == pool->magic) { threadmark_mark **pw; PZ_Lock(pool->lock); if (PR_GetCurrentThread() != pool->marking_thread) { PZ_Unlock(pool->lock); PORT_SetError(SEC_ERROR_NO_MEMORY); PORT_Assert(0); return /* no error indication available */; } pw = &pool->first_mark; while (((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark)) { pw = &(*pw)->next; } if ((threadmark_mark *)NULL == *pw) { /* bad mark */ PZ_Unlock(pool->lock); PORT_SetError(SEC_ERROR_NO_MEMORY); PORT_Assert(0); return /* no error indication available */; } *pw = (threadmark_mark *)NULL; if (!pool->first_mark) { pool->marking_thread = (PRThread *)NULL; } PZ_Unlock(pool->lock); } #endif /* THREADMARK */ }
void * PORT_ArenaAlloc(PLArenaPool *arena, size_t size) { void *p = NULL; PORTArenaPool *pool = (PORTArenaPool *)arena; if (size <= 0) { size = 1; } if (size > MAX_SIZE) { /* you lose. */ } else /* Is it one of ours? Assume so and check the magic */ if (ARENAPOOL_MAGIC == pool->magic) { PZ_Lock(pool->lock); #ifdef THREADMARK /* Most likely one of ours. Is there a thread id? */ if (pool->marking_thread && pool->marking_thread != PR_GetCurrentThread()) { /* Another thread holds a mark in this arena */ PZ_Unlock(pool->lock); PORT_SetError(SEC_ERROR_NO_MEMORY); PORT_Assert(0); return NULL; } /* tid != null */ #endif /* THREADMARK */ PL_ARENA_ALLOCATE(p, arena, size); PZ_Unlock(pool->lock); } else { PL_ARENA_ALLOCATE(p, arena, size); } if (!p) { PORT_SetError(SEC_ERROR_NO_MEMORY); } return (p); }
NSS_EXTERN PRStatus nssCertificateStore_AddSMIMEProfile ( nssCertificateStore *store, nssSMIMEProfile *profile ) { NSSCertificate *cert; certificate_hash_entry *entry; cert = profile->certificate; PZ_Lock(store->lock); entry = (certificate_hash_entry *) nssHash_Lookup(store->issuer_and_serial, cert); if (entry) { nssSMIMEProfile* newProfile = nssSMIMEProfile_AddRef(profile); if (entry->profile) { nssSMIMEProfile_Destroy(entry->profile); } entry->profile = newProfile; } PZ_Unlock(store->lock); return (entry) ? PR_SUCCESS : PR_FAILURE; }
void terminateWorkerThreads(void) { VLOG(("selfserv: server_thead: waiting on stopping")); PZ_Lock(qLock); PZ_NotifyAllCondVar(jobQNotEmptyCv); while (threadCount > 0) { PZ_WaitCondVar(threadCountChangeCv, PR_INTERVAL_NO_TIMEOUT); } /* The worker threads empty the jobQ before they terminate. */ PORT_Assert(PR_CLIST_IS_EMPTY(&jobQ)); PZ_Unlock(qLock); DESTROY_CONDVAR(jobQNotEmptyCv); DESTROY_CONDVAR(freeListNotEmptyCv); DESTROY_CONDVAR(threadCountChangeCv); PR_DestroyLock(lastLoadedCrlLock); DESTROY_LOCK(qLock); PR_Free(jobTable); PR_Free(threads); }
void * PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize) { PORTArenaPool *pool = (PORTArenaPool *)arena; PORT_Assert(newsize >= oldsize); if (newsize > MAX_SIZE) { PORT_SetError(SEC_ERROR_NO_MEMORY); return NULL; } if (ARENAPOOL_MAGIC == pool->magic) { PZ_Lock(pool->lock); /* Do we do a THREADMARK check here? */ PL_ARENA_GROW(ptr, arena, oldsize, (newsize - oldsize)); PZ_Unlock(pool->lock); } else { PL_ARENA_GROW(ptr, arena, oldsize, (newsize - oldsize)); } return (ptr); }
/* * stub files for legacy db's to be able to encrypt and decrypt * various keys and attributes. */ static SECStatus sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText, SECItem **cipherText) { SFTKDBHandle *handle = sdb->app_private; SECStatus rv; if (handle == NULL) { return SECFailure; } /* if we aren't the key handle, try the other handle */ if (handle->type != SFTK_KEYDB_TYPE) { handle = handle->peerDB; } /* not a key handle */ if (handle == NULL || handle->passwordLock == NULL) { return SECFailure; } PZ_Lock(handle->passwordLock); if (handle->passwordKey.data == NULL) { PZ_Unlock(handle->passwordLock); /* PORT_SetError */ return SECFailure; } #if defined(PKCS11_DB_DATA_KEY_USE_KEYSTORE) || defined(PKCS11_DB_DATA_KEY_USE_KEYCHAIN) rv = sftkdb_EncryptAttributeByDbDataKey(arena, plainText, cipherText); #else rv = sftkdb_EncryptAttribute(arena, handle->newKey?handle->newKey:&handle->passwordKey, plainText, cipherText); #endif PZ_Unlock(handle->passwordLock); return rv; }
NSS_EXTERN PRStatus nssCertificateStore_AddTrust ( nssCertificateStore *store, NSSTrust *trust ) { NSSCertificate *cert; certificate_hash_entry *entry; cert = trust->certificate; PZ_Lock(store->lock); entry = (certificate_hash_entry *) nssHash_Lookup(store->issuer_and_serial, cert); if (entry) { NSSTrust* newTrust = nssTrust_AddRef(trust); if (entry->trust) { nssTrust_Destroy(entry->trust); } entry->trust = newTrust; } PZ_Unlock(store->lock); return (entry) ? PR_SUCCESS : PR_FAILURE; }
/* ** Update the global random number generator with more seeding ** material. */ SECStatus RNG_RandomUpdate(const void *data, size_t bytes) { SECStatus rv; /* Make sure our assumption that size_t is unsigned is true */ PR_STATIC_ASSERT(((size_t)-1) > (size_t)1); #if defined(NS_PTR_GT_32) || (defined(NSS_USE_64) && !defined(NS_PTR_LE_32)) /* * NIST 800-90 requires us to verify our inputs. This value can * come from the application, so we need to make sure it's within the * spec. The spec says it must be less than 2^32 bytes (2^35 bits). * This can only happen if size_t is greater than 32 bits (i.e. on * most 64 bit platforms). The 90% case (perhaps 100% case), size_t * is less than or equal to 32 bits if the platform is not 64 bits, and * greater than 32 bits if it is a 64 bit platform. The corner * cases are handled with explicit defines NS_PTR_GT_32 and NS_PTR_LE_32. * * In general, neither NS_PTR_GT_32 nor NS_PTR_LE_32 will need to be * defined. If you trip over the next two size ASSERTS at compile time, * you will need to define them for your platform. * * if 'sizeof(size_t) > 4' is triggered it means that we were expecting * sizeof(size_t) to be greater than 4, but it wasn't. Setting * NS_PTR_LE_32 will correct that mistake. * * if 'sizeof(size_t) <= 4' is triggered, it means that we were expecting * sizeof(size_t) to be less than or equal to 4, but it wasn't. Setting * NS_PTR_GT_32 will correct that mistake. */ PR_STATIC_ASSERT(sizeof(size_t) > 4); if (bytes > PRNG_MAX_ADDITIONAL_BYTES) { bytes = PRNG_MAX_ADDITIONAL_BYTES; } #else PR_STATIC_ASSERT(sizeof(size_t) <= 4); #endif PZ_Lock(globalrng->lock); /* if we're passed more than our additionalDataCache, simply * call reseed with that data */ if (bytes > sizeof (globalrng->additionalDataCache)) { rv = prng_reseed_test(globalrng, NULL, 0, data, (unsigned int) bytes); /* if we aren't going to fill or overflow the buffer, just cache it */ } else if (bytes < ((sizeof globalrng->additionalDataCache) - globalrng->additionalAvail)) { PORT_Memcpy(globalrng->additionalDataCache+globalrng->additionalAvail, data, bytes); globalrng->additionalAvail += (PRUint32) bytes; rv = SECSuccess; } else { /* we are going to fill or overflow the buffer. In this case we will * fill the entropy buffer, reseed with it, start a new buffer with the * remainder. We know the remainder will fit in the buffer because * we already handled the case where bytes > the size of the buffer. */ size_t bufRemain = (sizeof globalrng->additionalDataCache) - globalrng->additionalAvail; /* fill the rest of the buffer */ if (bufRemain) { PORT_Memcpy(globalrng->additionalDataCache +globalrng->additionalAvail, data, bufRemain); data = ((unsigned char *)data) + bufRemain; bytes -= bufRemain; } /* reseed from buffer */ rv = prng_reseed_test(globalrng, NULL, 0, globalrng->additionalDataCache, sizeof globalrng->additionalDataCache); /* copy the rest into the cache */ PORT_Memcpy(globalrng->additionalDataCache, data, bytes); globalrng->additionalAvail = (PRUint32) bytes; } PZ_Unlock(globalrng->lock); return rv; }
SECStatus launch_threads( startFn *startFunc, PRFileDesc *a, PRFileDesc *b, int c, PRBool local) { int i; SECStatus rv = SECSuccess; /* create the thread management serialization structs */ qLock = PZ_NewLock(nssILockSelfServ); jobQNotEmptyCv = PZ_NewCondVar(qLock); freeListNotEmptyCv = PZ_NewCondVar(qLock); threadCountChangeCv = PZ_NewCondVar(qLock); /* create monitor for crl reload procedure */ lastLoadedCrlLock = PR_NewLock(); /* allocate the array of thread slots */ threads = PR_Calloc(maxThreads, sizeof(perThread)); if (NULL == threads) { fprintf(stderr, "Oh Drat! Can't allocate the perThread array\n"); return SECFailure; } /* 5 is a little extra, intended to keep the jobQ from underflowing. ** That is, from going empty while not stopping and clients are still ** trying to contact us. */ rv = setupJobs(maxThreads + 5); if (rv != SECSuccess) return rv; PZ_Lock(qLock); for (i = 0; i < maxThreads; ++i) { perThread *slot = threads + i; slot->state = rs_running; slot->a = a; slot->b = b; slot->c = c; slot->startFunc = startFunc; slot->prThread = PR_CreateThread(PR_USER_THREAD, thread_wrapper, slot, PR_PRIORITY_NORMAL, (PR_TRUE == local) ? PR_LOCAL_THREAD : PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); if (slot->prThread == NULL) { printf("httpserv: Failed to launch thread!\n"); slot->state = rs_idle; rv = SECFailure; break; } ++threadCount; } PZ_Unlock(qLock); return rv; }
/* * check to see if the module has added new slots. PKCS 11 v2.20 allows for * modules to add new slots, but never remove them. Slots cannot be added * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently * grow on the caller. It is permissible for the slots to increase between * successive calls with NULL to get the size. */ SECStatus SECMOD_UpdateSlotList(SECMODModule *mod) { CK_RV crv; CK_ULONG count; CK_ULONG i, oldCount; PRBool freeRef = PR_FALSE; void *mark = NULL; CK_ULONG *slotIDs = NULL; PK11SlotInfo **newSlots = NULL; PK11SlotInfo **oldSlots = NULL; if (!moduleLock) { PORT_SetError(SEC_ERROR_NOT_INITIALIZED); return SECFailure; } /* C_GetSlotList is not a session function, make sure * calls are serialized */ PZ_Lock(mod->refLock); freeRef = PR_TRUE; /* see if the number of slots have changed */ crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto loser; } /* nothing new, blow out early, we want this function to be quick * and cheap in the normal case */ if (count == mod->slotCount) { PZ_Unlock(mod->refLock); return SECSuccess; } if (count < (CK_ULONG)mod->slotCount) { /* shouldn't happen with a properly functioning PKCS #11 module */ PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); goto loser; } /* get the new slot list */ slotIDs = PORT_NewArray(CK_SLOT_ID, count); if (slotIDs == NULL) { goto loser; } crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto loser; } freeRef = PR_FALSE; PZ_Unlock(mod->refLock); mark = PORT_ArenaMark(mod->arena); if (mark == NULL) { goto loser; } newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); /* walk down the new slot ID list returned from the module. We keep * the old slots which match a returned ID, and we initialize the new * slots. */ for (i=0; i < count; i++) { PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); if (!slot) { /* we have a new slot create a new slot data structure */ slot = PK11_NewSlotInfo(mod); if (!slot) { goto loser; } PK11_InitSlot(mod, slotIDs[i], slot); STAN_InitTokenForSlotInfo(NULL, slot); } newSlots[i] = slot; } STAN_ResetTokenInterator(NULL); PORT_Free(slotIDs); slotIDs = NULL; PORT_ArenaUnmark(mod->arena, mark); /* until this point we're still using the old slot list. Now we update * module slot list. We update the slots (array) first then the count, * since we've already guarrenteed that count has increased (just in case * someone is looking at the slots field of module without holding the * moduleLock */ SECMOD_GetWriteLock(moduleLock); oldCount =mod->slotCount; oldSlots = mod->slots; mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is * allocated out of the module arena and won't * be freed until the module is freed */ mod->slotCount = count; SECMOD_ReleaseWriteLock(moduleLock); /* free our old references before forgetting about oldSlot*/ for (i=0; i < oldCount; i++) { PK11_FreeSlot(oldSlots[i]); } return SECSuccess; loser: if (freeRef) { PZ_Unlock(mod->refLock); } if (slotIDs) { PORT_Free(slotIDs); } /* free all the slots we allocated. newSlots are part of the * mod arena. NOTE: the newSlots array contain both new and old * slots, but we kept a reference to the old slots when we built the new * array, so we need to free all the slots in newSlots array. */ if (newSlots) { for (i=0; i < count; i++) { if (newSlots[i] == NULL) { break; /* hit the last one */ } PK11_FreeSlot(newSlots[i]); } } /* must come after freeing newSlots */ if (mark) { PORT_ArenaRelease(mod->arena, mark); } return SECFailure; }
/* * this function waits for a token event on any slot of a given module * This function should not be called from more than one thread of the * same process (though other threads can make other library calls * on this module while this call is blocked). */ PK11SlotInfo * SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, PRIntervalTime latency) { CK_SLOT_ID id; CK_RV crv; PK11SlotInfo *slot; if (!pk11_getFinalizeModulesOption() || ((mod->cryptokiVersion.major == 2) && (mod->cryptokiVersion.minor < 1))) { /* if we are sharing the module with other software in our * address space, we can't reliably use C_WaitForSlotEvent(), * and if the module is version 2.0, C_WaitForSlotEvent() doesn't * exist */ return secmod_HandleWaitForSlotEvent(mod, flags, latency); } /* first the the PKCS #11 call */ PZ_Lock(mod->refLock); if (mod->evControlMask & SECMOD_END_WAIT) { goto end_wait; } mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT; PZ_Unlock(mod->refLock); crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL); PZ_Lock(mod->refLock); mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT; /* if we are in end wait, short circuit now, don't even risk * going into secmod_HandleWaitForSlotEvent */ if (mod->evControlMask & SECMOD_END_WAIT) { goto end_wait; } PZ_Unlock(mod->refLock); if (crv == CKR_FUNCTION_NOT_SUPPORTED) { /* module doesn't support that call, simulate it */ return secmod_HandleWaitForSlotEvent(mod, flags, latency); } if (crv != CKR_OK) { /* we can get this error if finalize was called while we were * still running. This is the only way to force a C_WaitForSlotEvent() * to return in PKCS #11. In this case, just return that there * was no event. */ if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) { PORT_SetError(SEC_ERROR_NO_EVENT); } else { PORT_SetError(PK11_MapError(crv)); } return NULL; } slot = SECMOD_FindSlotByID(mod, id); if (slot == NULL) { /* possibly a new slot that was added? */ SECMOD_UpdateSlotList(mod); slot = SECMOD_FindSlotByID(mod, id); } /* if we are in the delay period for the "isPresent" call, reset * the delay since we know things have probably changed... */ if (slot && slot->nssToken && slot->nssToken->slot) { nssSlot_ResetDelay(slot->nssToken->slot); } return slot; /* must be called with the lock on. */ end_wait: mod->evControlMask &= ~SECMOD_END_WAIT; PZ_Unlock(mod->refLock); PORT_SetError(SEC_ERROR_NO_EVENT); return NULL; }
/* * pk11_getKeyFromList returns a symKey that has a session (if needSession * was specified), or explicitly does not have a session (if needSession * was not specified). */ static PK11SymKey * pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession) { PK11SymKey *symKey = NULL; PZ_Lock(slot->freeListLock); /* own session list are symkeys with sessions that the symkey owns. * 'most' symkeys will own their own session. */ if (needSession) { if (slot->freeSymKeysWithSessionHead) { symKey = slot->freeSymKeysWithSessionHead; slot->freeSymKeysWithSessionHead = symKey->next; slot->keyCount--; } } /* if we don't need a symkey with its own session, or we couldn't find * one on the owner list, get one from the non-owner free list. */ if (!symKey) { if (slot->freeSymKeysHead) { symKey = slot->freeSymKeysHead; slot->freeSymKeysHead = symKey->next; slot->keyCount--; } } PZ_Unlock(slot->freeListLock); if (symKey) { symKey->next = NULL; if (!needSession) { return symKey; } /* if we are getting an owner key, make sure we have a valid session. * session could be invalid if the token has been removed or because * we got it from the non-owner free list */ if ((symKey->series != slot->series) || (symKey->session == CK_INVALID_SESSION)) { symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner); } PORT_Assert(symKey->session != CK_INVALID_SESSION); if (symKey->session != CK_INVALID_SESSION) return symKey; PK11_FreeSymKey(symKey); /* if we are here, we need a session, but couldn't get one, it's * unlikely we pk11_GetNewSession will succeed if we call it a second * time. */ return NULL; } symKey = PORT_New(PK11SymKey); if (symKey == NULL) { return NULL; } symKey->next = NULL; if (needSession) { symKey->session = pk11_GetNewSession(slot,&symKey->sessionOwner); PORT_Assert(symKey->session != CK_INVALID_SESSION); if (symKey->session == CK_INVALID_SESSION) { PK11_FreeSymKey(symKey); symKey = NULL; } } else { symKey->session = CK_INVALID_SESSION; } return symKey; }
static void lock_cache(void) { ssl_InitSessionCacheLocks(PR_TRUE); PZ_Lock(cacheLock); }
static SECStatus get_blinding_params(RSAPrivateKey *key, mp_int *n, unsigned int modLen, mp_int *f, mp_int *g) { SECStatus rv = SECSuccess; mp_err err = MP_OKAY; int cmp; PRCList *el; struct RSABlindingParamsStr *rsabp = NULL; /* Init the list if neccessary (the init function is only called once!) */ if (blindingParamsList.lock == NULL) { if (PR_CallOnce(&coBPInit, init_blinding_params_list) != PR_SUCCESS) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } } /* Acquire the list lock */ PZ_Lock(blindingParamsList.lock); /* Walk the list looking for the private key */ for (el = PR_NEXT_LINK(&blindingParamsList.head); el != &blindingParamsList.head; el = PR_NEXT_LINK(el)) { rsabp = (struct RSABlindingParamsStr *)el; cmp = SECITEM_CompareItem(&rsabp->modulus, &key->modulus); if (cmp == 0) { /* Check the usage counter for the parameters */ if (--rsabp->counter <= 0) { /* Regenerate the blinding parameters */ CHECK_SEC_OK( generate_blinding_params(rsabp, key, n, modLen) ); } /* Return the parameters */ CHECK_MPI_OK( mp_copy(&rsabp->f, f) ); CHECK_MPI_OK( mp_copy(&rsabp->g, g) ); /* Now that the params are located, release the list lock. */ PZ_Unlock(blindingParamsList.lock); /* XXX when fails? */ return SECSuccess; } else if (cmp > 0) { /* The key is not in the list. Break to param creation. */ break; } } /* At this point, the key is not in the list. el should point to the ** list element that this key should be inserted before. NOTE: the list ** lock is still held, so there cannot be a race condition here. */ rsabp = (struct RSABlindingParamsStr *) PORT_ZAlloc(sizeof(struct RSABlindingParamsStr)); if (!rsabp) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto cleanup; } /* Initialize the list pointer for the element */ PR_INIT_CLIST(&rsabp->link); /* Initialize the blinding parameters ** This ties up the list lock while doing some heavy, element-specific ** operations, but we don't want to insert the element until it is valid, ** which requires computing the blinding params. If this proves costly, ** it could be done after the list lock is released, and then if it fails ** the lock would have to be reobtained and the invalid element removed. */ rv = init_blinding_params(rsabp, key, n, modLen); if (rv != SECSuccess) { PORT_ZFree(rsabp, sizeof(struct RSABlindingParamsStr)); goto cleanup; } /* Insert the new element into the list ** If inserting in the middle of the list, el points to the link ** to insert before. Otherwise, the link needs to be appended to ** the end of the list, which is the same as inserting before the ** head (since el would have looped back to the head). */ PR_INSERT_BEFORE(&rsabp->link, el); /* Return the parameters */ CHECK_MPI_OK( mp_copy(&rsabp->f, f) ); CHECK_MPI_OK( mp_copy(&rsabp->g, g) ); /* Release the list lock */ PZ_Unlock(blindingParamsList.lock); /* XXX when fails? */ return SECSuccess; cleanup: /* It is possible to reach this after the lock is already released. ** Ignore the error in that case. */ PZ_Unlock(blindingParamsList.lock); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return SECFailure; }
/* ** Generate some random bytes, using the global random number generator ** object. */ static SECStatus prng_GenerateGlobalRandomBytes(RNGContext *rng, void *dest, size_t len) { SECStatus rv = SECSuccess; PRUint8 *output = dest; /* check for a valid global RNG context */ PORT_Assert(rng != NULL); if (rng == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* FIPS limits the amount of entropy available in a single request */ if (len > PRNG_MAX_REQUEST_SIZE) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* --- LOCKED --- */ PZ_Lock(rng->lock); /* Check the amount of seed data in the generator. If not enough, * don't produce any data. */ if (rng->reseed_counter[0] >= RESEED_VALUE) { rv = prng_reseed_test(rng, NULL, 0, NULL, 0); PZ_Unlock(rng->lock); if (rv != SECSuccess) { return rv; } RNG_SystemInfoForRNG(); PZ_Lock(rng->lock); } /* * see if we have enough bytes to fulfill the request. */ if (len <= rng->dataAvail) { memcpy(output, rng->data + ((sizeof rng->data) - rng->dataAvail), len); memset(rng->data + ((sizeof rng->data) - rng->dataAvail), 0, len); rng->dataAvail -= len; rv = SECSuccess; /* if we are asking for a small number of bytes, cache the rest of * the bytes */ } else if (len < sizeof rng->data) { rv = prng_generateNewBytes(rng, rng->data, sizeof rng->data, rng->additionalAvail ? rng->additionalDataCache : NULL, rng->additionalAvail); rng->additionalAvail = 0; if (rv == SECSuccess) { memcpy(output, rng->data, len); memset(rng->data, 0, len); rng->dataAvail = (sizeof rng->data) - len; } /* we are asking for lots of bytes, just ask the generator to pass them */ } else { rv = prng_generateNewBytes(rng, output, len, rng->additionalAvail ? rng->additionalDataCache : NULL, rng->additionalAvail); rng->additionalAvail = 0; } PZ_Unlock(rng->lock); /* --- UNLOCKED --- */ return rv; }
static SECStatus get_blinding_params(RSAPrivateKey *key, mp_int *n, unsigned int modLen, mp_int *f, mp_int *g) { RSABlindingParams *rsabp = NULL; blindingParams *bpUnlinked = NULL; blindingParams *bp, *prevbp = NULL; PRCList *el; SECStatus rv = SECSuccess; mp_err err = MP_OKAY; int cmp = -1; PRBool holdingLock = PR_FALSE; do { if (blindingParamsList.lock == NULL) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } /* Acquire the list lock */ PZ_Lock(blindingParamsList.lock); holdingLock = PR_TRUE; /* Walk the list looking for the private key */ for (el = PR_NEXT_LINK(&blindingParamsList.head); el != &blindingParamsList.head; el = PR_NEXT_LINK(el)) { rsabp = (RSABlindingParams *)el; cmp = SECITEM_CompareItem(&rsabp->modulus, &key->modulus); if (cmp >= 0) { /* The key is found or not in the list. */ break; } } if (cmp) { /* At this point, the key is not in the list. el should point to ** the list element before which this key should be inserted. */ rsabp = PORT_ZNew(RSABlindingParams); if (!rsabp) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto cleanup; } rv = init_blinding_params(rsabp, key, n, modLen); if (rv != SECSuccess) { PORT_ZFree(rsabp, sizeof(RSABlindingParams)); goto cleanup; } /* Insert the new element into the list ** If inserting in the middle of the list, el points to the link ** to insert before. Otherwise, the link needs to be appended to ** the end of the list, which is the same as inserting before the ** head (since el would have looped back to the head). */ PR_INSERT_BEFORE(&rsabp->link, el); } /* We've found (or created) the RSAblindingParams struct for this key. * Now, search its list of ready blinding params for a usable one. */ while (0 != (bp = rsabp->bp)) { if (--(bp->counter) > 0) { /* Found a match and there are still remaining uses left */ /* Return the parameters */ CHECK_MPI_OK( mp_copy(&bp->f, f) ); CHECK_MPI_OK( mp_copy(&bp->g, g) ); PZ_Unlock(blindingParamsList.lock); return SECSuccess; } /* exhausted this one, give its values to caller, and * then retire it. */ mp_exch(&bp->f, f); mp_exch(&bp->g, g); mp_clear( &bp->f ); mp_clear( &bp->g ); bp->counter = 0; /* Move to free list */ rsabp->bp = bp->next; bp->next = rsabp->free; rsabp->free = bp; /* In case there're threads waiting for new blinding * value - notify 1 thread the value is ready */ if (blindingParamsList.waitCount > 0) { PR_NotifyCondVar( blindingParamsList.cVar ); blindingParamsList.waitCount--; } PZ_Unlock(blindingParamsList.lock); return SECSuccess; } /* We did not find a usable set of blinding params. Can we make one? */ /* Find a free bp struct. */ prevbp = NULL; if ((bp = rsabp->free) != NULL) { /* unlink this bp */ rsabp->free = bp->next; bp->next = NULL; bpUnlinked = bp; /* In case we fail */ PZ_Unlock(blindingParamsList.lock); holdingLock = PR_FALSE; /* generate blinding parameter values for the current thread */ CHECK_SEC_OK( generate_blinding_params(key, f, g, n, modLen ) ); /* put the blinding parameter values into cache */ CHECK_MPI_OK( mp_init( &bp->f) ); CHECK_MPI_OK( mp_init( &bp->g) ); CHECK_MPI_OK( mp_copy( f, &bp->f) ); CHECK_MPI_OK( mp_copy( g, &bp->g) ); /* Put this at head of queue of usable params. */ PZ_Lock(blindingParamsList.lock); holdingLock = PR_TRUE; /* initialize RSABlindingParamsStr */ bp->counter = RSA_BLINDING_PARAMS_MAX_REUSE; bp->next = rsabp->bp; rsabp->bp = bp; bpUnlinked = NULL; /* In case there're threads waiting for new blinding value * just notify them the value is ready */ if (blindingParamsList.waitCount > 0) { PR_NotifyAllCondVar( blindingParamsList.cVar ); blindingParamsList.waitCount = 0; } PZ_Unlock(blindingParamsList.lock); return SECSuccess; } /* Here, there are no usable blinding parameters available, * and no free bp blocks, presumably because they're all * actively having parameters generated for them. * So, we need to wait here and not eat up CPU until some * change happens. */ blindingParamsList.waitCount++; PR_WaitCondVar( blindingParamsList.cVar, PR_INTERVAL_NO_TIMEOUT ); PZ_Unlock(blindingParamsList.lock); holdingLock = PR_FALSE; } while (1); cleanup: /* It is possible to reach this after the lock is already released. */ if (bpUnlinked) { if (!holdingLock) { PZ_Lock(blindingParamsList.lock); holdingLock = PR_TRUE; } bp = bpUnlinked; mp_clear( &bp->f ); mp_clear( &bp->g ); bp->counter = 0; /* Must put the unlinked bp back on the free list */ bp->next = rsabp->free; rsabp->free = bp; } if (holdingLock) { PZ_Unlock(blindingParamsList.lock); holdingLock = PR_FALSE; } if (err) { MP_TO_SEC_ERROR(err); } return SECFailure; }
SECStatus do_accepts( PRFileDesc *listen_sock, PRFileDesc *model_sock, int requestCert ) { PRNetAddr addr; PRErrorCode perr; #ifdef XP_UNIX struct sigaction act; #endif VLOG(("selfserv: do_accepts: starting")); PR_SetThreadPriority( PR_GetCurrentThread(), PR_PRIORITY_HIGH); acceptorThread = PR_GetCurrentThread(); #ifdef XP_UNIX /* set up the signal handler */ act.sa_handler = sigusr1_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGUSR1, &act, NULL)) { fprintf(stderr, "Error installing signal handler.\n"); exit(1); } #endif while (!stopping) { PRFileDesc *tcp_sock; PRCList *myLink; FPRINTF(stderr, "\n\n\nselfserv: About to call accept.\n"); tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT); if (tcp_sock == NULL) { perr = PR_GetError(); if ((perr != PR_CONNECT_RESET_ERROR && perr != PR_PENDING_INTERRUPT_ERROR) || verbose) { errWarn("PR_Accept"); } if (perr == PR_CONNECT_RESET_ERROR) { FPRINTF(stderr, "Ignoring PR_CONNECT_RESET_ERROR error - continue\n"); continue; } stopping = 1; break; } VLOG(("selfserv: do_accept: Got connection\n")); PZ_Lock(qLock); while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) { PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT); } if (stopping) { PZ_Unlock(qLock); if (tcp_sock) { PR_Close(tcp_sock); } break; } myLink = PR_LIST_HEAD(&freeJobs); PR_REMOVE_AND_INIT_LINK(myLink); /* could release qLock here and reacquire it 7 lines below, but ** why bother for 4 assignment statements? */ { JOB * myJob = (JOB *)myLink; myJob->tcp_sock = tcp_sock; myJob->model_sock = model_sock; myJob->requestCert = requestCert; } PR_APPEND_LINK(myLink, &jobQ); PZ_NotifyCondVar(jobQNotEmptyCv); PZ_Unlock(qLock); } FPRINTF(stderr, "selfserv: Closing listen socket.\n"); VLOG(("selfserv: do_accepts: exiting")); if (listen_sock) { PR_Close(listen_sock); } return SECSuccess; }
/* * destroy a symetric key */ void PK11_FreeSymKey(PK11SymKey *symKey) { PK11SlotInfo *slot; PRBool freeit = PR_TRUE; if (PR_ATOMIC_DECREMENT(&symKey->refCount) == 0) { PK11SymKey *parent = symKey->parent; symKey->parent = NULL; if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) { pk11_EnterKeyMonitor(symKey); (void) PK11_GETTAB(symKey->slot)-> C_DestroyObject(symKey->session, symKey->objectID); pk11_ExitKeyMonitor(symKey); } if (symKey->data.data) { PORT_Memset(symKey->data.data, 0, symKey->data.len); PORT_Free(symKey->data.data); } /* free any existing data */ if (symKey->userData && symKey->freeFunc) { (*symKey->freeFunc)(symKey->userData); } slot = symKey->slot; PZ_Lock(slot->freeListLock); if (slot->keyCount < slot->maxKeyCount) { /* * freeSymkeysWithSessionHead contain a list of reusable * SymKey structures with valid sessions. * sessionOwner must be true. * session must be valid. * freeSymKeysHead contain a list of SymKey structures without * valid session. * session must be CK_INVALID_SESSION. * though sessionOwner is false, callers should not depend on * this fact. */ if (symKey->sessionOwner) { PORT_Assert (symKey->session != CK_INVALID_SESSION); symKey->next = slot->freeSymKeysWithSessionHead; slot->freeSymKeysWithSessionHead = symKey; } else { symKey->session = CK_INVALID_SESSION; symKey->next = slot->freeSymKeysHead; slot->freeSymKeysHead = symKey; } slot->keyCount++; symKey->slot = NULL; freeit = PR_FALSE; } PZ_Unlock(slot->freeListLock); if (freeit) { pk11_CloseSession(symKey->slot, symKey->session, symKey->sessionOwner); PORT_Free(symKey); } PK11_FreeSlot(slot); if (parent) { PK11_FreeSymKey(parent); } } }
NSS_IMPLEMENT void nssTrustDomain_LockCertCache(NSSTrustDomain *td) { PZ_Lock(td->cache->lock); }
CK_RV PR_CALLBACK secmodLockMutext(CK_VOID_PTR mutext) { PZ_Lock((PZLock *)mutext); return CKR_OK; }
/* * this handles modules that do not support C_WaitForSlotEvent(). * The internal flags are stored. Note that C_WaitForSlotEvent() does not * have a timeout, so we don't have one for handleWaitForSlotEvent() either. */ PK11SlotInfo * secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags, PRIntervalTime latency) { PRBool removableSlotsFound = PR_FALSE; int i; int error = SEC_ERROR_NO_EVENT; if (!moduleLock) { PORT_SetError(SEC_ERROR_NOT_INITIALIZED); return NULL; } PZ_Lock(mod->refLock); if (mod->evControlMask & SECMOD_END_WAIT) { mod->evControlMask &= ~SECMOD_END_WAIT; PZ_Unlock(mod->refLock); PORT_SetError(SEC_ERROR_NO_EVENT); return NULL; } mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT; while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) { PZ_Unlock(mod->refLock); /* now is a good time to see if new slots have been added */ SECMOD_UpdateSlotList(mod); /* loop through all the slots on a module */ SECMOD_GetReadLock(moduleLock); for (i=0; i < mod->slotCount; i++) { PK11SlotInfo *slot = mod->slots[i]; PRUint16 series; PRBool present; /* perm modules do not change */ if (slot->isPerm) { continue; } removableSlotsFound = PR_TRUE; /* simulate the PKCS #11 module flags. are the flags different * from the last time we called? */ series = slot->series; present = PK11_IsPresent(slot); if ((slot->flagSeries != series) || (slot->flagState != present)) { slot->flagState = present; slot->flagSeries = series; SECMOD_ReleaseReadLock(moduleLock); PZ_Lock(mod->refLock); mod->evControlMask &= ~SECMOD_END_WAIT; PZ_Unlock(mod->refLock); return PK11_ReferenceSlot(slot); } } SECMOD_ReleaseReadLock(moduleLock); /* if everything was perm modules, don't lock up forever */ if ((mod->slotCount !=0) && !removableSlotsFound) { error =SEC_ERROR_NO_SLOT_SELECTED; PZ_Lock(mod->refLock); break; } if (flags & CKF_DONT_BLOCK) { PZ_Lock(mod->refLock); break; } PR_Sleep(latency); PZ_Lock(mod->refLock); } mod->evControlMask &= ~SECMOD_END_WAIT; PZ_Unlock(mod->refLock); PORT_SetError(error); return NULL; }