예제 #1
0
파일: rsa.c 프로젝트: venkatarajasekhar/Qt
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;
}
예제 #2
0
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;
}