diff options
Diffstat (limited to 'security/nss/lib/softoken/sftkpwd.c')
-rw-r--r-- | security/nss/lib/softoken/sftkpwd.c | 307 |
1 files changed, 140 insertions, 167 deletions
diff --git a/security/nss/lib/softoken/sftkpwd.c b/security/nss/lib/softoken/sftkpwd.c index b6d098a07..f2acf7664 100644 --- a/security/nss/lib/softoken/sftkpwd.c +++ b/security/nss/lib/softoken/sftkpwd.c @@ -34,13 +34,40 @@ #include "secerr.h" #include "softoken.h" -const int NSS_DEFAULT_ITERATION_COUNT = -#ifdef DEBUG - 25 -#else - 500 -#endif - ; +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); +} /****************************************************************** * @@ -244,6 +271,7 @@ sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText, 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); @@ -682,7 +710,7 @@ sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key, /* * 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 + * don't do thousands of hash rounds. This allows us to startup and get * webpages without slowdown in normal mode. */ SECStatus @@ -823,11 +851,14 @@ sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key, const char *pw, { SECItem *result = NULL; SECStatus rv; - int iterationCount = NSS_DEFAULT_ITERATION_COUNT; + 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); if (rv != SECSuccess) { @@ -974,92 +1005,78 @@ static CK_RV sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle, CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount) { - CK_ATTRIBUTE authAttrs[] = { - { CKA_MODULUS, NULL, 0 }, - { CKA_PUBLIC_EXPONENT, NULL, 0 }, - { CKA_CERT_SHA1_HASH, NULL, 0 }, - { CKA_CERT_MD5_HASH, NULL, 0 }, - { CKA_TRUST_SERVER_AUTH, NULL, 0 }, - { CKA_TRUST_CLIENT_AUTH, NULL, 0 }, - { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 }, - { CKA_TRUST_CODE_SIGNING, NULL, 0 }, - { CKA_TRUST_STEP_UP_APPROVED, NULL, 0 }, - { CKA_NSS_OVERRIDE_EXTENSIONS, NULL, 0 }, - }; - CK_ULONG authAttrCount = sizeof(authAttrs) / sizeof(CK_ATTRIBUTE); - unsigned int i, count; SFTKDBHandle *keyHandle = handle; SDB *keyTarget = NULL; - - id &= SFTK_OBJ_ID_MASK; - if (handle->type != SFTK_KEYDB_TYPE) { keyHandle = handle->peerDB; } - if (keyHandle == NULL) { return CKR_OK; } - - /* old DB's don't have meta data, finished with MACs */ + // Old DBs don't have metadata, so we can return early here. keyTarget = SFTK_GET_SDB(keyHandle); if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) { return CKR_OK; } - /* - * STEP 1: find the MACed attributes of this object - */ - (void)sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount); - count = 0; - /* allocate space for the attributes */ - for (i = 0; i < authAttrCount; i++) { - if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)) { - continue; - } - count++; - authAttrs[i].pValue = PORT_ArenaAlloc(arena, authAttrs[i].ulValueLen); - if (authAttrs[i].pValue == NULL) { - break; - } - } - - /* if count was zero, none were found, finished with MACs */ - if (count == 0) { - return CKR_OK; - } - - (void)sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount); - /* ignore error code, we expect some possible errors */ + id &= SFTK_OBJ_ID_MASK; - /* GetAttributeValue just verified the old macs, safe to write - * them out then... */ - for (i = 0; i < authAttrCount; i++) { - SECItem *signText; - SECItem plainText; - SECStatus rv; + CK_ATTRIBUTE_TYPE authAttrTypes[] = { + CKA_MODULUS, + CKA_PUBLIC_EXPONENT, + CKA_CERT_SHA1_HASH, + CKA_CERT_MD5_HASH, + CKA_TRUST_SERVER_AUTH, + CKA_TRUST_CLIENT_AUTH, + CKA_TRUST_EMAIL_PROTECTION, + CKA_TRUST_CODE_SIGNING, + CKA_TRUST_STEP_UP_APPROVED, + CKA_NSS_OVERRIDE_EXTENSIONS, + }; + const CK_ULONG authAttrTypeCount = sizeof(authAttrTypes) / sizeof(authAttrTypes[0]); - if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)) { + // We don't know what attributes this object has, so we update them one at a + // time. + unsigned int i; + for (i = 0; i < authAttrTypeCount; i++) { + CK_ATTRIBUTE authAttr = { authAttrTypes[i], NULL, 0 }; + CK_RV rv = sftkdb_GetAttributeValue(handle, id, &authAttr, 1); + if (rv != CKR_OK) { continue; } - - if (authAttrs[i].ulValueLen == sizeof(CK_ULONG) && - sftkdb_isULONGAttribute(authAttrs[i].type)) { - CK_ULONG value = *(CK_ULONG *)authAttrs[i].pValue; - sftk_ULong2SDBULong(authAttrs[i].pValue, value); - authAttrs[i].ulValueLen = SDB_ULONG_SIZE; + if ((authAttr.ulValueLen == -1) || (authAttr.ulValueLen == 0)) { + continue; } - - plainText.data = authAttrs[i].pValue; - plainText.len = authAttrs[i].ulValueLen; - rv = sftkdb_SignAttribute(arena, newKey, iterationCount, id, - authAttrs[i].type, &plainText, &signText); - if (rv != SECSuccess) { + authAttr.pValue = PORT_ArenaAlloc(arena, authAttr.ulValueLen); + if (authAttr.pValue == NULL) { + return CKR_HOST_MEMORY; + } + rv = sftkdb_GetAttributeValue(handle, id, &authAttr, 1); + if (rv != CKR_OK) { + return rv; + } + if ((authAttr.ulValueLen == -1) || (authAttr.ulValueLen == 0)) { return CKR_GENERAL_ERROR; } - rv = sftkdb_PutAttributeSignature(handle, keyTarget, id, - authAttrs[i].type, signText); - if (rv != SECSuccess) { + // GetAttributeValue just verified the old macs, so it is safe to write + // them out now. + if (authAttr.ulValueLen == sizeof(CK_ULONG) && + sftkdb_isULONGAttribute(authAttr.type)) { + CK_ULONG value = *(CK_ULONG *)authAttr.pValue; + sftk_ULong2SDBULong(authAttr.pValue, value); + authAttr.ulValueLen = SDB_ULONG_SIZE; + } + SECItem *signText; + SECItem plainText; + plainText.data = authAttr.pValue; + plainText.len = authAttr.ulValueLen; + if (sftkdb_SignAttribute(arena, newKey, iterationCount, id, + authAttr.type, &plainText, + &signText) != SECSuccess) { + return CKR_GENERAL_ERROR; + } + if (sftkdb_PutAttributeSignature(handle, keyTarget, id, authAttr.type, + signText) != SECSuccess) { return CKR_GENERAL_ERROR; } } @@ -1071,112 +1088,66 @@ static CK_RV sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb, CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount) { - CK_RV crv = CKR_OK; - CK_RV crv2; - CK_ATTRIBUTE *first, *last; - CK_ATTRIBUTE privAttrs[] = { - { CKA_VALUE, NULL, 0 }, - { CKA_PRIVATE_EXPONENT, NULL, 0 }, - { CKA_PRIME_1, NULL, 0 }, - { CKA_PRIME_2, NULL, 0 }, - { CKA_EXPONENT_1, NULL, 0 }, - { CKA_EXPONENT_2, NULL, 0 }, - { CKA_COEFFICIENT, NULL, 0 } + CK_ATTRIBUTE_TYPE privAttrTypes[] = { + CKA_VALUE, + CKA_PRIVATE_EXPONENT, + CKA_PRIME_1, + CKA_PRIME_2, + CKA_EXPONENT_1, + CKA_EXPONENT_2, + CKA_COEFFICIENT, }; - CK_ULONG privAttrCount = sizeof(privAttrs) / sizeof(CK_ATTRIBUTE); - unsigned int i, count; + const CK_ULONG privAttrCount = sizeof(privAttrTypes) / sizeof(privAttrTypes[0]); - /* - * STEP 1. Read the old attributes in the clear. - */ - - /* Get the attribute sizes. - * ignore the error code, we will have unknown attributes here */ - crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount); - - /* - * find the valid block of attributes and fill allocate space for - * their data */ - first = last = NULL; + // We don't know what attributes this object has, so we update them one at a + // time. + unsigned int i; for (i = 0; i < privAttrCount; i++) { - /* find the block of attributes that are appropriate for this - * objects. There should only be once contiguous block, if not - * there's an error. - * - * find the first and last good entry. - */ - if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)) { - if (!first) - continue; - if (!last) { - /* previous entry was last good entry */ - last = &privAttrs[i - 1]; - } + // Read the old attribute in the clear. + CK_ATTRIBUTE privAttr = { privAttrTypes[i], NULL, 0 }; + CK_RV crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1); + if (crv != CKR_OK) { continue; } - if (!first) { - first = &privAttrs[i]; + if ((privAttr.ulValueLen == -1) || (privAttr.ulValueLen == 0)) { + continue; } - if (last) { - /* OOPS, we've found another good entry beyond the end of the - * last good entry, we need to fail here. */ - crv = CKR_GENERAL_ERROR; - break; + privAttr.pValue = PORT_ArenaAlloc(arena, privAttr.ulValueLen); + if (privAttr.pValue == NULL) { + return CKR_HOST_MEMORY; } - privAttrs[i].pValue = PORT_ArenaAlloc(arena, privAttrs[i].ulValueLen); - if (privAttrs[i].pValue == NULL) { - crv = CKR_HOST_MEMORY; - break; + crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1); + if (crv != CKR_OK) { + return crv; + } + if ((privAttr.ulValueLen == -1) || (privAttr.ulValueLen == 0)) { + return CKR_GENERAL_ERROR; } - } - if (first == NULL) { - /* no valid entries found, return error based on crv2 */ - return crv2; - } - if (last == NULL) { - last = &privAttrs[privAttrCount - 1]; - } - if (crv != CKR_OK) { - return crv; - } - /* read the attributes */ - count = (last - first) + 1; - crv = sftkdb_GetAttributeValue(keydb, id, first, count); - if (crv != CKR_OK) { - return crv; - } - - /* - * STEP 2: read the encrypt the attributes with the new key. - */ - for (i = 0; i < count; i++) { SECItem plainText; SECItem *result; - SECStatus rv; - - plainText.data = first[i].pValue; - plainText.len = first[i].ulValueLen; - rv = sftkdb_EncryptAttribute(arena, newKey, iterationCount, - &plainText, &result); - if (rv != SECSuccess) { + plainText.data = privAttr.pValue; + plainText.len = privAttr.ulValueLen; + if (sftkdb_EncryptAttribute(arena, newKey, iterationCount, + &plainText, &result) != SECSuccess) { return CKR_GENERAL_ERROR; } - first[i].pValue = result->data; - first[i].ulValueLen = result->len; - /* clear our sensitive data out */ + privAttr.pValue = result->data; + privAttr.ulValueLen = result->len; + // Clear sensitive data. PORT_Memset(plainText.data, 0, plainText.len); - } - /* - * STEP 3: write the newly encrypted attributes out directly - */ - id &= SFTK_OBJ_ID_MASK; - keydb->newKey = newKey; - keydb->newDefaultIterationCount = iterationCount; - crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count); - keydb->newKey = NULL; + // 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) { + return crv; + } + } - return crv; + return CKR_OK; } static CK_RV @@ -1266,7 +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 = NSS_DEFAULT_ITERATION_COUNT; + int iterationCount = getPBEIterationCount(); CK_RV crv; SDB *db; @@ -1304,6 +1275,8 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb, if (newPin && *newPin == 0) { iterationCount = 1; + } else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) { + iterationCount = 1; } rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey); |