Update NSS to 3.48 while keeping vc2013 hackfix and no-sslkeylogfile intact.

This commit is contained in:
Roy Tam 2020-01-03 13:36:26 +08:00
commit 171849c8e5
351 changed files with 115185 additions and 57946 deletions

View file

@ -645,17 +645,37 @@ FC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
CHECK_FORK();
if ((rv = sftk_fipsCheck()) == CKR_OK &&
(rv = sftk_newPinCheck(pNewPin, usNewLen)) == CKR_OK) {
rv = sftk_fipsCheck();
if (rv != CKR_OK) {
goto loser;
}
if (isLevel2 || usNewLen > 0) {
rv = sftk_newPinCheck(pNewPin, usNewLen);
if (rv != CKR_OK) {
goto loser;
}
rv = NSC_SetPIN(hSession, pOldPin, usOldLen, pNewPin, usNewLen);
if ((rv == CKR_OK) &&
(sftk_SlotIDFromSessionHandle(hSession) == FIPS_SLOT_ID)) {
if (rv != CKR_OK) {
goto loser;
}
if (sftk_SlotIDFromSessionHandle(hSession) == FIPS_SLOT_ID) {
/* if we set the password in level1 we now go
* to level2. NOTE: we don't allow the user to
* go from level2 to level1 */
isLevel2 = PR_TRUE;
}
} else {
/* here both old and new passwords are empty, but we need to
* call NSC_SetPIN to force rekey the database entries */
PORT_Assert(usNewLen == 0);
rv = NSC_SetPIN(hSession, pOldPin, usOldLen, pNewPin, usNewLen);
if (rv != CKR_OK) {
goto loser;
}
}
loser:
if (sftk_audit_enabled) {
char msg[128];
NSSAuditSeverity severity = (rv == CKR_OK) ? NSS_AUDIT_INFO : NSS_AUDIT_ERROR;

View file

@ -1213,6 +1213,8 @@ nsslowkey_EncodePW(SECOidTag alg, const SECItem *salt, SECItem *data)
unsigned char one = 1;
SECItem *epw = NULL;
SECItem *encParam;
int iterLen = 0;
int saltLen;
SECStatus rv;
param.salt = *salt;
@ -1221,6 +1223,17 @@ nsslowkey_EncodePW(SECOidTag alg, const SECItem *salt, SECItem *data)
param.iter.len = 1;
edi.encryptedData = *data;
iterLen = salt->len > 1 ? salt->data[salt->len - 1] : 2;
saltLen = (salt->len - iterLen) - 1;
/* if the resulting saltLen is a sha hash length, then assume that
* the iteration count is tacked on the end of the buffer */
if ((saltLen == SHA1_LENGTH) || (saltLen == SHA256_LENGTH) || (saltLen == SHA384_LENGTH) || (saltLen == SHA224_LENGTH) ||
(saltLen == SHA512_LENGTH)) {
param.iter.data = &salt->data[saltLen];
param.iter.len = iterLen;
param.salt.len = saltLen;
}
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
return NULL;
@ -1270,9 +1283,23 @@ nsslowkey_DecodePW(const SECItem *derData, SECOidTag *alg, SECItem *salt)
if (rv != SECSuccess) {
goto loser;
}
rv = SECITEM_CopyItem(NULL, salt, &param.salt);
if (rv != SECSuccess) {
goto loser;
/* if the iteration count isn't one, tack it at the end of the salt */
if (!((param.iter.len == 1) && (param.iter.data[0] == 1))) {
int total_len = param.salt.len + param.iter.len + 1;
salt->data = PORT_Alloc(total_len);
if (salt->data == NULL) {
goto loser;
}
PORT_Memcpy(salt->data, param.salt.data, param.salt.len);
PORT_Memcpy(&salt->data[param.salt.len], param.iter.data,
param.iter.len);
salt->data[total_len - 1] = param.iter.len;
salt->len = total_len;
} else {
rv = SECITEM_CopyItem(NULL, salt, &param.salt);
if (rv != SECSuccess) {
goto loser;
}
}
pwe = SECITEM_DupItem(&edi.encryptedData);

View file

@ -1069,7 +1069,7 @@ lg_FindTrustAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
NSSLOWCERTCertificate *cert;
unsigned char hash[SHA1_LENGTH];
unsigned int trustFlags;
CK_RV crv;
CK_RV crv = CKR_CANCEL;
switch (type) {
case CKA_PRIVATE:

View file

@ -171,6 +171,8 @@ sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText,
{
SFTKDBHandle *handle = sdb->app_private;
SECStatus rv;
SECItem *key;
int iterationCount;
if (handle == NULL) {
return SECFailure;
@ -192,9 +194,18 @@ sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText,
/* PORT_SetError */
return SECFailure;
}
key = handle->newKey ? handle->newKey : &handle->passwordKey;
if (sftk_isLegacyIterationCountAllowed()) {
if (handle->newKey) {
iterationCount = handle->newDefaultIterationCount;
} else {
iterationCount = handle->defaultIterationCount;
}
} else {
iterationCount = 1;
}
rv = sftkdb_EncryptAttribute(arena,
handle->newKey ? handle->newKey : &handle->passwordKey,
rv = sftkdb_EncryptAttribute(arena, key, iterationCount,
plainText, cipherText);
PZ_Unlock(handle->passwordLock);

View file

@ -324,6 +324,8 @@ static const struct mechanismList mechanisms[] = {
{ CKM_AES_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
{ CKM_AES_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
{ CKM_AES_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
{ CKM_AES_CMAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
{ CKM_AES_CMAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
{ CKM_AES_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
{ CKM_AES_CTS, { 16, 32, CKF_EN_DE }, PR_TRUE },
{ CKM_AES_CTR, { 16, 32, CKF_EN_DE }, PR_TRUE },
@ -624,7 +626,7 @@ sftk_hasNullPassword(SFTKSlot *slot, SFTKDBHandle *keydb)
pwenabled = PR_FALSE;
if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
PRBool tokenRemoved = PR_FALSE;
SECStatus rv = sftkdb_CheckPassword(keydb, "", &tokenRemoved);
SECStatus rv = sftkdb_CheckPasswordNull(keydb, &tokenRemoved);
if (tokenRemoved) {
sftk_CloseAllSessions(slot, PR_FALSE);
}
@ -2283,14 +2285,19 @@ sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyTyp
default:
return CKR_KEY_TYPE_INCONSISTENT;
}
if (crv != CKR_OK) {
return crv;
}
crv = sftk_AddAttributeType(publicKey, CKA_CLASS, &classType,
sizeof(CK_OBJECT_CLASS));
if (crv != CKR_OK)
if (crv != CKR_OK) {
return crv;
}
crv = sftk_AddAttributeType(publicKey, CKA_KEY_TYPE, &keyType,
sizeof(CK_KEY_TYPE));
if (crv != CKR_OK)
if (crv != CKR_OK) {
return crv;
}
/* now handle the operator attributes */
if (sftk_isTrue(privateKey, CKA_DECRYPT)) {
crv = sftk_forceAttribute(publicKey, CKA_ENCRYPT, &cktrue, sizeof(CK_BBOOL));
@ -3901,7 +3908,10 @@ NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
crv = CKR_PIN_LEN_RANGE;
goto loser;
}
if (ulNewLen < (CK_ULONG)slot->minimumPinLen) {
/* check the length of new pin, unless both old and new passwords
* are empty */
if ((ulNewLen != 0 || ulOldLen != 0) &&
ulNewLen < (CK_ULONG)slot->minimumPinLen) {
crv = CKR_PIN_LEN_RANGE;
goto loser;
}
@ -3937,7 +3947,7 @@ NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
PZ_Unlock(slot->slotLock);
tokenRemoved = PR_FALSE;
rv = sftkdb_CheckPassword(handle, "", &tokenRemoved);
rv = sftkdb_CheckPasswordNull(handle, &tokenRemoved);
if (tokenRemoved) {
sftk_CloseAllSessions(slot, PR_FALSE);
}
@ -4059,7 +4069,6 @@ NSC_CloseSession(CK_SESSION_HANDLE hSession)
session = NULL;
}
sftk_FreeSession(session);
return CKR_OK;
}

View file

@ -30,6 +30,7 @@
#include "lowpbe.h" /* We do PBE below */
#include "pkcs11t.h"
#include "secoid.h"
#include "cmac.h"
#include "alghmac.h"
#include "softoken.h"
#include "secasn1.h"
@ -39,7 +40,7 @@
#include "prenv.h"
#define __PASTE(x, y) x##y
#define BAD_PARAM_CAST(pMech, typeSize) (!pMech->pParameter || pMech->ulParameterLen < typeSize)
/*
* we renamed all our internal functions, get the correct
* definitions for them...
@ -782,6 +783,10 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
PRBool useNewKey = PR_FALSE;
int t;
if (!pMechanism) {
return CKR_MECHANISM_PARAM_INVALID;
}
crv = sftk_MechAllowsOperation(pMechanism->mechanism, mechUsage);
if (crv != CKR_OK)
return crv;
@ -895,6 +900,11 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crv = CKR_KEY_HANDLE_INVALID;
break;
}
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC2_CBC_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
rc2_param = (CK_RC2_CBC_PARAMS *)pMechanism->pParameter;
effectiveKeyLength = (rc2_param->ulEffectiveBits + 7) / 8;
context->cipherInfo =
@ -924,6 +934,11 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crv = CKR_KEY_HANDLE_INVALID;
break;
}
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_CBC_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
context->blockSize = rc5_param->ulWordsize * 2;
rc5Key.data = (unsigned char *)att->attrib.pValue;
@ -987,6 +1002,10 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crv = CKR_KEY_TYPE_INCONSISTENT;
break;
}
if (pMechanism->ulParameterLen < 8) {
crv = CKR_DOMAIN_PARAMS_INVALID;
break;
}
t = NSS_DES_CBC;
goto finish_des;
case CKM_DES3_ECB:
@ -1004,6 +1023,10 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crv = CKR_KEY_TYPE_INCONSISTENT;
break;
}
if (pMechanism->ulParameterLen < 8) {
crv = CKR_DOMAIN_PARAMS_INVALID;
break;
}
t = NSS_DES_EDE3_CBC;
finish_des:
context->blockSize = 8;
@ -1121,6 +1144,13 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
case CKM_AES_CTS:
case CKM_AES_CTR:
case CKM_AES_GCM:
if ((pMechanism->mechanism == CKM_AES_GCM && BAD_PARAM_CAST(pMechanism, sizeof(CK_GCM_PARAMS))) ||
(pMechanism->mechanism == CKM_AES_CTR && BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CTR_PARAMS))) ||
((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CTS) && BAD_PARAM_CAST(pMechanism, AES_BLOCK_SIZE))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
if (pMechanism->mechanism == CKM_AES_GCM) {
context->multi = PR_FALSE;
}
@ -1347,8 +1377,11 @@ NSC_EncryptUpdate(CK_SESSION_HANDLE hSession,
/* do it: NOTE: this assumes buf size in is >= buf size out! */
rv = (*context->update)(context->cipherInfo, pEncryptedPart,
&outlen, maxout, pPart, ulPartLen);
if (rv != SECSuccess) {
return sftk_MapCryptError(PORT_GetError());
}
*pulEncryptedPartLen = (CK_ULONG)(outlen + padoutlen);
return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
return CKR_OK;
}
/* NSC_EncryptFinal finishes a multiple-part encryption operation. */
@ -1428,26 +1461,29 @@ NSC_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
return crv;
if (!pEncryptedData) {
*pulEncryptedDataLen = context->rsa ? context->maxLen : ulDataLen + 2 * context->blockSize;
goto finish;
outlen = context->rsa ? context->maxLen : ulDataLen + 2 * context->blockSize;
goto done;
}
if (context->doPad) {
if (context->multi) {
CK_ULONG updateLen = maxoutlen;
CK_ULONG finalLen;
/* padding is fairly complicated, have the update and final
* code deal with it */
sftk_FreeSession(session);
crv = NSC_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData,
pulEncryptedDataLen);
if (crv != CKR_OK)
*pulEncryptedDataLen = 0;
maxoutlen -= *pulEncryptedDataLen;
pEncryptedData += *pulEncryptedDataLen;
&updateLen);
if (crv != CKR_OK) {
updateLen = 0;
}
maxoutlen -= updateLen;
pEncryptedData += updateLen;
finalLen = maxoutlen;
crv2 = NSC_EncryptFinal(hSession, pEncryptedData, &finalLen);
if (crv2 == CKR_OK)
*pulEncryptedDataLen += finalLen;
if (crv == CKR_OK && crv2 == CKR_OK) {
*pulEncryptedDataLen = updateLen + finalLen;
}
return crv == CKR_OK ? crv2 : crv;
}
/* doPad without multi means that padding must be done on the first
@ -1473,14 +1509,15 @@ NSC_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
rv = (*context->update)(context->cipherInfo, pEncryptedData,
&outlen, maxoutlen, pText.data, pText.len);
crv = (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
*pulEncryptedDataLen = (CK_ULONG)outlen;
if (pText.data != pData)
PORT_ZFree(pText.data, pText.len);
fail:
sftk_TerminateOp(session, SFTK_ENCRYPT, context);
finish:
done:
sftk_FreeSession(session);
if (crv == CKR_OK) {
*pulEncryptedDataLen = (CK_ULONG)outlen;
}
return crv;
}
@ -1569,8 +1606,73 @@ NSC_DecryptUpdate(CK_SESSION_HANDLE hSession,
/* do it: NOTE: this assumes buf size in is >= buf size out! */
rv = (*context->update)(context->cipherInfo, pPart, &outlen,
maxout, pEncryptedPart, ulEncryptedPartLen);
if (rv != SECSuccess) {
return sftk_MapDecryptError(PORT_GetError());
}
*pulPartLen = (CK_ULONG)(outlen + padoutlen);
return (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
return CKR_OK;
}
/* From ssl3con.c: Constant-time helper macro that copies the MSB of x to all
* other bits. */
#define DUPLICATE_MSB_TO_ALL(x) ((unsigned int)((int)(x) >> (sizeof(int) * 8 - 1)))
/* CK_RVToMask returns, in constant time, a mask value of
* all ones if rv == CKR_OK. Otherwise it returns zero. */
static unsigned int
CK_RVToMask(CK_RV rv)
{
unsigned int good;
/* rv ^ CKR_OK is zero iff rv == CKR_OK. Subtracting one results
* in the MSB being set to one iff it was zero before. */
good = rv ^ CKR_OK;
good--;
return DUPLICATE_MSB_TO_ALL(good);
}
/* Constant-time helper macro that selects l or r depending on all-1 or all-0
* mask m */
#define CT_SEL(m, l, r) (((m) & (l)) | (~(m) & (r)))
/* Constant-time helper macro that returns all-1s if x is not 0; and all-0s
* otherwise. */
#define CT_NOT_ZERO(x) (DUPLICATE_MSB_TO_ALL(((x) | (0 - x))))
/* sftk_CheckCBCPadding checks, in constant time, the padding validity and
* accordingly sets the pad length. */
static CK_RV
sftk_CheckCBCPadding(CK_BYTE_PTR pLastPart,
unsigned int blockSize, unsigned int *outPadSize)
{
PORT_Assert(outPadSize);
unsigned int padSize = (unsigned int)pLastPart[blockSize - 1];
/* If padSize <= blockSize, set goodPad to all-1s and all-0s otherwise.*/
unsigned int goodPad = DUPLICATE_MSB_TO_ALL(~(blockSize - padSize));
/* padSize should not be 0 */
goodPad &= CT_NOT_ZERO(padSize);
unsigned int i;
for (i = 0; i < blockSize; i++) {
/* If i < padSize, set loopMask to all-1s and all-0s otherwise.*/
unsigned int loopMask = DUPLICATE_MSB_TO_ALL(~(padSize - 1 - i));
/* Get the padding value (should be padSize) from buffer */
unsigned int padVal = pLastPart[blockSize - 1 - i];
/* Update goodPad only if i < padSize */
goodPad &= CT_SEL(loopMask, ~(padVal ^ padSize), goodPad);
}
/* If any of the final padding bytes had the wrong value, one or more
* of the lower eight bits of |goodPad| will be cleared. We AND the
* bottom 8 bits together and duplicate the result to all the bits. */
goodPad &= goodPad >> 4;
goodPad &= goodPad >> 2;
goodPad &= goodPad >> 1;
goodPad <<= sizeof(goodPad) * 8 - 1;
goodPad = DUPLICATE_MSB_TO_ALL(goodPad);
/* Set outPadSize to padSize or 0 */
*outPadSize = CT_SEL(goodPad, padSize, 0);
/* Return OK if the pad is valid */
return CT_SEL(goodPad, CKR_OK, CKR_ENCRYPTED_DATA_INVALID);
}
/* NSC_DecryptFinal finishes a multiple-part decryption operation. */
@ -1611,24 +1713,10 @@ NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
if (rv != SECSuccess) {
crv = sftk_MapDecryptError(PORT_GetError());
} else {
unsigned int padSize =
(unsigned int)pLastPart[context->blockSize - 1];
if ((padSize > context->blockSize) || (padSize == 0)) {
crv = CKR_ENCRYPTED_DATA_INVALID;
} else {
unsigned int i;
unsigned int badPadding = 0; /* used as a boolean */
for (i = 0; i < padSize; i++) {
badPadding |=
(unsigned int)pLastPart[context->blockSize - 1 - i] ^
padSize;
}
if (badPadding) {
crv = CKR_ENCRYPTED_DATA_INVALID;
} else {
*pulLastPartLen = outlen - padSize;
}
}
unsigned int padSize = 0;
crv = sftk_CheckCBCPadding(&pLastPart[outlen - context->blockSize], context->blockSize, &padSize);
/* Update pulLastPartLen, in constant time, if crv is OK */
*pulLastPartLen = CT_SEL(CK_RVToMask(crv), outlen - padSize, *pulLastPartLen);
}
}
}
@ -1661,52 +1749,48 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
return crv;
if (!pData) {
*pulDataLen = ulEncryptedDataLen + context->blockSize;
goto finish;
*pulDataLen = (CK_ULONG)(ulEncryptedDataLen + context->blockSize);
goto done;
}
if (context->doPad && context->multi) {
CK_ULONG updateLen = maxoutlen;
CK_ULONG finalLen;
/* padding is fairly complicated, have the update and final
* code deal with it */
sftk_FreeSession(session);
crv = NSC_DecryptUpdate(hSession, pEncryptedData, ulEncryptedDataLen,
pData, pulDataLen);
if (crv != CKR_OK)
*pulDataLen = 0;
maxoutlen -= *pulDataLen;
pData += *pulDataLen;
pData, &updateLen);
if (crv == CKR_OK) {
maxoutlen -= updateLen;
pData += updateLen;
}
finalLen = maxoutlen;
crv2 = NSC_DecryptFinal(hSession, pData, &finalLen);
if (crv2 == CKR_OK)
*pulDataLen += finalLen;
return crv == CKR_OK ? crv2 : crv;
if (crv == CKR_OK) {
*pulDataLen = CT_SEL(CK_RVToMask(crv2), updateLen + finalLen, *pulDataLen);
return crv2;
} else {
return crv;
}
}
rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen,
pEncryptedData, ulEncryptedDataLen);
/* XXX need to do MUCH better error mapping than this. */
crv = (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
if (rv == SECSuccess && context->doPad) {
unsigned int padding = pData[outlen - 1];
if (padding > context->blockSize || !padding) {
crv = CKR_ENCRYPTED_DATA_INVALID;
if (rv == SECSuccess) {
if (context->doPad) {
unsigned int padSize = 0;
crv = sftk_CheckCBCPadding(&pData[outlen - context->blockSize], context->blockSize, &padSize);
/* Update pulDataLen, in constant time, if crv is OK */
*pulDataLen = CT_SEL(CK_RVToMask(crv), outlen - padSize, *pulDataLen);
} else {
unsigned int i;
unsigned int badPadding = 0; /* used as a boolean */
for (i = 0; i < padding; i++) {
badPadding |= (unsigned int)pData[outlen - 1 - i] ^ padding;
}
if (badPadding) {
crv = CKR_ENCRYPTED_DATA_INVALID;
} else {
outlen -= padding;
}
*pulDataLen = (CK_ULONG)outlen;
}
}
*pulDataLen = (CK_ULONG)outlen;
sftk_TerminateOp(session, SFTK_DECRYPT, context);
finish:
done:
sftk_FreeSession(session);
return crv;
}
@ -1920,54 +2004,55 @@ sftk_HMACCmp(CK_ULONG *copyLen, unsigned char *sig, unsigned int sigLen,
}
/*
* common HMAC initalization routine
* common HMAC + CMAC initialization routine
*/
static CK_RV
sftk_doHMACInit(SFTKSessionContext *context, HASH_HashType hash,
SFTKObject *key, CK_ULONG mac_size)
sftk_doMACInit(CK_MECHANISM_TYPE mech, SFTKSessionContext *session,
SFTKObject *key, CK_ULONG mac_size)
{
SFTKAttribute *keyval;
HMACContext *HMACcontext;
CK_RV crv;
sftk_MACCtx *context;
CK_ULONG *intpointer;
const SECHashObject *hashObj = HASH_GetRawHashObject(hash);
PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID);
/* required by FIPS 198 Section 4 */
if (isFIPS && (mac_size < 4 || mac_size < hashObj->length / 2)) {
/* Set up the initial context. */
crv = sftk_MAC_Create(mech, key, &context);
if (crv != CKR_OK) {
return crv;
}
session->hashInfo = context;
session->multi = PR_TRUE;
/* Required by FIPS 198 Section 4. Delay this check until after the MAC
* has been initialized to steal the output size of the MAC. */
if (isFIPS && (mac_size < 4 || mac_size < context->mac_size / 2)) {
sftk_MAC_Destroy(context, PR_TRUE);
return CKR_BUFFER_TOO_SMALL;
}
keyval = sftk_FindAttribute(key, CKA_VALUE);
if (keyval == NULL)
return CKR_KEY_SIZE_RANGE;
/* Configure our helper functions appropriately. Note that these casts
* ignore the return values. */
session->hashUpdate = (SFTKHash)sftk_MAC_Update;
session->end = (SFTKEnd)sftk_MAC_Finish;
session->hashdestroy = (SFTKDestroy)sftk_MAC_Destroy;
HMACcontext = HMAC_Create(hashObj,
(const unsigned char *)keyval->attrib.pValue,
keyval->attrib.ulValueLen, isFIPS);
context->hashInfo = HMACcontext;
context->multi = PR_TRUE;
sftk_FreeAttribute(keyval);
if (context->hashInfo == NULL) {
if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
return CKR_KEY_SIZE_RANGE;
}
return CKR_HOST_MEMORY;
}
context->hashUpdate = (SFTKHash)HMAC_Update;
context->end = (SFTKEnd)HMAC_Finish;
context->hashdestroy = (SFTKDestroy)HMAC_Destroy;
intpointer = PORT_New(CK_ULONG);
if (intpointer == NULL) {
sftk_MAC_Destroy(context, PR_TRUE);
return CKR_HOST_MEMORY;
}
*intpointer = mac_size;
context->cipherInfo = intpointer;
context->destroy = (SFTKDestroy)sftk_Space;
context->update = (SFTKCipher)sftk_SignCopy;
context->verify = (SFTKVerify)sftk_HMACCmp;
context->maxLen = hashObj->length;
HMAC_Begin(HMACcontext);
session->cipherInfo = intpointer;
/* Since we're only "hashing", copy the result from session->end to the
* caller using sftk_SignCopy. */
session->update = (SFTKCipher)sftk_SignCopy;
session->verify = (SFTKVerify)sftk_HMACCmp;
session->destroy = (SFTKDestroy)sftk_Space;
session->maxLen = context->mac_size;
return CKR_OK;
}
@ -2123,9 +2208,13 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
unsigned int blockSize;
PRBool isXCBC = PR_FALSE;
if (!pMechanism) {
return CKR_MECHANISM_PARAM_INVALID;
}
switch (pMechanism->mechanism) {
case CKM_RC2_MAC_GENERAL:
if (!pMechanism->pParameter) {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC2_MAC_GENERAL_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
mac_bytes =
@ -2145,12 +2234,18 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
break;
#if NSS_SOFTOKEN_DOES_RC5
case CKM_RC5_MAC_GENERAL:
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_MAC_GENERAL_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
mac_bytes =
((CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
/* fall through */
case CKM_RC5_MAC:
/* this works because ulEffectiveBits is in the same place in both the
* CK_RC5_MAC_GENERAL_PARAMS and CK_RC5_CBC_PARAMS */
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_MAC_GENERAL_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
rc5_mac = (CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter;
rc5_params.ulWordsize = rc5_mac->ulWordsize;
rc5_params.ulRounds = rc5_mac->ulRounds;
@ -2707,18 +2802,19 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
break;
#define INIT_HMAC_MECH(mmm) \
case CKM_##mmm##_HMAC_GENERAL: \
PORT_Assert(pMechanism->pParameter); \
if (!pMechanism->pParameter) { \
crv = CKR_MECHANISM_PARAM_INVALID; \
break; \
} \
crv = sftk_doHMACInit(context, HASH_Alg##mmm, key, \
*(CK_ULONG *)pMechanism->pParameter); \
break; \
case CKM_##mmm##_HMAC: \
crv = sftk_doHMACInit(context, HASH_Alg##mmm, key, mmm##_LENGTH); \
#define INIT_HMAC_MECH(mmm) \
case CKM_##mmm##_HMAC_GENERAL: \
PORT_Assert(pMechanism->pParameter); \
if (!pMechanism->pParameter) { \
crv = CKR_MECHANISM_PARAM_INVALID; \
break; \
} \
crv = sftk_doMACInit(pMechanism->mechanism, context, key, \
*(CK_ULONG *)pMechanism->pParameter); \
break; \
case CKM_##mmm##_HMAC: \
crv = sftk_doMACInit(pMechanism->mechanism, context, key, \
mmm##_LENGTH); \
break;
INIT_HMAC_MECH(MD2)
@ -2730,17 +2826,27 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
case CKM_SHA_1_HMAC_GENERAL:
PORT_Assert(pMechanism->pParameter);
if (!pMechanism->pParameter) {
if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
crv = sftk_doHMACInit(context, HASH_AlgSHA1, key,
*(CK_ULONG *)pMechanism->pParameter);
crv = sftk_doMACInit(pMechanism->mechanism, context, key,
*(CK_ULONG *)pMechanism->pParameter);
break;
case CKM_SHA_1_HMAC:
crv = sftk_doHMACInit(context, HASH_AlgSHA1, key, SHA1_LENGTH);
crv = sftk_doMACInit(pMechanism->mechanism, context, key, SHA1_LENGTH);
break;
case CKM_AES_CMAC_GENERAL:
PORT_Assert(pMechanism->pParameter);
if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
crv = sftk_doMACInit(pMechanism->mechanism, context, key, *(CK_ULONG *)pMechanism->pParameter);
break;
case CKM_AES_CMAC:
crv = sftk_doMACInit(pMechanism->mechanism, context, key, AES_BLOCK_SIZE);
break;
case CKM_SSL3_MD5_MAC:
PORT_Assert(pMechanism->pParameter);
if (!pMechanism->pParameter) {
@ -3414,11 +3520,11 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession,
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
crv = sftk_doHMACInit(context, HASH_AlgSHA1, key,
*(CK_ULONG *)pMechanism->pParameter);
crv = sftk_doMACInit(pMechanism->mechanism, context, key,
*(CK_ULONG *)pMechanism->pParameter);
break;
case CKM_SHA_1_HMAC:
crv = sftk_doHMACInit(context, HASH_AlgSHA1, key, SHA1_LENGTH);
crv = sftk_doMACInit(pMechanism->mechanism, context, key, SHA1_LENGTH);
break;
case CKM_SSL3_MD5_MAC:
@ -3744,11 +3850,17 @@ nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism,
iv.len = 0;
if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PKCS5_PBKD2_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
pwitem.data = (unsigned char *)pbkd2_params->pPassword;
/* was this a typo in the PKCS #11 spec? */
pwitem.len = *pbkd2_params->ulPasswordLen;
} else {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PBE_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
pwitem.data = (unsigned char *)pbe_params->pPassword;
pwitem.len = pbe_params->ulPasswordLen;
@ -4048,6 +4160,10 @@ nsc_SetupHMACKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe)
PORT_FreeArena(arena, PR_TRUE);
return CKR_HOST_MEMORY;
}
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PBE_PARAMS))) {
PORT_FreeArena(arena, PR_TRUE);
return CKR_MECHANISM_PARAM_INVALID;
}
params->poolp = arena;
params->ivLen = 0;
@ -4127,10 +4243,10 @@ nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe,
}
if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
if (pbkd2_params == NULL) {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PKCS5_PBKD2_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
switch (pbkd2_params->prf) {
case CKP_PKCS5_PBKD2_HMAC_SHA1:
hashType = HASH_AlgSHA1;
@ -4157,6 +4273,9 @@ nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe,
salt.len = (unsigned int)pbkd2_params->ulSaltSourceDataLen;
iteration = pbkd2_params->iterations;
} else {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PBE_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
salt.data = (unsigned char *)pbe_params->pSalt;
salt.len = (unsigned int)pbe_params->ulSaltLen;
@ -4203,11 +4322,12 @@ nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe,
break;
default:
crv = CKR_MECHANISM_INVALID;
nsspkcs5_DestroyPBEParameter(params);
break;
}
if (crv == CKR_OK) {
*pbe = params;
} else {
nsspkcs5_DestroyPBEParameter(params);
}
return crv;
}
@ -4272,12 +4392,12 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
}
crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i]));
if (crv != CKR_OK)
if (crv != CKR_OK) {
break;
}
}
if (crv != CKR_OK) {
sftk_FreeObject(key);
return crv;
goto loser;
}
/* make sure we don't have any class, key_type, or value fields */
@ -4390,8 +4510,10 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
}
if (crv != CKR_OK) {
sftk_FreeObject(key);
return crv;
if (pbe_param) {
nsspkcs5_DestroyPBEParameter(pbe_param);
}
goto loser;
}
/* if there was no error,
@ -4409,6 +4531,10 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
break;
case nsc_ssl:
rsa_pms = (SSL3RSAPreMasterSecret *)buf;
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_VERSION))) {
crv = CKR_MECHANISM_PARAM_INVALID;
goto loser;
}
version = (CK_VERSION *)pMechanism->pParameter;
rsa_pms->client_version[0] = version->major;
rsa_pms->client_version[1] = version->minor;
@ -4427,6 +4553,10 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
crv = nsc_parameter_gen(key_type, key);
break;
case nsc_jpake:
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_NSS_JPAKERound1Params))) {
crv = CKR_MECHANISM_PARAM_INVALID;
goto loser;
}
crv = jpake_Round1(hashType,
(CK_NSS_JPAKERound1Params *)pMechanism->pParameter,
key);
@ -4434,34 +4564,30 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
}
if (crv != CKR_OK) {
sftk_FreeObject(key);
return crv;
goto loser;
}
/* Add the class, key_type, and value */
crv = sftk_AddAttributeType(key, CKA_CLASS, &objclass, sizeof(CK_OBJECT_CLASS));
if (crv != CKR_OK) {
sftk_FreeObject(key);
return crv;
goto loser;
}
crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE));
if (crv != CKR_OK) {
sftk_FreeObject(key);
return crv;
goto loser;
}
if (key_length != 0) {
crv = sftk_AddAttributeType(key, CKA_VALUE, buf, key_length);
if (crv != CKR_OK) {
sftk_FreeObject(key);
return crv;
goto loser;
}
}
/* get the session */
session = sftk_SessionFromHandle(hSession);
if (session == NULL) {
sftk_FreeObject(key);
return CKR_SESSION_HANDLE_INVALID;
crv = CKR_SESSION_HANDLE_INVALID;
goto loser;
}
/*
@ -4478,6 +4604,7 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
if (crv == CKR_OK) {
*phKey = key->handle;
}
loser:
sftk_FreeObject(key);
return crv;
}
@ -5591,8 +5718,8 @@ NSC_WrapKey(CK_SESSION_HANDLE hSession,
}
key = sftk_ObjectFromHandle(hKey, session);
sftk_FreeSession(session);
if (key == NULL) {
sftk_FreeSession(session);
return CKR_KEY_HANDLE_INVALID;
}
@ -5698,7 +5825,7 @@ NSC_WrapKey(CK_SESSION_HANDLE hSession,
break;
}
sftk_FreeObject(key);
sftk_FreeSession(session);
return sftk_mapWrap(crv);
}
@ -6507,7 +6634,6 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
CK_OBJECT_CLASS classType = CKO_SECRET_KEY;
CK_KEY_DERIVATION_STRING_DATA *stringPtr;
CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
PRBool isTLS = PR_FALSE;
PRBool isDH = PR_FALSE;
HASH_HashType tlsPrfHash = HASH_AlgNULL;
@ -6525,6 +6651,11 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (!slot) {
return CKR_SESSION_HANDLE_INVALID;
}
if (!pMechanism) {
return CKR_MECHANISM_PARAM_INVALID;
}
CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
/*
* now lets create an object to hang the attributes off of
*/
@ -6698,6 +6829,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if ((mechanism == CKM_TLS12_MASTER_KEY_DERIVE) ||
(mechanism == CKM_TLS12_MASTER_KEY_DERIVE_DH)) {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
CK_TLS12_MASTER_KEY_DERIVE_PARAMS *tls12_master =
(CK_TLS12_MASTER_KEY_DERIVE_PARAMS *)pMechanism->pParameter;
tlsPrfHash = GetHashTypeFromMechanism(tls12_master->prfHashMechanism);
@ -6965,6 +7100,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
if (mechanism == CKM_TLS12_KEY_AND_MAC_DERIVE) {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_TLS12_KEY_MAT_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
CK_TLS12_KEY_MAT_PARAMS *tls12_keys =
(CK_TLS12_KEY_MAT_PARAMS *)pMechanism->pParameter;
tlsPrfHash = GetHashTypeFromMechanism(tls12_keys->prfHashMechanism);
@ -7008,6 +7147,13 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
crv = CKR_HOST_MEMORY;
break;
}
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_SSL3_KEY_MAT_PARAMS))) {
MD5_DestroyContext(md5, PR_TRUE);
SHA1_DestroyContext(sha, PR_TRUE);
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *)pMechanism->pParameter;
PORT_Memcpy(srcrdata,
@ -7202,6 +7348,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_ULONG len;
if (mechanism == CKM_DES3_ECB_ENCRYPT_DATA) {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
pMechanism->pParameter;
mode = NSS_DES_EDE3;
@ -7251,10 +7401,18 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (mechanism == CKM_AES_ECB_ENCRYPT_DATA) {
mode = NSS_AES;
iv = NULL;
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
data = stringPtr->pData;
len = stringPtr->ulLen;
} else {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
aesEncryptPtr =
(CK_AES_CBC_ENCRYPT_DATA_PARAMS *)pMechanism->pParameter;
mode = NSS_AES_CBC;
@ -7287,6 +7445,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_ULONG len;
if (mechanism == CKM_CAMELLIA_ECB_ENCRYPT_DATA) {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
pMechanism->pParameter;
aesEncryptPtr = NULL;
@ -7295,6 +7457,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
len = stringPtr->ulLen;
iv = NULL;
} else {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
stringPtr = NULL;
aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
pMechanism->pParameter;
@ -7328,6 +7494,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_ULONG len;
if (mechanism == CKM_SEED_ECB_ENCRYPT_DATA) {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
mode = NSS_SEED;
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
pMechanism->pParameter;
@ -7336,6 +7506,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
len = stringPtr->ulLen;
iv = NULL;
} else {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
mode = NSS_SEED_CBC;
aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
pMechanism->pParameter;
@ -7427,6 +7601,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (crv != CKR_OK)
break;
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
tmpKeySize = att->attrib.ulValueLen + stringPtr->ulLen;
if (keySize == 0)
@ -7453,6 +7631,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (crv != CKR_OK)
break;
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
tmpKeySize = att->attrib.ulValueLen + stringPtr->ulLen;
if (keySize == 0)
@ -7479,6 +7661,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (crv != CKR_OK)
break;
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
tmpKeySize = PR_MIN(att->attrib.ulValueLen, stringPtr->ulLen);
if (keySize == 0)
@ -7503,6 +7689,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
break;
case CKM_EXTRACT_KEY_FROM_KEY: {
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_EXTRACT_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
/* the following assumes 8 bits per byte */
CK_ULONG extract = *(CK_EXTRACT_PARAMS *)pMechanism->pParameter;
CK_ULONG shift = extract & 0x7; /* extract mod 8 the fast way */

View file

@ -17,6 +17,9 @@
#include "chacha20poly1305.h"
#include "hasht.h"
#include "alghmac.h"
#include "cmac.h"
/*
* Configuration Defines
*
@ -458,7 +461,7 @@ struct SFTKItemTemplateStr {
#define SFTK_TOKEN_KRL_HANDLE (SFTK_TOKEN_MAGIC | SFTK_TOKEN_TYPE_CRL | 1)
/* how big (in bytes) a password/pin we can deal with */
#define SFTK_MAX_PIN 255
#define SFTK_MAX_PIN 500
/* minimum password/pin length (in Unicode characters) in FIPS mode */
#define FIPS_MIN_PIN 7
@ -595,6 +598,73 @@ typedef struct sftk_parametersStr {
#define CERT_DB_FMT "%scert%s.db"
#define KEY_DB_FMT "%skey%s.db"
struct sftk_MACConstantTimeCtxStr {
const SECHashObject *hash;
unsigned char mac[64];
unsigned char secret[64];
unsigned int headerLength;
unsigned int secretLength;
unsigned int totalLength;
unsigned char header[75];
};
typedef struct sftk_MACConstantTimeCtxStr sftk_MACConstantTimeCtx;
struct sftk_MACCtxStr {
/* This is a common MAC context that supports both HMAC and CMAC
* operations. This also presents a unified set of semantics:
*
* - Everything except Destroy returns a CK_RV, indicating success
* or failure. (This handles the difference between HMAC's and CMAC's
* interfaces, since the underlying AES _might_ fail with CMAC).
*
* - The underlying MAC is started on Init(...), so Update(...) can
* called right away. (This handles the difference between HMAC and
* CMAC in their *_Init(...) functions).
*
* - Calling semantics:
*
* - One of sftk_MAC_{Create,Init,InitRaw}(...) to set up the MAC
* context, checking the return code.
* - sftk_MAC_Update(...) as many times as necessary to process
* input data, checking the return code.
* - sftk_MAC_Finish(...) to get the output of the MAC; result_len
* may be NULL if the caller knows the expected output length,
* checking the return code. If result_len is NULL, this will
* PR_ASSERT(...) that the actual returned length was equal to
* max_result_len.
*
* Note: unlike HMAC_Finish(...), this allows the caller to specify
* a return value less than return length, to align with
* CMAC_Finish(...)'s semantics. This will force an additional
* stack allocation of size SFTK_MAX_MAC_LENGTH.
* - sftk_MAC_Reset(...) if the caller wishes to compute a new MAC
* with the same key, checking the return code.
* - sftk_MAC_Destroy(...) when the caller frees its associated
* memory, passing PR_TRUE if sftk_MAC_Create(...) was called,
* and PR_FALSE otherwise.
*/
CK_MECHANISM_TYPE mech;
unsigned int mac_size;
union {
HMACContext *hmac;
CMACContext *cmac;
/* Functions to update when adding a new MAC or a new hash:
*
* - sftk_MAC_Init
* - sftk_MAC_Update
* - sftk_MAC_Finish
* - sftk_MAC_Reset
*/
void *raw;
} mac;
void (*destroy_func)(void *ctx, PRBool free_it);
};
typedef struct sftk_MACCtxStr sftk_MACCtx;
SEC_BEGIN_PROTOS
/* shared functions between pkcs11.c and fipstokn.c */
@ -766,17 +836,6 @@ extern CK_RV jpake_Final(HASH_HashType hashType,
SFTKObject *sourceKey, SFTKObject *key);
/* Constant time MAC functions (hmacct.c) */
struct sftk_MACConstantTimeCtxStr {
const SECHashObject *hash;
unsigned char mac[64];
unsigned char secret[64];
unsigned int headerLength;
unsigned int secretLength;
unsigned int totalLength;
unsigned char header[75];
};
typedef struct sftk_MACConstantTimeCtxStr sftk_MACConstantTimeCtx;
sftk_MACConstantTimeCtx *sftk_HMACConstantTime_New(
CK_MECHANISM_PTR mech, SFTKObject *key);
sftk_MACConstantTimeCtx *sftk_SSLv3MACConstantTime_New(
@ -798,6 +857,16 @@ sftk_TLSPRFInit(SFTKSessionContext *context,
HASH_HashType hash_alg,
unsigned int out_len);
/* PKCS#11 MAC implementation. See sftk_MACCtxStr declaration above for
* calling semantics for these functions. */
CK_RV sftk_MAC_Create(CK_MECHANISM_TYPE mech, SFTKObject *key, sftk_MACCtx **ret_ctx);
CK_RV sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, SFTKObject *key);
CK_RV sftk_MAC_InitRaw(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, const unsigned char *key, unsigned int key_len, PRBool isFIPS);
CK_RV sftk_MAC_Update(sftk_MACCtx *ctx, CK_BYTE_PTR data, unsigned int data_len);
CK_RV sftk_MAC_Finish(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result_len, unsigned int max_result_len);
CK_RV sftk_MAC_Reset(sftk_MACCtx *ctx);
void sftk_MAC_Destroy(sftk_MACCtx *ctx, PRBool free_it);
SEC_END_PROTOS
#endif /* _PKCS11I_H_ */

View file

@ -141,7 +141,7 @@ sftk_DestroyAttribute(SFTKAttribute *attribute)
void
sftk_FreeAttribute(SFTKAttribute *attribute)
{
if (attribute->freeAttr) {
if (attribute && attribute->freeAttr) {
sftk_DestroyAttribute(attribute);
return;
}

View file

@ -159,7 +159,7 @@ static const CK_ATTRIBUTE_TYPE known_attributes[] = {
CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS,
CKA_PUBLIC_KEY_INFO
CKA_PUBLIC_KEY_INFO, CKA_NSS_SERVER_DISTRUST_AFTER, CKA_NSS_EMAIL_DISTRUST_AFTER
};
static int known_attributes_size = sizeof(known_attributes) /

View file

@ -530,6 +530,7 @@ sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle,
goto loser;
}
rv = sftkdb_SignAttribute(arena, &keyHandle->passwordKey,
keyHandle->defaultIterationCount,
objectID, template[i].type,
&plainText, &signText);
PZ_Unlock(keyHandle->passwordLock);
@ -663,6 +664,7 @@ sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
break;
}
rv = sftkdb_EncryptAttribute(arena, &handle->passwordKey,
handle->defaultIterationCount,
&plainText, &cipherText);
PZ_Unlock(handle->passwordLock);
if (rv == SECSuccess) {
@ -2449,7 +2451,7 @@ sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID)
* initialize a new database handle
*/
static SFTKDBHandle *
sftk_NewDBHandle(SDB *sdb, int type)
sftk_NewDBHandle(SDB *sdb, int type, PRBool legacy)
{
SFTKDBHandle *handle = PORT_New(SFTKDBHandle);
handle->ref = 1;
@ -2461,6 +2463,7 @@ sftk_NewDBHandle(SDB *sdb, int type)
handle->updatePasswordKey = NULL;
handle->updateID = NULL;
handle->type = type;
handle->usesLegacyStorage = legacy;
handle->passwordKey.data = NULL;
handle->passwordKey.len = 0;
handle->passwordLock = NULL;
@ -2620,6 +2623,7 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
PRBool newInit = PR_FALSE;
PRBool needUpdate = PR_FALSE;
char *nconfdir = NULL;
PRBool legacy = PR_TRUE;
if (!readOnly) {
flags = SDB_CREATE;
@ -2652,12 +2656,14 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
case NSS_DB_TYPE_EXTERN: /* SHOULD open a loadable db */
crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags,
noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit);
legacy = PR_FALSE;
/*
* if we failed to open the DB's read only, use the old ones if
* the exists.
*/
if (crv != CKR_OK) {
legacy = PR_TRUE;
if ((flags & SDB_RDONLY) == SDB_RDONLY) {
nconfdir = sftk_legacyPathFromSDBPath(confdir);
}
@ -2711,12 +2717,12 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
goto done;
}
if (!noCertDB) {
*certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE);
*certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE, legacy);
} else {
*certDB = NULL;
}
if (!noKeyDB) {
*keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE);
*keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE, legacy);
} else {
*keyDB = NULL;
}
@ -2759,7 +2765,7 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
(sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ? PR_TRUE : PR_FALSE;
/* if the password on the key db is NULL, kick off our update
* chain of events */
sftkdb_CheckPassword((*keyDB), "", &tokenRemoved);
sftkdb_CheckPasswordNull((*keyDB), &tokenRemoved);
} else {
/* we don't have a key DB, update the certificate DB now */
sftkdb_Update(*certDB, NULL);

View file

@ -25,6 +25,7 @@ CK_RV sftkdb_closeDB(SFTKDBHandle *handle);
SECStatus sftkdb_PWIsInitialized(SFTKDBHandle *keydb);
SECStatus sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw,
PRBool *tokenRemoved);
SECStatus sftkdb_CheckPasswordNull(SFTKDBHandle *keydb, PRBool *tokenRemoved);
SECStatus sftkdb_PWCached(SFTKDBHandle *keydb);
SECStatus sftkdb_HasPasswordSet(SFTKDBHandle *keydb);
SECStatus sftkdb_ResetKeyDB(SFTKDBHandle *keydb);
@ -69,3 +70,5 @@ SFTKDBHandle *sftk_getKeyDB(SFTKSlot *slot);
SFTKDBHandle *sftk_getDBForTokenObject(SFTKSlot *slot,
CK_OBJECT_HANDLE objectID);
void sftk_freeDB(SFTKDBHandle *certHandle);
PRBool sftk_isLegacyIterationCountAllowed(void);

View file

@ -13,7 +13,9 @@ struct SFTKDBHandleStr {
PRInt32 ref;
CK_OBJECT_HANDLE type;
SECItem passwordKey;
int defaultIterationCount;
SECItem *newKey;
int newDefaultIterationCount;
SECItem *oldKey;
SECItem *updatePasswordKey;
PZLock *passwordLock;
@ -21,6 +23,7 @@ struct SFTKDBHandleStr {
SDB *update;
char *updateID;
PRBool updateDBIsInit;
PRBool usesLegacyStorage;
};
#define SFTK_KEYDB_TYPE 0x40000000
@ -39,9 +42,10 @@ struct SFTKDBHandleStr {
SECStatus sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText,
SECItem **plainText);
SECStatus sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey,
SECItem *plainText, SECItem **cipherText);
int iterationCount, SECItem *plainText,
SECItem **cipherText);
SECStatus sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey,
CK_OBJECT_HANDLE objectID,
int iterationCount, CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE attrType,
SECItem *plainText, SECItem **sigText);
SECStatus sftkdb_VerifyAttribute(SECItem *passKey,

View file

@ -9,12 +9,14 @@
#include "softoken.h"
#include "hmacct.h"
/* MACMechanismToHash converts a PKCS#11 MAC mechanism into a freebl hash
/* HMACMechanismToHash converts a PKCS#11 MAC mechanism into a freebl hash
* type. */
static HASH_HashType
MACMechanismToHash(CK_MECHANISM_TYPE mech)
HMACMechanismToHash(CK_MECHANISM_TYPE mech)
{
switch (mech) {
case CKM_MD2_HMAC:
return HASH_AlgMD2;
case CKM_MD5_HMAC:
case CKM_SSL3_MD5_MAC:
return HASH_AlgMD5;
@ -48,7 +50,7 @@ SetupMAC(CK_MECHANISM_PTR mech, SFTKObject *key)
return NULL;
}
alg = MACMechanismToHash(params->macAlg);
alg = HMACMechanismToHash(params->macAlg);
if (alg == HASH_AlgNULL) {
return NULL;
}
@ -188,3 +190,284 @@ sftk_MACConstantTime_DestroyContext(void *pctx, PRBool free)
{
PORT_Free(pctx);
}
CK_RV
sftk_MAC_Create(CK_MECHANISM_TYPE mech, SFTKObject *key, sftk_MACCtx **ret_ctx)
{
CK_RV ret;
if (ret_ctx == NULL || key == NULL) {
return CKR_HOST_MEMORY;
}
*ret_ctx = PORT_New(sftk_MACCtx);
if (*ret_ctx == NULL) {
return CKR_HOST_MEMORY;
}
ret = sftk_MAC_Init(*ret_ctx, mech, key);
if (ret != CKR_OK) {
sftk_MAC_Destroy(*ret_ctx, PR_TRUE);
}
return ret;
}
CK_RV
sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, SFTKObject *key)
{
SFTKAttribute *keyval = NULL;
PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID);
CK_RV ret = CKR_OK;
/* Find the actual value of the key. */
keyval = sftk_FindAttribute(key, CKA_VALUE);
if (keyval == NULL) {
ret = CKR_KEY_SIZE_RANGE;
goto done;
}
ret = sftk_MAC_InitRaw(ctx, mech,
(const unsigned char *)keyval->attrib.pValue,
keyval->attrib.ulValueLen, isFIPS);
done:
sftk_FreeAttribute(keyval);
return ret;
}
CK_RV
sftk_MAC_InitRaw(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, const unsigned char *key, unsigned int key_len, PRBool isFIPS)
{
const SECHashObject *hashObj = NULL;
CK_RV ret = CKR_OK;
if (ctx == NULL) {
return CKR_HOST_MEMORY;
}
/* Clear the context before use. */
PORT_Memset(ctx, 0, sizeof(*ctx));
/* Save the mech. */
ctx->mech = mech;
/* Initialize the correct MAC context. */
switch (mech) {
case CKM_MD2_HMAC:
case CKM_MD5_HMAC:
case CKM_SHA_1_HMAC:
case CKM_SHA224_HMAC:
case CKM_SHA256_HMAC:
case CKM_SHA384_HMAC:
case CKM_SHA512_HMAC:
hashObj = HASH_GetRawHashObject(HMACMechanismToHash(mech));
/* Because we condition above only on hashes we know to be valid,
* hashObj should never be NULL. This assert is only useful when
* adding a new hash function (for which only partial support has
* been added); thus there is no need to turn it into an if and
* avoid the NULL dereference on the following line. */
PR_ASSERT(hashObj != NULL);
ctx->mac_size = hashObj->length;
goto hmac;
case CKM_AES_CMAC:
ctx->mac.cmac = CMAC_Create(CMAC_AES, key, key_len);
ctx->destroy_func = (void (*)(void *, PRBool))(&CMAC_Destroy);
/* Copy the behavior of sftk_doCMACInit here. */
if (ctx->mac.cmac == NULL) {
if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
ret = CKR_KEY_SIZE_RANGE;
goto done;
}
ret = CKR_HOST_MEMORY;
goto done;
}
ctx->mac_size = AES_BLOCK_SIZE;
goto done;
default:
ret = CKR_MECHANISM_PARAM_INVALID;
goto done;
}
hmac:
ctx->mac.hmac = HMAC_Create(hashObj, key, key_len, isFIPS);
ctx->destroy_func = (void (*)(void *, PRBool))(&HMAC_Destroy);
/* Copy the behavior of sftk_doHMACInit here. */
if (ctx->mac.hmac == NULL) {
if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
ret = CKR_KEY_SIZE_RANGE;
goto done;
}
ret = CKR_HOST_MEMORY;
goto done;
}
/* Semantics: HMAC and CMAC should behave the same. Begin HMAC now. */
HMAC_Begin(ctx->mac.hmac);
done:
/* Handle a failure: ctx->mac.raw should be NULL, but make sure
* destroy_func isn't set. */
if (ret != CKR_OK) {
ctx->destroy_func = NULL;
}
return ret;
}
CK_RV
sftk_MAC_Reset(sftk_MACCtx *ctx)
{
/* Useful for resetting the state of MAC prior to calling update again
*
* This lets the caller keep a single MAC instance and re-use it as long
* as the key stays the same. */
switch (ctx->mech) {
case CKM_MD2_HMAC:
case CKM_MD5_HMAC:
case CKM_SHA_1_HMAC:
case CKM_SHA224_HMAC:
case CKM_SHA256_HMAC:
case CKM_SHA384_HMAC:
case CKM_SHA512_HMAC:
HMAC_Begin(ctx->mac.hmac);
break;
case CKM_AES_CMAC:
if (CMAC_Begin(ctx->mac.cmac) != SECSuccess) {
return CKR_FUNCTION_FAILED;
}
break;
default:
/* This shouldn't happen -- asserting indicates partial support
* for a new MAC type. */
PR_ASSERT(PR_FALSE);
return CKR_FUNCTION_FAILED;
}
return CKR_OK;
}
CK_RV
sftk_MAC_Update(sftk_MACCtx *ctx, CK_BYTE_PTR data, unsigned int data_len)
{
switch (ctx->mech) {
case CKM_MD2_HMAC:
case CKM_MD5_HMAC:
case CKM_SHA_1_HMAC:
case CKM_SHA224_HMAC:
case CKM_SHA256_HMAC:
case CKM_SHA384_HMAC:
case CKM_SHA512_HMAC:
/* HMAC doesn't indicate failure in the return code. */
HMAC_Update(ctx->mac.hmac, data, data_len);
break;
case CKM_AES_CMAC:
/* CMAC indicates failure in the return code, however this is
* unlikely to occur. */
if (CMAC_Update(ctx->mac.cmac, data, data_len) != SECSuccess) {
return CKR_FUNCTION_FAILED;
}
break;
default:
/* This shouldn't happen -- asserting indicates partial support
* for a new MAC type. */
PR_ASSERT(PR_FALSE);
return CKR_FUNCTION_FAILED;
}
return CKR_OK;
}
CK_RV
sftk_MAC_Finish(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result_len, unsigned int max_result_len)
{
unsigned int actual_result_len;
switch (ctx->mech) {
case CKM_MD2_HMAC:
case CKM_MD5_HMAC:
case CKM_SHA_1_HMAC:
case CKM_SHA224_HMAC:
case CKM_SHA256_HMAC:
case CKM_SHA384_HMAC:
case CKM_SHA512_HMAC:
/* HMAC doesn't indicate failure in the return code. Additionally,
* unlike CMAC, it doesn't support partial results. This means that we
* need to allocate a buffer if max_result_len < ctx->mac_size. */
if (max_result_len >= ctx->mac_size) {
/* Split this into two calls to avoid an unnecessary stack
* allocation and memcpy when possible. */
HMAC_Finish(ctx->mac.hmac, result, &actual_result_len, max_result_len);
} else {
uint8_t tmp_buffer[SFTK_MAX_MAC_LENGTH];
/* Assumption: buffer is large enough to hold this HMAC's
* output. */
PR_ASSERT(SFTK_MAX_MAC_LENGTH >= ctx->mac_size);
HMAC_Finish(ctx->mac.hmac, tmp_buffer, &actual_result_len, SFTK_MAX_MAC_LENGTH);
if (actual_result_len > max_result_len) {
/* This should always be true since:
*
* (SFTK_MAX_MAC_LENGTH >= ctx->mac_size =
* actual_result_len) > max_result_len,
*
* but guard this truncation just in case. */
actual_result_len = max_result_len;
}
PORT_Memcpy(result, tmp_buffer, actual_result_len);
}
break;
case CKM_AES_CMAC:
/* CMAC indicates failure in the return code, however this is
* unlikely to occur. */
if (CMAC_Finish(ctx->mac.cmac, result, &actual_result_len, max_result_len) != SECSuccess) {
return CKR_FUNCTION_FAILED;
}
break;
default:
/* This shouldn't happen -- asserting indicates partial support
* for a new MAC type. */
PR_ASSERT(PR_FALSE);
return CKR_FUNCTION_FAILED;
}
if (result_len) {
/* When result length is passed, inform the caller of its value. */
*result_len = actual_result_len;
} else if (max_result_len == ctx->mac_size) {
/* Validate that the amount requested was what was actually given; the
* caller assumes that what they passed was the output size of the
* underlying MAC and that they got all the bytes the asked for. */
PR_ASSERT(actual_result_len == max_result_len);
}
return CKR_OK;
}
void
sftk_MAC_Destroy(sftk_MACCtx *ctx, PRBool free_it)
{
if (ctx == NULL) {
return;
}
if (ctx->mac.raw != NULL && ctx->destroy_func != NULL) {
ctx->destroy_func(ctx->mac.raw, PR_TRUE);
}
/* Clean up the struct so we don't double free accidentally. */
PORT_Memset(ctx, 0, sizeof(sftk_MACCtx));
if (free_it == PR_TRUE) {
PORT_Free(ctx);
}
}

