Commit 4703a817 authored by Robert Relyea's avatar Robert Relyea

Bug 1585189 - Changed the algorithm used to encrypt NSS database entries, from 3DES to AES256.

Our NSS DB uses 3DES internally to encrypt their entries.
This patch changes the default algorithm for AES256 to increase the security.
This patch also adds code to use AES Wrap in the future. It also adds an integrity
check to the AES256 CBC. The change only affects sqlite databases.

bob

Differential Revision: https://phabricator.services.mozilla.com/D54589
parent f699f5c1
......@@ -2251,6 +2251,12 @@ lg_PutMetaData(SDB *sdb, const char *id,
return CKR_OK;
}
CK_RV
lg_DestroyMetaData(SDB *db, const char *id)
{
return CKR_GENERAL_ERROR; /* no extra data stored */
}
CK_RV
lg_Reset(SDB *sdb)
{
......
......@@ -960,6 +960,22 @@ lg_createKeyObject(SDB *sdb, CK_OBJECT_CLASS objclass,
return CKR_ATTRIBUTE_VALUE_INVALID;
}
/*
* return the 'next' key handle
*/
CK_RV
lg_GetNewObjectID(SDB *sdb, CK_OBJECT_HANDLE *handle)
{
/* the upper level needs the Object ID early to populate any
* signature attributes. The legacy can't really return a new
* handle without the full object template (chicken and egg issue).
* Fortunately we can just return a bogus handle because the legacy
* database doesn't support meta data and can't store any of the signed
* attributes anyway */
*handle = CK_INVALID_HANDLE;
return CKR_OK;
}
/*
* Parse the template and create an object stored in the DB that reflects.
* the object specified in the database.
......
......@@ -150,6 +150,8 @@ CK_RV lg_Abort(SDB *sdb);
CK_RV lg_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2);
CK_RV lg_PutMetaData(SDB *sdb, const char *id,
const SECItem *item1, const SECItem *item2);
CK_RV lg_DestroyMetaData(SDB *sdb, const char *id);
CK_RV lg_GetNewObjectID(SDB *sdb, CK_OBJECT_HANDLE *object_id);
SEC_END_PROTOS
......
......@@ -519,7 +519,7 @@ lg_init(SDB **pSdb, int flags, NSSLOWCERTCertDBHandle *certdbPtr,
}
sdb->private = lgdb_p;
sdb->version = 0;
sdb->version = 1;
sdb->sdb_flags = flags;
sdb->app_private = NULL;
sdb->sdb_FindObjectsInit = lg_FindObjectsInit;
......@@ -531,12 +531,14 @@ lg_init(SDB **pSdb, int flags, NSSLOWCERTCertDBHandle *certdbPtr,
sdb->sdb_DestroyObject = lg_DestroyObject;
sdb->sdb_GetMetaData = lg_GetMetaData;
sdb->sdb_PutMetaData = lg_PutMetaData;
sdb->sdb_DestroyMetaData = lg_DestroyMetaData;
sdb->sdb_Begin = lg_Begin;
sdb->sdb_Commit = lg_Commit;
sdb->sdb_Abort = lg_Abort;
sdb->sdb_Reset = lg_Reset;
sdb->sdb_Close = lg_Close;
sdb->sdb_SetForkState = lg_SetForkState;
sdb->sdb_GetNewObjectID = lg_GetNewObjectID;
*pSdb = sdb;
return CKR_OK;
......
......@@ -205,7 +205,8 @@ sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText,
iterationCount = 1;
}
rv = sftkdb_EncryptAttribute(arena, key, iterationCount,
rv = sftkdb_EncryptAttribute(arena, handle, sdb, key, iterationCount,
CK_INVALID_HANDLE, CKT_INVALID_TYPE,
plainText, cipherText);
PZ_Unlock(handle->passwordLock);
......@@ -227,7 +228,7 @@ sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText)
return SECFailure;
}
/* if we aren't th handle, try the other handle */
/* if we aren't the key handle, try the other handle */
oldKey = handle->oldKey;
if (handle->type != SFTK_KEYDB_TYPE) {
handle = handle->peerDB;
......@@ -244,7 +245,9 @@ sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText)
/* PORT_SetError */
return SECFailure;
}
rv = sftkdb_DecryptAttribute(oldKey ? oldKey : &handle->passwordKey,
rv = sftkdb_DecryptAttribute(NULL, oldKey ? oldKey : &handle->passwordKey,
CK_INVALID_HANDLE,
CKT_INVALID_TYPE,
cipherText, plainText);
PZ_Unlock(handle->passwordLock);
......
This diff is collapsed.
......@@ -101,6 +101,7 @@ extern void
nsspkcs5_DestroyPBEParameter(NSSPKCS5PBEParameter *param);
HASH_HashType HASH_FromHMACOid(SECOidTag oid);
SECOidTag HASH_HMACOidFromHash(HASH_HashType);
SEC_END_PROTOS
......
......@@ -1613,68 +1613,6 @@ NSC_DecryptUpdate(CK_SESSION_HANDLE hSession,
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. */
CK_RV
NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
......@@ -1714,9 +1652,10 @@ NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
crv = sftk_MapDecryptError(PORT_GetError());
} else {
unsigned int padSize = 0;
crv = sftk_CheckCBCPadding(&pLastPart[outlen - context->blockSize], context->blockSize, &padSize);
crv = sftk_CheckCBCPadding(pLastPart, outlen,
context->blockSize, &padSize);
/* Update pulLastPartLen, in constant time, if crv is OK */
*pulLastPartLen = CT_SEL(CK_RVToMask(crv), outlen - padSize, *pulLastPartLen);
*pulLastPartLen = CT_SEL(sftk_CKRVToMask(crv), outlen - padSize, *pulLastPartLen);
}
}
}
......@@ -1768,7 +1707,7 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
finalLen = maxoutlen;
crv2 = NSC_DecryptFinal(hSession, pData, &finalLen);
if (crv == CKR_OK) {
*pulDataLen = CT_SEL(CK_RVToMask(crv2), updateLen + finalLen, *pulDataLen);
*pulDataLen = CT_SEL(sftk_CKRVToMask(crv2), updateLen + finalLen, *pulDataLen);
return crv2;
} else {
return crv;
......@@ -1782,9 +1721,10 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
if (rv == SECSuccess) {
if (context->doPad) {
unsigned int padSize = 0;
crv = sftk_CheckCBCPadding(&pData[outlen - context->blockSize], context->blockSize, &padSize);
crv = sftk_CheckCBCPadding(pData, outlen, context->blockSize,
&padSize);
/* Update pulDataLen, in constant time, if crv is OK */
*pulDataLen = CT_SEL(CK_RVToMask(crv), outlen - padSize, *pulDataLen);
*pulDataLen = CT_SEL(sftk_CKRVToMask(crv), outlen - padSize, *pulDataLen);
} else {
*pulDataLen = (CK_ULONG)outlen;
}
......
......@@ -71,6 +71,17 @@
* before we start freeing them */
#define MAX_KEY_LEN 256 /* maximum symmetric key length in bytes */
/* From ssl3con.c: Constant-time helper macro that copies the MSB of x to all
* * other bits. */
#define CT_DUPLICATE_MSB_TO_ALL(x) ((unsigned int)((int)(x) >> (sizeof(int) * 8 - 1)))
/* 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) (CT_DUPLICATE_MSB_TO_ALL(((x) | (0 - x))))
/*
* LOG2_BUCKETS_PER_SESSION_LOCK must be a prime number.
* With SESSION_HASH_SIZE=1024, LOG2 can be 9, 5, 1, or 0.
......@@ -867,6 +878,10 @@ CK_RV sftk_MAC_Finish(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result
CK_RV sftk_MAC_Reset(sftk_MACCtx *ctx);
void sftk_MAC_Destroy(sftk_MACCtx *ctx, PRBool free_it);
/* constant time helpers */
unsigned int sftk_CKRVToMask(CK_RV rv);
CK_RV sftk_CheckCBCPadding(CK_BYTE_PTR pBuf, unsigned int bufLen,
unsigned int blockSize, unsigned int *outPadSize);
SEC_END_PROTOS
#endif /* _PKCS11I_H_ */
......@@ -1249,7 +1249,7 @@ sftk_DeleteObject(SFTKSession *session, SFTKObject *object)
SFTKTokenObject *to = sftk_narrowToTokenObject(object);
PORT_Assert(to);
#endif
crv = sftkdb_DestroyObject(handle, object->handle);
crv = sftkdb_DestroyObject(handle, object->handle, object->objclass);
sftk_freeDB(handle);
}
return crv;
......@@ -2010,3 +2010,54 @@ sftk_narrowToTokenObject(SFTKObject *obj)
{
return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;
}
/* Constant time helper functions */
/* sftk_CKRVToMask returns, in constant time, a mask value of
* all ones if rv == CKR_OK. Otherwise it returns zero. */
unsigned int
sftk_CKRVToMask(CK_RV rv)
{
PR_STATIC_ASSERT(CKR_OK == 0);
return ~CT_NOT_ZERO(rv);
}
/* sftk_CheckCBCPadding checks, in constant time, the padding validity and
* accordingly sets the pad length. */
CK_RV
sftk_CheckCBCPadding(CK_BYTE_PTR pBuf, unsigned int bufLen,
unsigned int blockSize, unsigned int *outPadSize)
{
PORT_Assert(outPadSize);
unsigned int padSize = (unsigned int)pBuf[bufLen - 1];
/* If padSize <= blockSize, set goodPad to all-1s and all-0s otherwise.*/
unsigned int goodPad = CT_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 = CT_DUPLICATE_MSB_TO_ALL(~(padSize - 1 - i));
/* Get the padding value (should be padSize) from buffer */
unsigned int padVal = pBuf[bufLen - 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 = CT_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);
}
......@@ -1161,6 +1161,19 @@ sdb_getObjectId(SDB *sdb)
return CK_INVALID_HANDLE;
}
CK_RV
sdb_GetNewObjectID(SDB *sdb, CK_OBJECT_HANDLE *object)
{
CK_OBJECT_HANDLE id;
id = sdb_getObjectId(sdb);
if (id == CK_INVALID_HANDLE) {
return CKR_DEVICE_MEMORY; /* basically we ran out of resources */
}
*object = id;
return CKR_OK;
}
static const char CREATE_CMD[] = "INSERT INTO %s (id%s) VALUES($ID%s);";
CK_RV
sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id,
......@@ -1268,10 +1281,13 @@ loser:
return error;
}
/*
* Generic destroy that can destroy metadata or objects
*/
static const char DESTROY_CMD[] = "DELETE FROM %s WHERE (id=$ID);";
CK_RV
sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id)
sdb_destroyAnyObject(SDB *sdb, const char *table,
CK_OBJECT_HANDLE object_id, const char *string_id)
{
SDBPrivate *sdb_p = sdb->private;
sqlite3 *sqlDB = NULL;
......@@ -1290,7 +1306,7 @@ sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id)
if (error != CKR_OK) {
goto loser;
}
newStr = sqlite3_mprintf(DESTROY_CMD, sdb_p->table);
newStr = sqlite3_mprintf(DESTROY_CMD, table);
if (newStr == NULL) {
error = CKR_HOST_MEMORY;
goto loser;
......@@ -1299,7 +1315,12 @@ sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id)
sqlite3_free(newStr);
if (sqlerr != SQLITE_OK)
goto loser;
sqlerr = sqlite3_bind_int(stmt, 1, object_id);
if (string_id == NULL) {
sqlerr = sqlite3_bind_int(stmt, 1, object_id);
} else {
sqlerr = sqlite3_bind_text(stmt, 1, string_id,
PORT_Strlen(string_id), SQLITE_STATIC);
}
if (sqlerr != SQLITE_OK)
goto loser;
......@@ -1328,6 +1349,19 @@ loser:
return error;
}
CK_RV
sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id)
{
SDBPrivate *sdb_p = sdb->private;
return sdb_destroyAnyObject(sdb, sdb_p->table, object_id, NULL);
}
CK_RV
sdb_DestroyMetaData(SDB *sdb, const char *id)
{
return sdb_destroyAnyObject(sdb, "metaData", 0, id);
}
static const char BEGIN_CMD[] = "BEGIN IMMEDIATE TRANSACTION;";
/*
......@@ -2044,7 +2078,7 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
sdb_p->sqlXactDB = NULL;
sdb_p->sqlXactThread = NULL;
sdb->private = sdb_p;
sdb->version = 0;
sdb->version = 1;
sdb->sdb_flags = inFlags | SDB_HAS_META;
sdb->app_private = NULL;
sdb->sdb_FindObjectsInit = sdb_FindObjectsInit;
......@@ -2056,12 +2090,14 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
sdb->sdb_DestroyObject = sdb_DestroyObject;
sdb->sdb_GetMetaData = sdb_GetMetaData;
sdb->sdb_PutMetaData = sdb_PutMetaData;
sdb->sdb_DestroyMetaData = sdb_DestroyMetaData;
sdb->sdb_Begin = sdb_Begin;
sdb->sdb_Commit = sdb_Commit;
sdb->sdb_Abort = sdb_Abort;
sdb->sdb_Reset = sdb_Reset;
sdb->sdb_Close = sdb_Close;
sdb->sdb_SetForkState = sdb_SetForkState;
sdb->sdb_GetNewObjectID = sdb_GetNewObjectID;
if (inTransaction) {
sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL);
......
......@@ -75,6 +75,10 @@ struct SDBStr {
CK_RV(*sdb_Close)
(SDB *sdb);
void (*sdb_SetForkState)(PRBool forked);
CK_RV(*sdb_GetNewObjectID)
(SDB *db, CK_OBJECT_HANDLE *object);
CK_RV(*sdb_DestroyMetaData)
(SDB *db, const char *id);
};
CK_RV s_open(const char *directory, const char *certPrefix,
......
This diff is collapsed.
......@@ -17,7 +17,8 @@ CK_RV sftkdb_GetAttributeValue(SFTKDBHandle *handle,
CK_OBJECT_HANDLE object_id, CK_ATTRIBUTE *template, CK_ULONG count);
CK_RV sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object,
const CK_ATTRIBUTE *template, CK_ULONG count);
CK_RV sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id);
CK_RV sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id,
CK_OBJECT_CLASS objclass);
CK_RV sftkdb_closeDB(SFTKDBHandle *handle);
/* keydb functions */
......
......@@ -39,16 +39,26 @@ struct SFTKDBHandleStr {
#define SFTK_GET_SDB(handle) \
((handle)->update ? (handle)->update : (handle)->db)
SECStatus sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText,
SECItem **plainText);
SECStatus sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey,
int iterationCount, SECItem *plainText,
SECItem **cipherText);
SECStatus sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey,
SECStatus sftkdb_DecryptAttribute(SFTKDBHandle *handle,
SECItem *passKey,
CK_OBJECT_HANDLE id,
CK_ATTRIBUTE_TYPE attrType,
SECItem *cipherText, SECItem **plainText);
SECStatus sftkdb_EncryptAttribute(PLArenaPool *arena,
SFTKDBHandle *handle, SDB *db,
SECItem *passKey,
int iterationCount,
CK_OBJECT_HANDLE id,
CK_ATTRIBUTE_TYPE attrType,
SECItem *plainText, SECItem **cipherText);
SECStatus sftkdb_SignAttribute(PLArenaPool *arena,
SFTKDBHandle *handle, SDB *db,
SECItem *passKey,
int iterationCount, CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE attrType,
SECItem *plainText, SECItem **sigText);
SECStatus sftkdb_VerifyAttribute(SECItem *passKey,
SECStatus sftkdb_VerifyAttribute(SFTKDBHandle *handle,
SECItem *passKey,
CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE attrType,
SECItem *plainText, SECItem *sigText);
......@@ -59,5 +69,14 @@ CK_RV sftkdb_Update(SFTKDBHandle *handle, SECItem *key);
CK_RV sftkdb_PutAttributeSignature(SFTKDBHandle *handle,
SDB *keyTarget, CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE type, SECItem *signText);
CK_RV sftkdb_GetAttributeSignature(SFTKDBHandle *handle,
SFTKDBHandle *keyHandle,
CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE type,
SECItem *signText);
CK_RV
sftkdb_DestroyAttributeSignature(SFTKDBHandle *handle, SDB *db,
CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE type);
#endif
......@@ -260,18 +260,19 @@ loser:
* with SECITEM_FreeItem by the caller.
*/
SECStatus
sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText,
SECItem **plain)
sftkdb_DecryptAttribute(SFTKDBHandle *handle, SECItem *passKey,
CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type,
SECItem *cipherText, SECItem **plain)
{
SECStatus rv;
sftkCipherValue cipherValue;
/* First get the cipher type */
*plain = NULL;
rv = sftkdb_decodeCipherText(cipherText, &cipherValue);
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);
......@@ -280,6 +281,33 @@ sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText,
goto loser;
}
/* If we are using aes 256, we need to check authentication as well.*/
if ((type != CKT_INVALID_TYPE) && (cipherValue.alg == SEC_OID_AES_256_CBC)) {
SECItem signature;
unsigned char signData[SDB_MAX_META_DATA_LEN];
/* if we get here from the old legacy db, there is clearly an
* error, don't return the plaintext */
if (handle == NULL) {
rv = SECFailure;
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
signature.data = signData;
signature.len = sizeof(signData);
rv = sftkdb_GetAttributeSignature(handle, handle, id, type,
&signature);
if (rv != SECSuccess) {
goto loser;
}
rv = sftkdb_VerifyAttribute(handle, passKey, CK_INVALID_HANDLE, type,
*plain, &signature);
if (rv != SECSuccess) {
goto loser;
}
}
loser:
if (cipherValue.param) {
nsspkcs5_DestroyPBEParameter(cipherValue.param);
......@@ -287,9 +315,36 @@ loser:
if (cipherValue.arena) {
PORT_FreeArena(cipherValue.arena, PR_FALSE);
}
/* Item decrypted, but failed integrity, clear it out */
if (*plain && rv != SECSuccess) {
SECITEM_ZfreeItem(*plain, PR_TRUE);
*plain = NULL;
}
return rv;
}
/* If the database can't store the integrity check, it's a non-FIPS database
* and we use the old encryption scheme for it */
static PRBool
sftkdb_useLegacyEncryption(SFTKDBHandle *handle, SDB *db)
{
if ((handle == NULL) || (db == NULL)) {
/* this is the case where the legacy db is calling back to us to
* encrypt or decrypt attributes inside the lower level db code.
* This is because the legacy db stored keys as pkcs #8 encrypted
* blobs rather than individual encrypted attributes */
return PR_TRUE;
}
/* currently, only the legacy db can't store meta data, but if we
* add a new db that also can't store meta data, then it to wouldn't
* be able to do the integrity checks. In both cases use the old encryption
* algorithms. */
if ((db->sdb_flags & SDB_HAS_META) == 0) {
return PR_TRUE;
}
return PR_FALSE;
}
/*
* encrypt a block. This function returned the encrypted ciphertext which
* the caller must free. If the caller provides an arena, cipherText will
......@@ -297,22 +352,32 @@ loser:
* salt automatically.
*/
SECStatus
sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey,
int iterationCount, SECItem *plainText,
SECItem **cipherText)
sftkdb_EncryptAttribute(PLArenaPool *arena, SFTKDBHandle *handle, SDB *db,
SECItem *passKey, int iterationCount,
CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type,
SECItem *plainText, SECItem **cipherText)
{
SECStatus rv;
sftkCipherValue cipherValue;
SECItem *cipher = NULL;
NSSPKCS5PBEParameter *param = NULL;
unsigned char saltData[HASH_LENGTH_MAX];
SECItem *signature = NULL;
HASH_HashType hashType = HASH_AlgNULL;
cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
cipherValue.salt.len = SHA1_LENGTH;
if (sftkdb_useLegacyEncryption(handle, db)) {
cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
cipherValue.salt.len = SHA1_LENGTH;
hashType = HASH_AlgSHA1;
} else {
cipherValue.alg = SEC_OID_AES_256_CBC;
cipherValue.salt.len = SHA256_LENGTH;
hashType = HASH_AlgSHA256;
}
cipherValue.salt.data = saltData;
RNG_GenerateGlobalRandomBytes(saltData, cipherValue.salt.len);
param = nsspkcs5_NewParam(cipherValue.alg, HASH_AlgSHA1, &cipherValue.salt,
param = nsspkcs5_NewParam(cipherValue.alg, hashType, &cipherValue.salt,
iterationCount);
if (param == NULL) {
rv = SECFailure;
......@@ -331,7 +396,26 @@ sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey,
goto loser;
}
/* If we are using aes 256, we need to add authentication as well */
if ((type != CKT_INVALID_TYPE) &&
(cipherValue.param->encAlg == SEC_OID_AES_256_CBC)) {
rv = sftkdb_SignAttribute(arena, handle, db, passKey, iterationCount,
CK_INVALID_HANDLE, type, plainText,
&signature);
if (rv != SECSuccess) {
goto loser;
}
rv = sftkdb_PutAttributeSignature(handle, db, id, type,
signature);
if (rv != SECSuccess) {
goto loser;
}
}
loser:
if ((arena == NULL) && signature) {
SECITEM_FreeItem(cipher, PR_TRUE);
}
if (cipher) {
SECITEM_FreeItem(cipher, PR_TRUE);
}
......@@ -408,7 +492,8 @@ loser:
* plainText is the plainText of the attribute.
*/
SECStatus
sftkdb_VerifyAttribute(SECItem *passKey, CK_OBJECT_HANDLE objectID,
sftkdb_VerifyAttribute(SFTKDBHandle *handle,
SECItem *passKey, CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE attrType,
SECItem *plainText, SECItem *signText)
{
......@@ -450,8 +535,9 @@ loser:
* attribute. The signText is a PKCS 5 v2 pbe.
*/
SECStatus
sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey,
int iterationCount, CK_OBJECT_HANDLE objectID,
sftkdb_SignAttribute(PLArenaPool *arena, SFTKDBHandle *keyDB, SDB *db,
SECItem *passKey, int iterationCount,
CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE_TYPE attrType,
SECItem *plainText, SECItem **signature)
{
......@@ -860,7 +946,8 @@ sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key, const char *pw,
}
/* decrypt the entry value */
rv = sftkdb_DecryptAttribute(key, value, &result);
rv = sftkdb_DecryptAttribute(keydb, key, CK_INVALID_HANDLE,
CKT_INVALID_TYPE, value, &result);
if (rv != SECSuccess) {
goto done;
}
......@@ -1070,9 +1157,9 @@ sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
SECItem plainText;
plainText.data = authAttr.pValue;
plainText.len = authAttr.ulValueLen;
if (sftkdb_SignAttribute(arena, newKey, iterationCount, id,
authAttr.type, &plainText,
&signText) != SECSuccess) {
if (sftkdb_SignAttribute(arena, handle, keyTarget, newKey,
iterationCount, id, authAttr.type,
&plainText, &signText) != SECSuccess) {
return CKR_GENERAL_ERROR;
}
if (sftkdb_PutAttributeSignature(handle, keyTarget, id, authAttr.type,
......@@ -1127,7 +1214,8 @@ sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
SECItem *result;
plainText.data = privAttr.pValue;
plainText.len = privAttr.ulValueLen;
if (sftkdb_EncryptAttribute(arena, newKey, iterationCount,
if (sftkdb_EncryptAttribute(arena, keydb, keydb->db, newKey,
iterationCount, id, privAttr.type,
&plainText, &result) != SECSuccess) {
return CKR_GENERAL_ERROR;
}
......@@ -1317,8 +1405,9 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
plainText.len = SFTK_PW_CHECK_LEN;
rv = sftkdb_EncryptAttribute(NULL, &newKey, iterationCount,
&plainText, &result);
rv = sftkdb_EncryptAttribute(NULL, keydb, keydb->db, &newKey,
iterationCount, CK_INVALID_HANDLE,
CKT_INVALID_TYPE, &plainText, &result);
if (rv != SECSuccess) {
goto loser;
}
......
......@@ -138,6 +138,7 @@
/* FAKE PKCS #11 defines */
#define CKM_FAKE_RANDOM 0x80000efeUL
#define CKM_INVALID_MECHANISM 0xffffffffUL
#define CKT_INVALID_TYPE 0xffffffffUL
/*
* NSS-defined crypto mechanisms
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment