summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/softoken/sftkpwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/softoken/sftkpwd.c')
-rw-r--r--security/nss/lib/softoken/sftkpwd.c307
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);