diff options
Diffstat (limited to 'security/nss/lib/softoken/sftkpwd.c')
-rw-r--r-- | security/nss/lib/softoken/sftkpwd.c | 193 |
1 files changed, 160 insertions, 33 deletions
diff --git a/security/nss/lib/softoken/sftkpwd.c b/security/nss/lib/softoken/sftkpwd.c index 9834d3ba0..b6d098a07 100644 --- a/security/nss/lib/softoken/sftkpwd.c +++ b/security/nss/lib/softoken/sftkpwd.c @@ -34,6 +34,14 @@ #include "secerr.h" #include "softoken.h" +const int NSS_DEFAULT_ITERATION_COUNT = +#ifdef DEBUG + 25 +#else + 500 +#endif + ; + /****************************************************************** * * Key DB password handling functions @@ -132,7 +140,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 +233,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; @@ -261,7 +270,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 +285,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 +423,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 +457,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 +503,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 +519,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 +673,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 +771,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 +806,30 @@ 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 = NSS_DEFAULT_ITERATION_COUNT; + + if (*pw == 0) { + 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 +870,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 +905,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 +939,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 +955,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 +972,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) { CK_ATTRIBUTE authAttrs[] = { { CKA_MODULUS, NULL, 0 }, @@ -937,7 +1052,7 @@ sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle, plainText.data = authAttrs[i].pValue; plainText.len = authAttrs[i].ulValueLen; - rv = sftkdb_SignAttribute(arena, newKey, id, + rv = sftkdb_SignAttribute(arena, newKey, iterationCount, id, authAttrs[i].type, &plainText, &signText); if (rv != SECSuccess) { return CKR_GENERAL_ERROR; @@ -954,7 +1069,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_RV crv = CKR_OK; CK_RV crv2; @@ -1041,7 +1156,8 @@ sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb, plainText.data = first[i].pValue; plainText.len = first[i].ulValueLen; - rv = sftkdb_EncryptAttribute(arena, newKey, &plainText, &result); + rv = sftkdb_EncryptAttribute(arena, newKey, iterationCount, + &plainText, &result); if (rv != SECSuccess) { return CKR_GENERAL_ERROR; } @@ -1056,6 +1172,7 @@ sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb, */ id &= SFTK_OBJ_ID_MASK; keydb->newKey = newKey; + keydb->newDefaultIterationCount = iterationCount; crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count); keydb->newKey = NULL; @@ -1063,8 +1180,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; @@ -1078,13 +1195,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; } @@ -1106,7 +1224,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; @@ -1122,7 +1240,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); @@ -1147,6 +1266,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 = NSS_DEFAULT_ITERATION_COUNT; CK_RV crv; SDB *db; @@ -1182,6 +1302,10 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb, RNG_GenerateGlobalRandomBytes(salt.data, salt.len); } + if (newPin && *newPin == 0) { + iterationCount = 1; + } + rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey); if (rv != SECSuccess) { goto loser; @@ -1190,7 +1314,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; @@ -1202,13 +1326,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; @@ -1218,7 +1344,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; } @@ -1237,7 +1364,7 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb, keydb->newKey = NULL; - sftkdb_switchKeys(keydb, &newKey); + sftkdb_switchKeys(keydb, &newKey, iterationCount); loser: if (newKey.data) { @@ -1262,7 +1389,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); } |