View file

@ -34,6 +34,41 @@
#include "secerr.h"
#include "softoken.h"
static const int NSS_MP_PBE_ITERATION_COUNT = 10000;
static int
getPBEIterationCount(void)
{
int c = NSS_MP_PBE_ITERATION_COUNT;
char *val = getenv("NSS_MIN_MP_PBE_ITERATION_COUNT");
if (val) {
int minimum = atoi(val);
if (c < minimum) {
c = minimum;
}
}
val = getenv("NSS_MAX_MP_PBE_ITERATION_COUNT");
if (val) {
int maximum = atoi(val);
if (c > maximum) {
c = maximum;
}
}
return c;
}
PRBool
sftk_isLegacyIterationCountAllowed(void)
{
static const char *legacyCountEnvVar =
"NSS_ALLOW_LEGACY_DBM_ITERATION_COUNT";
char *iterEnv = getenv(legacyCountEnvVar);
return (iterEnv && strcmp("0", iterEnv) != 0);
}
/******************************************************************
*
* Key DB password handling functions
@ -132,7 +167,7 @@ const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate[] = {
* to data in cipherText, if cipherText is freed, cipherValue will be invalid.
*/
static SECStatus
sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue)
sftkdb_decodeCipherText(const SECItem *cipherText, sftkCipherValue *cipherValue)
{
PLArenaPool *arena = NULL;
SFTKDBEncryptedDataInfo edi;
@ -225,7 +260,8 @@ loser:
* with SECITEM_FreeItem by the caller.
*/
SECStatus
sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText, SECItem **plain)
sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText,
SECItem **plain)
{
SECStatus rv;
sftkCipherValue cipherValue;
@ -235,6 +271,7 @@ sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText, SECItem **plain)
if (rv != SECSuccess) {
goto loser;
}
/* fprintf(stderr, "sftkdb_DecryptAttribute iteration: %d\n", cipherValue.param->iter); */
*plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value,
PR_FALSE, NULL);
@ -261,7 +298,8 @@ loser:
*/
SECStatus
sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey,
SECItem *plainText, SECItem **cipherText)
int iterationCount, SECItem *plainText,
SECItem **cipherText)
{
SECStatus rv;
sftkCipherValue cipherValue;
@ -275,7 +313,7 @@ sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey,
RNG_GenerateGlobalRandomBytes(saltData, cipherValue.salt.len);
param = nsspkcs5_NewParam(cipherValue.alg, HASH_AlgSHA1, &cipherValue.salt,
1);
iterationCount);
if (param == NULL) {
rv = SECFailure;
goto loser;
@ -413,7 +451,8 @@ loser:
*/
SECStatus
sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey,
CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
int iterationCount, CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE attrType,
SECItem *plainText, SECItem **signature)
{
SECStatus rv;
@ -446,7 +485,8 @@ sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey,
RNG_GenerateGlobalRandomBytes(saltData, prfLength);
/* initialize our pkcs5 parameter */
param = nsspkcs5_NewParam(signValue.alg, HASH_AlgSHA1, &signValue.salt, 1);
param = nsspkcs5_NewParam(signValue.alg, HASH_AlgSHA1, &signValue.salt,
iterationCount);
if (param == NULL) {
rv = SECFailure;
goto loser;
@ -491,7 +531,7 @@ loser:
* and sftkdb_DecryptAttribute calls.
*/
static void
sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey)
sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey, int iterationCount)
{
unsigned char *data;
int len;
@ -507,6 +547,7 @@ sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey)
len = keydb->passwordKey.len;
keydb->passwordKey.data = passKey->data;
keydb->passwordKey.len = passKey->len;
keydb->defaultIterationCount = iterationCount;
passKey->data = data;
passKey->len = len;
SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock));
@ -660,6 +701,90 @@ sftkdb_HasPasswordSet(SFTKDBHandle *keydb)
return (crv == CKR_OK) ? SECSuccess : SECFailure;
}
/* pull out the common final part of checking a password */
SECStatus
sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key,
const char *pw, SECItem *value,
PRBool *tokenRemoved);
/*
* check to see if we have the NULL password set.
* We special case the NULL password so that if you have no password set, you
* don't do thousands of hash rounds. This allows us to startup and get
* webpages without slowdown in normal mode.
*/
SECStatus
sftkdb_CheckPasswordNull(SFTKDBHandle *keydb, PRBool *tokenRemoved)
{
/* just like sftkdb_CheckPassowd, we get the salt and value, and
* create a dbkey */
SECStatus rv;
SECItem salt, value;
unsigned char saltData[SDB_MAX_META_DATA_LEN];
unsigned char valueData[SDB_MAX_META_DATA_LEN];
SECItem key;
SDB *db;
CK_RV crv;
sftkCipherValue cipherValue;
cipherValue.param = NULL;
cipherValue.arena = NULL;
if (keydb == NULL) {
return SECFailure;
}
db = sftk_getPWSDB(keydb);
if (db == NULL) {
return SECFailure;
}
key.data = NULL;
key.len = 0;
/* get the entry from the database */
salt.data = saltData;
salt.len = sizeof(saltData);
value.data = valueData;
value.len = sizeof(valueData);
crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
if (crv != CKR_OK) {
rv = SECFailure;
goto done;
}
/* get our intermediate key based on the entry salt value */
rv = sftkdb_passwordToKey(keydb, &salt, "", &key);
if (rv != SECSuccess) {
goto done;
}
/* First get the cipher type */
rv = sftkdb_decodeCipherText(&value, &cipherValue);
if (rv != SECSuccess) {
goto done;
}
if (cipherValue.param->iter != 1) {
rv = SECFailure;
goto done;
}
rv = sftkdb_finishPasswordCheck(keydb, &key, "", &value, tokenRemoved);
done:
if (key.data) {
PORT_ZFree(key.data, key.len);
}
if (cipherValue.param) {
nsspkcs5_DestroyPBEParameter(cipherValue.param);
}
if (cipherValue.arena) {
PORT_FreeArena(cipherValue.arena, PR_FALSE);
}
return rv;
}
#define SFTK_PW_CHECK_STRING "password-check"
#define SFTK_PW_CHECK_LEN 14
@ -674,7 +799,6 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
unsigned char saltData[SDB_MAX_META_DATA_LEN];
unsigned char valueData[SDB_MAX_META_DATA_LEN];
SECItem key;
SECItem *result = NULL;
SDB *db;
CK_RV crv;
@ -710,8 +834,33 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
goto done;
}
rv = sftkdb_finishPasswordCheck(keydb, &key, pw, &value, tokenRemoved);
done:
if (key.data) {
PORT_ZFree(key.data, key.len);
}
return rv;
}
/* we need to pass iterationCount in case we are updating a new database
* and from an old one. */
SECStatus
sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key, const char *pw,
SECItem *value, PRBool *tokenRemoved)
{
SECItem *result = NULL;
SECStatus rv;
int iterationCount = getPBEIterationCount();
if (*pw == 0) {
iterationCount = 1;
} else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) {
iterationCount = 1;
}
/* decrypt the entry value */
rv = sftkdb_DecryptAttribute(&key, &value, &result);
rv = sftkdb_DecryptAttribute(key, value, &result);
if (rv != SECSuccess) {
goto done;
}
@ -752,7 +901,7 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
* as well as changing which database is returned from
* SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword()
* and sftkdb_HasPasswordSet()) */
keydb->updatePasswordKey = SECITEM_DupItem(&key);
keydb->updatePasswordKey = SECITEM_DupItem(key);
PZ_Unlock(keydb->passwordLock);
if (keydb->updatePasswordKey == NULL) {
/* PORT_Error set by SECITEM_DupItem */
@ -787,7 +936,7 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
* are good to go */
goto done;
}
sftkdb_CheckPassword(keydb, "", tokenRemoved);
sftkdb_CheckPasswordNull(keydb, tokenRemoved);
/*
* Important 'NULL' code here. At this point either we
@ -821,15 +970,15 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
PZ_Unlock(keydb->passwordLock);
}
/* load the keys, so the keydb can parse it's key set */
sftkdb_switchKeys(keydb, &key);
sftkdb_switchKeys(keydb, key, iterationCount);
/* we need to update, do it now */
if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) {
/* update the peer certdb if it exists */
if (keydb->peerDB) {
sftkdb_Update(keydb->peerDB, &key);
sftkdb_Update(keydb->peerDB, key);
}
sftkdb_Update(keydb, &key);
sftkdb_Update(keydb, key);
}
} else {
rv = SECFailure;
@ -837,9 +986,6 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
}
done:
if (key.data) {
PORT_ZFree(key.data, key.len);
}
if (result) {
SECITEM_FreeItem(result, PR_TRUE);
}
@ -857,7 +1003,7 @@ sftkdb_PWCached(SFTKDBHandle *keydb)
static CK_RV
sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
CK_OBJECT_HANDLE id, SECItem *newKey)
CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount)
{
SFTKDBHandle *keyHandle = handle;
SDB *keyTarget = NULL;
@ -924,7 +1070,8 @@ sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
SECItem plainText;
plainText.data = authAttr.pValue;
plainText.len = authAttr.ulValueLen;
if (sftkdb_SignAttribute(arena, newKey, id, authAttr.type, &plainText,
if (sftkdb_SignAttribute(arena, newKey, iterationCount, id,
authAttr.type, &plainText,
&signText) != SECSuccess) {
return CKR_GENERAL_ERROR;
}
@ -939,7 +1086,7 @@ sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
static CK_RV
sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
CK_OBJECT_HANDLE id, SECItem *newKey)
CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount)
{
CK_ATTRIBUTE_TYPE privAttrTypes[] = {
CKA_VALUE,
@ -980,7 +1127,8 @@ sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
SECItem *result;
plainText.data = privAttr.pValue;
plainText.len = privAttr.ulValueLen;
if (sftkdb_EncryptAttribute(arena, newKey, &plainText, &result) != SECSuccess) {
if (sftkdb_EncryptAttribute(arena, newKey, iterationCount,
&plainText, &result) != SECSuccess) {
return CKR_GENERAL_ERROR;
}
privAttr.pValue = result->data;
@ -991,6 +1139,7 @@ sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
// Write the newly encrypted attributes out directly.
CK_OBJECT_HANDLE newId = id & SFTK_OBJ_ID_MASK;
keydb->newKey = newKey;
keydb->newDefaultIterationCount = iterationCount;
crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, newId, &privAttr, 1);
keydb->newKey = NULL;
if (crv != CKR_OK) {
@ -1002,8 +1151,8 @@ sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
}
static CK_RV
sftk_convertAttributes(SFTKDBHandle *handle,
CK_OBJECT_HANDLE id, SECItem *newKey)
sftk_convertAttributes(SFTKDBHandle *handle, CK_OBJECT_HANDLE id,
SECItem *newKey, int iterationCount)
{
CK_RV crv = CKR_OK;
PLArenaPool *arena = NULL;
@ -1017,13 +1166,14 @@ sftk_convertAttributes(SFTKDBHandle *handle,
/*
* first handle the MACS
*/
crv = sftk_updateMacs(arena, handle, id, newKey);
crv = sftk_updateMacs(arena, handle, id, newKey, iterationCount);
if (crv != CKR_OK) {
goto loser;
}
if (handle->type == SFTK_KEYDB_TYPE) {
crv = sftk_updateEncrypted(arena, handle, id, newKey);
crv = sftk_updateEncrypted(arena, handle, id, newKey,
iterationCount);
if (crv != CKR_OK) {
goto loser;
}
@ -1045,7 +1195,7 @@ loser:
*/
CK_RV
sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template,
CK_ULONG count, SECItem *newKey)
CK_ULONG count, SECItem *newKey, int iterationCount)
{
SDBFind *find = NULL;
CK_ULONG idCount = SFTK_MAX_IDS;
@ -1061,7 +1211,8 @@ sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template,
while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) {
crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount);
for (i = 0; (crv == CKR_OK) && (i < idCount); i++) {
crv = sftk_convertAttributes(handle, ids[i], newKey);
crv = sftk_convertAttributes(handle, ids[i], newKey,
iterationCount);
}
}
crv2 = sftkdb_FindObjectsFinal(handle, find);
@ -1086,6 +1237,7 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
SFTKDBHandle *certdb;
unsigned char saltData[SDB_MAX_META_DATA_LEN];
unsigned char valueData[SDB_MAX_META_DATA_LEN];
int iterationCount = getPBEIterationCount();
CK_RV crv;
SDB *db;
@ -1121,6 +1273,12 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
RNG_GenerateGlobalRandomBytes(salt.data, salt.len);
}
if (newPin && *newPin == 0) {
iterationCount = 1;
} else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) {
iterationCount = 1;
}
rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
if (rv != SECSuccess) {
goto loser;
@ -1129,7 +1287,7 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
/*
* convert encrypted entries here.
*/
crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey);
crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey, iterationCount);
if (crv != CKR_OK) {
rv = SECFailure;
goto loser;
@ -1141,13 +1299,15 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
CK_OBJECT_CLASS myClass = CKO_NETSCAPE_TRUST;
objectType.pValue = &myClass;
crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey,
iterationCount);
if (crv != CKR_OK) {
rv = SECFailure;
goto loser;
}
myClass = CKO_PUBLIC_KEY;
crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey,
iterationCount);
if (crv != CKR_OK) {
rv = SECFailure;
goto loser;
@ -1157,7 +1317,8 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
plainText.len = SFTK_PW_CHECK_LEN;
rv = sftkdb_EncryptAttribute(NULL, &newKey, &plainText, &result);
rv = sftkdb_EncryptAttribute(NULL, &newKey, iterationCount,
&plainText, &result);
if (rv != SECSuccess) {
goto loser;
}
@ -1176,7 +1337,7 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
keydb->newKey = NULL;
sftkdb_switchKeys(keydb, &newKey);
sftkdb_switchKeys(keydb, &newKey, iterationCount);
loser:
if (newKey.data) {
@ -1201,7 +1362,7 @@ sftkdb_ClearPassword(SFTKDBHandle *keydb)
SECItem oldKey;
oldKey.data = NULL;
oldKey.len = 0;
sftkdb_switchKeys(keydb, &oldKey);
sftkdb_switchKeys(keydb, &oldKey, 1);
if (oldKey.data) {
PORT_ZFree(oldKey.data, oldKey.len);
}

View file

@ -17,10 +17,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define SOFTOKEN_VERSION "3.44.3" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VERSION "3.48" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VMAJOR 3
#define SOFTOKEN_VMINOR 44
#define SOFTOKEN_VPATCH 3
#define SOFTOKEN_VMINOR 48
#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE