summaryrefslogtreecommitdiff
path: root/security/nss/lib/softoken
diff options
context:
space:
mode:
authorrrelyea%redhat.com <devnull@localhost>2007-08-09 22:36:20 +0000
committerrrelyea%redhat.com <devnull@localhost>2007-08-09 22:36:20 +0000
commit2536c68d5ab6ca467691176855f9e715ab68d8ea (patch)
tree6cf084c8d8aae6b5bc78f527e30abf9cd12d5c26 /security/nss/lib/softoken
parent84bcb3e77a502e07b3f92e64d6f4d9aacf804398 (diff)
downloadnss-hg-2536c68d5ab6ca467691176855f9e715ab68d8ea.tar.gz
Bug 391291 Implement Shared Database Integrity checks.
r=nelson (plus review from kengert)
Diffstat (limited to 'security/nss/lib/softoken')
-rw-r--r--security/nss/lib/softoken/legacydb/keydb.c29
-rw-r--r--security/nss/lib/softoken/legacydb/lgdb.h5
-rw-r--r--security/nss/lib/softoken/legacydb/lginit.c4
-rw-r--r--security/nss/lib/softoken/legacydb/lowkeyti.h9
-rw-r--r--security/nss/lib/softoken/lowpbe.c306
-rw-r--r--security/nss/lib/softoken/lowpbe.h5
-rw-r--r--security/nss/lib/softoken/padbuf.c13
-rw-r--r--security/nss/lib/softoken/pkcs11c.c87
-rw-r--r--security/nss/lib/softoken/pkcs11t.h15
-rw-r--r--security/nss/lib/softoken/sdb.c115
-rw-r--r--security/nss/lib/softoken/sdb.h14
-rw-r--r--security/nss/lib/softoken/sftkdb.c664
-rw-r--r--security/nss/lib/softoken/sftkdbt.h2
-rw-r--r--security/nss/lib/softoken/softoken.h15
14 files changed, 1049 insertions, 234 deletions
diff --git a/security/nss/lib/softoken/legacydb/keydb.c b/security/nss/lib/softoken/legacydb/keydb.c
index 51bb402c8..d64d9080e 100644
--- a/security/nss/lib/softoken/legacydb/keydb.c
+++ b/security/nss/lib/softoken/legacydb/keydb.c
@@ -1355,7 +1355,7 @@ loser:
* check to see if the user has a password
*/
static SECStatus
-nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle,SDBPasswordEntry *entry)
+nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle,NSSLOWKEYPasswordEntry *entry)
{
DBT checkkey; /*, checkdata; */
NSSLOWKEYDBKey *dbkey = NULL;
@@ -1427,7 +1427,7 @@ loser:
* check to see if the user has a password
*/
static SECStatus
-nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle,SDBPasswordEntry *entry)
+nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle,NSSLOWKEYPasswordEntry *entry)
{
DBT checkkey;
NSSLOWKEYDBKey *dbkey = NULL;
@@ -2224,33 +2224,50 @@ keydb_Close(NSSLOWKEYDBHandle *kdb)
*/
CK_RV
-lg_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry)
+lg_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2)
{
NSSLOWKEYDBHandle *keydb;
+ NSSLOWKEYPasswordEntry entry;
SECStatus rv;
keydb = lg_getKeyDB(sdb);
if (keydb == NULL) {
return CKR_TOKEN_WRITE_PROTECTED;
}
- rv = nsslowkey_GetPWCheckEntry(keydb, entry);
+ if (PORT_Strcmp(id,"password") != 0) {
+ /* shouldn't happen */
+ return CKR_GENERAL_ERROR; /* no extra data stored */
+ }
+ rv = nsslowkey_GetPWCheckEntry(keydb, &entry);
if (rv != SECSuccess) {
return CKR_GENERAL_ERROR;
}
+ item1->len = entry.salt.len;
+ PORT_Memcpy(item1->data, entry.salt.data, item1->len);
+ item2->len = entry.value.len;
+ PORT_Memcpy(item2->data, entry.value.data, item2->len);
return CKR_OK;
}
CK_RV
-lg_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry)
+lg_PutMetaData(SDB *sdb, const char *id,
+ const SECItem *item1, const SECItem *item2)
{
NSSLOWKEYDBHandle *keydb;
+ NSSLOWKEYPasswordEntry entry;
SECStatus rv;
keydb = lg_getKeyDB(sdb);
if (keydb == NULL) {
return CKR_TOKEN_WRITE_PROTECTED;
}
- rv = nsslowkey_PutPWCheckEntry(keydb, entry);
+ if (PORT_Strcmp(id,"password") != 0) {
+ /* shouldn't happen */
+ return CKR_GENERAL_ERROR; /* no extra data stored */
+ }
+ entry.salt = *item1;
+ entry.value = *item2;
+ rv = nsslowkey_PutPWCheckEntry(keydb, &entry);
if (rv != SECSuccess) {
return CKR_GENERAL_ERROR;
}
diff --git a/security/nss/lib/softoken/legacydb/lgdb.h b/security/nss/lib/softoken/legacydb/lgdb.h
index 2369acd94..207b7aecf 100644
--- a/security/nss/lib/softoken/legacydb/lgdb.h
+++ b/security/nss/lib/softoken/legacydb/lgdb.h
@@ -189,8 +189,9 @@ CK_RV lg_Reset(SDB *sdb);
CK_RV lg_Begin(SDB *sdb);
CK_RV lg_Commit(SDB *sdb);
CK_RV lg_Abort(SDB *sdb);
-CK_RV lg_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry);
-CK_RV lg_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry);
+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);
SEC_END_PROTOS
diff --git a/security/nss/lib/softoken/legacydb/lginit.c b/security/nss/lib/softoken/legacydb/lginit.c
index 060579b91..3964f6ee7 100644
--- a/security/nss/lib/softoken/legacydb/lginit.c
+++ b/security/nss/lib/softoken/legacydb/lginit.c
@@ -546,8 +546,8 @@ lg_init(SDB **pSdb, int flags, NSSLOWCERTCertDBHandle *certdbPtr,
sdb->sdb_SetAttributeValue = lg_SetAttributeValue;
sdb->sdb_CreateObject = lg_CreateObject;
sdb->sdb_DestroyObject = lg_DestroyObject;
- sdb->sdb_GetPWEntry = lg_GetPWEntry;
- sdb->sdb_PutPWEntry = lg_PutPWEntry;
+ sdb->sdb_GetMetaData = lg_GetMetaData;
+ sdb->sdb_PutMetaData = lg_PutMetaData;
sdb->sdb_Begin = lg_Begin;
sdb->sdb_Commit = lg_Commit;
sdb->sdb_Abort = lg_Abort;
diff --git a/security/nss/lib/softoken/legacydb/lowkeyti.h b/security/nss/lib/softoken/legacydb/lowkeyti.h
index 57f8105e3..7fa74da72 100644
--- a/security/nss/lib/softoken/legacydb/lowkeyti.h
+++ b/security/nss/lib/softoken/legacydb/lowkeyti.h
@@ -158,4 +158,13 @@ struct NSSLOWKEYPrivateKeyStr {
};
typedef struct NSSLOWKEYPrivateKeyStr NSSLOWKEYPrivateKey;
+
+typedef struct NSSLOWKEYPasswordEntryStr NSSLOWKEYPasswordEntry;
+struct NSSLOWKEYPasswordEntryStr {
+ SECItem salt;
+ SECItem value;
+ unsigned char data[128];
+};
+
+
#endif /* _LOWKEYTI_H_ */
diff --git a/security/nss/lib/softoken/lowpbe.c b/security/nss/lib/softoken/lowpbe.c
index 6b4605b4e..778834156 100644
--- a/security/nss/lib/softoken/lowpbe.c
+++ b/security/nss/lib/softoken/lowpbe.c
@@ -74,6 +74,42 @@ static const SEC_ASN1Template NSSPKCS5PKCS12V2PBEParameterTemplate[] =
{ 0 }
};
+
+/* PKCS5 v2 */
+
+struct nsspkcs5V2PBEParameterStr {
+ SECAlgorithmID keyParams; /* parameters of the key generation */
+ SECAlgorithmID algParams; /* paramters for the encryption or mac op */
+};
+
+typedef struct nsspkcs5V2PBEParameterStr nsspkcs5V2PBEParameter;
+#define PBKDF2
+
+#ifdef PBKDF2
+static const SEC_ASN1Template NSSPKCS5V2PBES2ParameterTemplate[] =
+{
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(nsspkcs5V2PBEParameter) },
+ { SEC_ASN1_INLINE, offsetof(nsspkcs5V2PBEParameter, keyParams),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_INLINE, offsetof(nsspkcs5V2PBEParameter, algParams),
+ SECOID_AlgorithmIDTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template NSSPKCS5V2PBEParameterTemplate[] =
+{
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSPKCS5PBEParameter) },
+ /* this is really a choice, but since we don't understand any other
+ *choice, just inline it. */
+ { SEC_ASN1_OCTET_STRING, offsetof(NSSPKCS5PBEParameter, salt) },
+ { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, iteration) },
+ { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, keyLength) },
+ { SEC_ASN1_INLINE, offsetof(NSSPKCS5PBEParameter, prfAlg),
+ SECOID_AlgorithmIDTemplate },
+ { 0 }
+};
+#endif
+
SECStatus
nsspkcs5_HashBuf(const SECHashObject *hashObj, unsigned char *dest,
unsigned char *src, int len)
@@ -297,28 +333,16 @@ nsspkcs5_PBKDF1Extended(const SECHashObject *hashObj,
/*
* PBDKDF2 is PKCS #5 v2.0 it's currently not used by NSS
*/
-/*
- * We This is safe because hLen for all our
- * HMAC algorithms are multiples of 4.
- */
static void
-xorbytes(unsigned char *dest, unsigned char *src, int len)
+do_xor(unsigned char *dest, unsigned char *src, int len)
{
-#ifdef PARANOIA
+ /* use byt xor, not all platforms are happy about inaligned
+ * integer fetches */
while (len--) {
*dest = *dest ^ *src;
dest++;
src++;
}
-#else
- PRUInt32 dest32 = (PRUInt32 *)dest;
- PRUInt32 src32 = (PRUInt32 *)dest;
- while (len -= sizeof(PRUInt32)) {
- *dest32 = *dest32 ^ *src32;
- dest++;
- src++;
- }
-#endif
}
static SECStatus
@@ -327,33 +351,31 @@ nsspkcs5_PBKFD2_F(const SECHashObject *hashobj, SECItem *pwitem, SECItem *salt,
{
int j;
HMACContext *cx = NULL;
- unsigned int hLen = hashObject->length
+ unsigned int hLen = hashobj->length;
SECStatus rv = SECFailure;
unsigned char *last = NULL;
- int lastLength = salt->len + 4;
+ unsigned int lastLength = salt->len + 4;
+ unsigned int lastBufLength;
cx=HMAC_Create(hashobj,pwitem->data,pwitem->len,PR_TRUE);
if (cx == NULL) {
goto loser;
}
PORT_Memset(T,0,hLen);
- realLastLength= MAX(lastLength,hLen);
- last = PORT_Alloc(realLastLength);
+ lastBufLength = PR_MAX(lastLength, hLen);
+ last = PORT_Alloc(lastBufLength);
if (last == NULL) {
goto loser;
}
- PORT_Memcpy(last,salt.data,salt.len);
+ PORT_Memcpy(last,salt->data,salt->len);
last[salt->len ] = (i >> 24) & 0xff;
last[salt->len+1] = (i >> 16) & 0xff;
last[salt->len+2] = (i >> 8) & 0xff;
last[salt->len+3] = i & 0xff;
/* NOTE: we need at least one iteration to return success! */
- for (j=0; j < interations; j++) {
- rv =HMAC_Begin(cx);
- if (rv !=SECSuccess) {
- break;
- }
+ for (j=0; j < iterations; j++) {
+ HMAC_Begin(cx);
HMAC_Update(cx,last,lastLength);
rv =HMAC_Finish(cx,last,&lastLength,hLen);
if (rv !=SECSuccess) {
@@ -363,26 +385,29 @@ nsspkcs5_PBKFD2_F(const SECHashObject *hashobj, SECItem *pwitem, SECItem *salt,
}
loser:
if (cx) {
- HMAC_DestroyContext(cx, PR_TRUE);
+ HMAC_Destroy(cx, PR_TRUE);
}
if (last) {
- PORT_ZFree(last,reaLastLength);
+ PORT_ZFree(last,lastBufLength);
}
return rv;
}
static SECItem *
-nsspkcs5_PBKFD2(const SECHashObject *hashObj, NSSPKCS5PBEParameter *pbe_param,
+nsspkcs5_PBKDF2(const SECHashObject *hashobj, NSSPKCS5PBEParameter *pbe_param,
SECItem *pwitem)
{
+ int iterations = pbe_param->iter;
+ int bytesNeeded = pbe_param->keyLen;
unsigned int dkLen = bytesNeeded;
- unsigned int hLen = hashObject->length
+ unsigned int hLen = hashobj->length;
unsigned int l = (dkLen+hLen-1) / hLen;
+ unsigned int i;
unsigned char *rp;
- SECItem *result;
- SECItem *salt = pbe_param->salt;
- int interations = pbe_param->iter;
- int bytesNeeded = pbe_param->keyLen;
+ unsigned char *T = NULL;
+ SECItem *result = NULL;;
+ SECItem *salt = &pbe_param->salt;
+ SECStatus rv = SECFailure;
result = SECITEM_AllocItem(NULL,NULL,l*hLen);
if (result == NULL) {
@@ -394,7 +419,7 @@ nsspkcs5_PBKFD2(const SECHashObject *hashObj, NSSPKCS5PBEParameter *pbe_param,
goto loser;
}
- for (i=0,rp=results->data; i < l ; i++, rp +=hLen) {
+ for (i=0,rp=result->data; i < l ; i++, rp +=hLen) {
rv = nsspkcs5_PBKFD2_F(hashobj,pwitem,salt,iterations,i,T);
if (rv != SECSuccess) {
break;
@@ -404,10 +429,10 @@ nsspkcs5_PBKFD2(const SECHashObject *hashObj, NSSPKCS5PBEParameter *pbe_param,
loser:
if (T) {
- PORT_ZFree(T);
+ PORT_ZFree(T,hLen);
}
if (rv != SECSuccess) {
- SECITEM_FreeITEM(result,PR_TRUE);
+ SECITEM_FreeItem(result,PR_TRUE);
result = NULL;
} else {
result->len = dkLen;
@@ -580,7 +605,7 @@ nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem,
return NULL;
}
- if ((pbe_param->ivLen) && (iv->data == NULL)) {
+ if (iv && (pbe_param->ivLen) && (iv->data == NULL)) {
getIV = PR_TRUE;
iv->data = (unsigned char *)PORT_Alloc(pbe_param->ivLen);
if (iv->data == NULL) {
@@ -596,15 +621,18 @@ nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem,
if (hash == NULL) {
goto loser;
}
- PORT_Assert(hash->len >= key->len+iv->len);
+ PORT_Assert(hash->len >= key->len+(getIV ? iv->len : 0));
if (getIV) {
PORT_Memcpy(iv->data, hash->data+(hash->len - iv->len),iv->len);
- }
+ }
+
break;
#ifdef PBKDF2
case NSSPKCS5_PBKDF2:
hash = nsspkcs5_PBKDF2(hashObj,pbe_param,pwitem);
- PORT_Assert(!getIV);
+ if (getIV) {
+ PORT_Memcpy(iv->data, pbe_param->ivData, iv->len);
+ }
break;
#endif
case NSSPKCS5_PKCS12_V2:
@@ -715,6 +743,19 @@ finish_des:
pbe_param->ivLen = 0;
pbe_param->encAlg = SEC_OID_RC4;
break;
+
+#ifdef PBKDF2
+ case SEC_OID_PKCS5_PBKDF2:
+ case SEC_OID_PKCS5_PBES2:
+ case SEC_OID_PKCS5_PBMAC1:
+ /* everything else will be filled in by the template */
+ pbe_param->ivLen = 0;
+ pbe_param->pbeType = NSSPKCS5_PBKDF2;
+ pbe_param->encAlg = SEC_OID_PKCS5_PBKDF2;
+ pbe_param->keyLen = 0; /* needs to be set by caller after return */
+ break;
+#endif
+
default:
return SECFailure;
}
@@ -767,12 +808,36 @@ loser:
return pbe_param;
}
+/*
+ * find the hash type needed to implement a specific HMAC.
+ * OID definitions are from pkcs 5 v2.0 and 2.1
+ */
+HASH_HashType
+HASH_FromHMACOid(SECOidTag hmac)
+{
+ switch (hmac) {
+ case SEC_OID_HMAC_SHA1:
+ return HASH_AlgSHA1;
+ case SEC_OID_HMAC_SHA256:
+ return HASH_AlgSHA256;
+ case SEC_OID_HMAC_SHA384:
+ return HASH_AlgSHA384;
+ case SEC_OID_HMAC_SHA512:
+ return HASH_AlgSHA512;
+ case SEC_OID_HMAC_SHA224:
+ default:
+ break;
+ }
+ return HASH_AlgNULL;
+}
+
/* decode the algid and generate a PKCS 5 parameter from it
*/
NSSPKCS5PBEParameter *
nsspkcs5_AlgidToParam(SECAlgorithmID *algid)
{
NSSPKCS5PBEParameter *pbe_param = NULL;
+ nsspkcs5V2PBEParameter pbev2_param;
SECOidTag algorithm;
SECStatus rv = SECFailure;
@@ -801,8 +866,42 @@ nsspkcs5_AlgidToParam(SECAlgorithmID *algid)
rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param,
NSSPKCS5PKCS12V2PBEParameterTemplate, &algid->parameters);
break;
+#ifdef PBKDF2
case NSSPKCS5_PBKDF2:
+ PORT_Memset(&pbev2_param,0, sizeof(pbev2_param));
+ /* just the PBE */
+ if (algorithm == SEC_OID_PKCS5_PBKDF2) {
+ rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param,
+ NSSPKCS5V2PBEParameterTemplate, &algid->parameters);
+ } else {
+ /* PBE data an others */
+ rv = SEC_ASN1DecodeItem(pbe_param->poolp, &pbev2_param,
+ NSSPKCS5V2PBES2ParameterTemplate, &algid->parameters);
+ if (rv != SECSuccess) {
+ break;
+ }
+ pbe_param->encAlg = SECOID_GetAlgorithmTag(&pbev2_param.algParams);
+ rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param,
+ NSSPKCS5V2PBEParameterTemplate,
+ &pbev2_param.keyParams.parameters);
+ if (rv != SECSuccess) {
+ break;
+ }
+ pbe_param->keyLen = DER_GetInteger(&pbe_param->keyLength);
+ }
+ /* we we are encrypting, save any iv's */
+ if (algorithm == SEC_OID_PKCS5_PBES2) {
+ pbe_param->ivLen = pbev2_param.algParams.parameters.len;
+ pbe_param->ivData = pbev2_param.algParams.parameters.data;
+ }
+ pbe_param->hashType =
+ HASH_FromHMACOid(SECOID_GetAlgorithmTag(&pbe_param->prfAlg));
+ if (pbe_param->hashType == HASH_AlgNULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ rv = SECFailure;
+ }
break;
+#endif
}
loser:
@@ -853,8 +952,8 @@ sec_pkcs5_des(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des,
if(encrypt != PR_FALSE) {
void *dummy;
- dummy = DES_PadBuffer(NULL, dup_src->data,
- dup_src->len, &dup_src->len);
+ dummy = CBC_PadBuffer(NULL, dup_src->data,
+ dup_src->len, &dup_src->len, 8 /* DES_BLOCK_SIZE */);
if(dummy == NULL) {
SECITEM_FreeItem(dup_src, PR_TRUE);
return NULL;
@@ -911,6 +1010,85 @@ sec_pkcs5_des(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des,
return dest;
}
+/* perform aes encryption/decryption if an error occurs, NULL is returned
+ */
+static SECItem *
+sec_pkcs5_aes(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des,
+ PRBool encrypt)
+{
+ SECItem *dest;
+ SECItem *dup_src;
+ SECStatus rv = SECFailure;
+ int pad;
+
+ if((src == NULL) || (key == NULL) || (iv == NULL))
+ return NULL;
+
+ dup_src = SECITEM_DupItem(src);
+ if(dup_src == NULL) {
+ return NULL;
+ }
+
+ if(encrypt != PR_FALSE) {
+ void *dummy;
+
+ dummy = CBC_PadBuffer(NULL, dup_src->data,
+ dup_src->len, &dup_src->len,AES_BLOCK_SIZE);
+ if(dummy == NULL) {
+ SECITEM_FreeItem(dup_src, PR_TRUE);
+ return NULL;
+ }
+ dup_src->data = (unsigned char*)dummy;
+ }
+
+ dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+ if(dest != NULL) {
+ /* allocate with over flow */
+ dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64);
+ if(dest->data != NULL) {
+ AESContext *ctxt;
+ ctxt = AES_CreateContext(key->data, iv->data,
+ NSS_AES_CBC, encrypt, key->len, 16);
+
+ if(ctxt != NULL) {
+ rv = (encrypt ? AES_Encrypt : AES_Decrypt)(
+ ctxt, dest->data, &dest->len,
+ dup_src->len + 64, dup_src->data, dup_src->len);
+
+ /* remove padding -- assumes 64 bit blocks */
+ if((encrypt == PR_FALSE) && (rv == SECSuccess)) {
+ pad = dest->data[dest->len-1];
+ if((pad > 0) && (pad <= 16)) {
+ if(dest->data[dest->len-pad] != pad) {
+ rv = SECFailure;
+ PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+ } else {
+ dest->len -= pad;
+ }
+ } else {
+ rv = SECFailure;
+ PORT_SetError(SEC_ERROR_BAD_PASSWORD);
+ }
+ }
+ AES_DestroyContext(ctxt, PR_TRUE);
+ }
+ }
+ }
+
+ if(rv == SECFailure) {
+ if(dest != NULL) {
+ SECITEM_FreeItem(dest, PR_TRUE);
+ }
+ dest = NULL;
+ }
+
+ if(dup_src != NULL) {
+ SECITEM_FreeItem(dup_src, PR_TRUE);
+ }
+
+ return dest;
+}
+
/* perform rc2 encryption/decryption if an error occurs, NULL is returned
*/
static SECItem *
@@ -934,8 +1112,8 @@ sec_pkcs5_rc2(SECItem *key, SECItem *iv, SECItem *src, PRBool dummy,
if(encrypt != PR_FALSE) {
void *dummy;
- dummy = DES_PadBuffer(NULL, dup_src->data,
- dup_src->len, &dup_src->len);
+ dummy = CBC_PadBuffer(NULL, dup_src->data,
+ dup_src->len, &dup_src->len, 8 /* RC2_BLOCK_SIZE */);
if(dummy == NULL) {
SECITEM_FreeItem(dup_src, PR_TRUE);
return NULL;
@@ -1062,6 +1240,12 @@ nsspkcs5_CipherData(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem,
}
switch(pbe_param->encAlg) {
+ /* PKCS 5 v2 only */
+ case SEC_OID_AES_128_CBC:
+ case SEC_OID_AES_192_CBC:
+ case SEC_OID_AES_256_CBC:
+ cryptof = sec_pkcs5_aes;
+ break;
case SEC_OID_DES_EDE3_CBC:
cryptof = sec_pkcs5_des;
tripleDES = PR_TRUE;
@@ -1125,6 +1309,8 @@ nsspkcs5_CreateAlgorithmID(PRArenaPool *arena, SECOidTag algorithm,
{
SECAlgorithmID *algid, *ret_algid = NULL;
SECItem der_param;
+ nsspkcs5V2PBEParameter pkcs5v2_param;
+
SECStatus rv = SECFailure;
void *dummy = NULL;
@@ -1157,6 +1343,38 @@ nsspkcs5_CreateAlgorithmID(PRArenaPool *arena, SECOidTag algorithm,
dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param,
NSSPKCS5PKCS12V2PBEParameterTemplate);
break;
+#ifdef PBKDF2
+ case NSSPKCS5_PBKDF2:
+ if (pbe_param->keyLength.data == NULL) {
+ dummy = SEC_ASN1EncodeInteger(pbe_param->poolp,
+ &pbe_param->keyLength, pbe_param->keyLen);
+ if (dummy == NULL) {
+ goto loser;
+ }
+ }
+ PORT_Memset(&pkcs5v2_param, 0, sizeof(pkcs5v2_param));
+ dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param,
+ NSSPKCS5V2PBEParameterTemplate);
+ if (dummy == NULL) {
+ break;
+ }
+ dummy = NULL;
+ rv = SECOID_SetAlgorithmID(arena, &pkcs5v2_param.keyParams,
+ SEC_OID_PKCS5_PBKDF2, &der_param);
+ if (rv != SECSuccess) {
+ break;
+ }
+ der_param.data = pbe_param->ivData;
+ der_param.len = pbe_param->ivLen;
+ rv = SECOID_SetAlgorithmID(arena, &pkcs5v2_param.algParams,
+ pbe_param->encAlg, pbe_param->ivLen ? &der_param : NULL);
+ if (rv != SECSuccess) {
+ break;
+ }
+ dummy = SEC_ASN1EncodeItem(arena, &der_param, &pkcs5v2_param,
+ NSSPKCS5V2PBES2ParameterTemplate);
+ break;
+#endif
default:
break;
}
diff --git a/security/nss/lib/softoken/lowpbe.h b/security/nss/lib/softoken/lowpbe.h
index 32e1e1169..974b2fa4f 100644
--- a/security/nss/lib/softoken/lowpbe.h
+++ b/security/nss/lib/softoken/lowpbe.h
@@ -65,13 +65,16 @@ struct NSSPKCS5PBEParameterStr {
PRArenaPool *poolp;
SECItem salt; /* octet string */
SECItem iteration; /* integer */
+ SECItem keyLength; /* integer */
/* used locally */
int iter;
int keyLen;
int ivLen;
+ unsigned char *ivData;
HASH_HashType hashType;
NSSPKCS5PBEType pbeType;
+ SECAlgorithmID prfAlg;
PBEBitGenID keyID;
SECOidTag encAlg;
PRBool is2KeyDES;
@@ -130,6 +133,8 @@ nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *, SECItem *pwitem,
extern void
nsspkcs5_DestroyPBEParameter(NSSPKCS5PBEParameter *param);
+HASH_HashType HASH_FromHMACOid(SECOidTag oid);
+
SEC_END_PROTOS
#endif
diff --git a/security/nss/lib/softoken/padbuf.c b/security/nss/lib/softoken/padbuf.c
index c37a0469e..8c43fa287 100644
--- a/security/nss/lib/softoken/padbuf.c
+++ b/security/nss/lib/softoken/padbuf.c
@@ -38,15 +38,16 @@
#include "secerr.h"
/*
- * Prepare a buffer for DES encryption, growing to the appropriate boundary,
- * filling with the appropriate padding.
+ * Prepare a buffer for any padded CBC encryption algorithm, growing to the
+ * appropriate boundary and filling with the appropriate padding.
+ * blockSize must be a power of 2.
*
* NOTE: If arena is non-NULL, we re-allocate from there, otherwise
* we assume (and use) XP memory (re)allocation.
*/
unsigned char *
-DES_PadBuffer(PRArenaPool *arena, unsigned char *inbuf, unsigned int inlen,
- unsigned int *outlen)
+CBC_PadBuffer(PRArenaPool *arena, unsigned char *inbuf, unsigned int inlen,
+ unsigned int *outlen, int blockSize)
{
unsigned char *outbuf;
unsigned int des_len;
@@ -54,11 +55,11 @@ DES_PadBuffer(PRArenaPool *arena, unsigned char *inbuf, unsigned int inlen,
unsigned char des_pad_len;
/*
- * We need from 1 to DES_KEY_LENGTH bytes -- we *always* grow.
+ * We need from 1 to blockSize bytes -- we *always* grow.
* The extra bytes contain the value of the length of the padding:
* if we have 2 bytes of padding, then the padding is "0x02, 0x02".
*/
- des_len = (inlen + DES_KEY_LENGTH) & ~(DES_KEY_LENGTH - 1);
+ des_len = (inlen + blockSize) & ~(blockSize - 1);
if (arena != NULL) {
outbuf = (unsigned char*)PORT_ArenaGrow (arena, inbuf, inlen, des_len);
diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c
index df149a9ea..70ae8693d 100644
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -2597,14 +2597,20 @@ nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism,
{
SECItem *pbe_key = NULL, iv, pwitem;
CK_PBE_PARAMS *pbe_params = NULL;
+ CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL;
*key_length = 0;
iv.data = NULL; iv.len = 0;
- pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
-
- pwitem.data = (unsigned char *)pbe_params->pPassword;
- pwitem.len = (unsigned int)pbe_params->ulPasswordLen;
+ if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
+ pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
+ pwitem.data = (unsigned char *)pbkd2_params->pPassword;
+ pwitem.len = (unsigned int)pbkd2_params->ulPasswordLen;
+ } else {
+ pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
+ pwitem.data = (unsigned char *)pbe_params->pPassword;
+ pwitem.len = (unsigned int)pbe_params->ulPasswordLen;
+ }
pbe_key = nsspkcs5_ComputeKeyAndIV(pkcs5_pbe, &pwitem, &iv, faulty3DES);
if (pbe_key == NULL) {
return CKR_HOST_MEMORY;
@@ -2616,7 +2622,7 @@ nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism,
pbe_key = NULL;
if (iv.data) {
- if (pbe_params->pInitVector != NULL) {
+ if (pbe_params && pbe_params->pInitVector != NULL) {
PORT_Memcpy(pbe_params->pInitVector, iv.data, iv.len);
}
PORT_Free(iv.data);
@@ -2698,11 +2704,6 @@ loser:
return crv;
}
-
-
-
-
-
static CK_RV
nsc_SetupBulkKeyGen(CK_MECHANISM_TYPE mechanism, CK_KEY_TYPE *key_type,
@@ -2823,16 +2824,19 @@ nsc_SetupHMACKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe)
*pbe = params;
return CKR_OK;
}
+
/* maybe this should be table driven? */
static CK_RV
nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe,
- CK_KEY_TYPE *key_type)
+ CK_KEY_TYPE *key_type, CK_ULONG *key_length)
{
CK_RV crv = CKR_OK;
SECOidData *oid;
- CK_PBE_PARAMS *pbe_params;
- NSSPKCS5PBEParameter *params;
+ CK_PBE_PARAMS *pbe_params = NULL;
+ NSSPKCS5PBEParameter *params = NULL;
+ CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL;
SECItem salt;
+ CK_ULONG iteration = 0;
*pbe = NULL;
@@ -2841,28 +2845,66 @@ nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe,
return CKR_MECHANISM_INVALID;
}
- pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
- salt.data = (unsigned char *)pbe_params->pSalt;
- salt.len = (unsigned int)pbe_params->ulSaltLen;
-
- params=nsspkcs5_NewParam(oid->offset, &salt, pbe_params->ulIteration);
+ if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
+ pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
+ if (pbkd2_params->saltSource != CKZ_SALT_SPECIFIED) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ salt.data = (unsigned char *)pbkd2_params->pSaltSourceData;
+ salt.len = (unsigned int)pbkd2_params->ulSaltSourceDataLen;
+ iteration = pbkd2_params->iterations;
+ } else {
+ pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
+ salt.data = (unsigned char *)pbe_params->pSalt;
+ salt.len = (unsigned int)pbe_params->ulSaltLen;
+ iteration = pbe_params->ulIteration;
+ }
+ params=nsspkcs5_NewParam(oid->offset, &salt, iteration);
if (params == NULL) {
return CKR_MECHANISM_INVALID;
}
-
switch (params->encAlg) {
case SEC_OID_DES_CBC:
*key_type = CKK_DES;
+ *key_length = params->keyLen;
break;
case SEC_OID_DES_EDE3_CBC:
*key_type = params->is2KeyDES ? CKK_DES2 : CKK_DES3;
+ *key_length = params->keyLen;
break;
case SEC_OID_RC2_CBC:
*key_type = CKK_RC2;
+ *key_length = params->keyLen;
break;
case SEC_OID_RC4:
*key_type = CKK_RC4;
+ *key_length = params->keyLen;
+ break;
+ case SEC_OID_PKCS5_PBKDF2:
+ /* sigh, PKCS #11 currently only defines SHA1 for the KDF hash type.
+ * we do the check here because this where we would handle multiple
+ * hash types in the future */
+ if (pbkd2_params == NULL ||
+ pbkd2_params->prf != CKP_PKCS5_PBKD2_HMAC_SHA1) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
+ /* key type must already be set */
+ if (*key_type == CKK_INVALID_KEY_TYPE) {
+ crv = CKR_TEMPLATE_INCOMPLETE;
+ break;
+ }
+ /* PBKDF2 needs to calculate the key length from the other parameters
+ */
+ if (*key_length == 0) {
+ *key_length = sftk_MapKeySize(*key_type);
+ }
+ if (*key_length == 0) {
+ crv = CKR_TEMPLATE_INCOMPLETE;
+ break;
+ }
+ params->keyLen = *key_length;
break;
default:
crv = CKR_MECHANISM_INVALID;
@@ -2920,6 +2962,11 @@ CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession,
key_length = *(CK_ULONG *)pTemplate[i].pValue;
continue;
}
+ /* some algorithms need keytype specified */
+ if (pTemplate[i].type == CKA_KEY_TYPE) {
+ key_type = *(CK_ULONG *)pTemplate[i].pValue;
+ continue;
+ }
crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
if (crv != CKR_OK) break;
@@ -2982,7 +3029,7 @@ CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession,
case CKM_PBE_MD5_DES_CBC:
case CKM_PBE_MD2_DES_CBC:
key_gen_type = nsc_pbe;
- crv = nsc_SetupPBEKeyGen(pMechanism,&pbe_param, &key_type);
+ crv = nsc_SetupPBEKeyGen(pMechanism,&pbe_param, &key_type, &key_length);
break;
case CKM_DSA_PARAMETER_GEN:
key_gen_type = nsc_param;
diff --git a/security/nss/lib/softoken/pkcs11t.h b/security/nss/lib/softoken/pkcs11t.h
index 7f8009e40..a828743c3 100644
--- a/security/nss/lib/softoken/pkcs11t.h
+++ b/security/nss/lib/softoken/pkcs11t.h
@@ -661,6 +661,10 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
#define CKM_SHA384_RSA_PKCS_PSS 0x00000044
#define CKM_SHA512_RSA_PKCS_PSS 0x00000045
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224_RSA_PKCS 0x00000046
+#define CKM_SHA224_RSA_PKCS_PSS 0x00000047
+
#define CKM_RC2_KEY_GEN 0x00000100
#define CKM_RC2_ECB 0x00000101
#define CKM_RC2_CBC 0x00000102
@@ -744,6 +748,11 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
#define CKM_SHA512_HMAC 0x00000271
#define CKM_SHA512_HMAC_GENERAL 0x00000272
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224 0x00000255
+#define CKM_SHA224_HMAC 0x00000256
+#define CKM_SHA224_HMAC_GENERAL 0x00000257
+
/* All of the following mechanisms are new for v2.0 */
/* Note that CAST128 and CAST5 are the same algorithm */
#define CKM_CAST_KEY_GEN 0x00000300
@@ -815,6 +824,9 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
#define CKM_SHA384_KEY_DERIVATION 0x00000394
#define CKM_SHA512_KEY_DERIVATION 0x00000395
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224_KEY_DERIVATION 0x00000396
+
#define CKM_PBE_MD2_DES_CBC 0x000003A0
#define CKM_PBE_MD5_DES_CBC 0x000003A1
#define CKM_PBE_MD5_CAST_CBC 0x000003A2
@@ -1235,6 +1247,9 @@ typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
#define CKG_MGF1_SHA384 0x00000003
#define CKG_MGF1_SHA512 0x00000004
+/* v2.20 amendment 3 */
+#define CKG_MGF1_SHA224 0x00000005
+
/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10.
* CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
* of the encoding parameter when formatting a message block
diff --git a/security/nss/lib/softoken/sdb.c b/security/nss/lib/softoken/sdb.c
index 2642a991d..a258c555d 100644
--- a/security/nss/lib/softoken/sdb.c
+++ b/security/nss/lib/softoken/sdb.c
@@ -282,8 +282,8 @@ struct SDBFindStr {
};
-#define FIND_OBJECTS_CMD "SELECT ALL * FROM %s WHERE %s;"
-#define FIND_OBJECTS_ALL_CMD "SELECT ALL * FROM %s;"
+static const char FIND_OBJECTS_CMD[] = "SELECT ALL * FROM %s WHERE %s;";
+static const char FIND_OBJECTS_ALL_CMD[] = "SELECT ALL * FROM %s;";
CK_RV
sdb_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *template, CK_ULONG count,
SDBFind **find)
@@ -420,7 +420,7 @@ sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind)
return sdb_mapSQLError(sdb_p->type, sqlerr);
}
-#define GET_ATTRIBUTE_CMD "SELECT ALL %s FROM %s WHERE id=$ID;"
+static const char GET_ATTRIBUTE_CMD[] = "SELECT ALL %s FROM %s WHERE id=$ID;";
CK_RV
sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id,
CK_ATTRIBUTE *template, CK_ULONG count)
@@ -547,7 +547,7 @@ sdb_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id,
return crv;
}
-#define SET_ATTRIBUTE_CMD "UPDATE %s SET %s WHERE id=$ID;"
+static const char SET_ATTRIBUTE_CMD[] = "UPDATE %s SET %s WHERE id=$ID;";
CK_RV
sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id,
const CK_ATTRIBUTE *template, CK_ULONG count)
@@ -562,7 +562,7 @@ sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id,
CK_RV error = CKR_OK;
int i;
- if (sdb->sdb_flags == SDB_RDONLY) {
+ if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
return CKR_TOKEN_WRITE_PROTECTED;
}
@@ -697,7 +697,7 @@ sdb_getObjectId(SDB *sdb)
return CK_INVALID_HANDLE;
}
-#define CREATE_CMD "INSERT INTO %s (id%s) VALUES($ID%s);"
+static const char CREATE_CMD[] = "INSERT INTO %s (id%s) VALUES($ID%s);";
CK_RV
sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id,
const CK_ATTRIBUTE *template, CK_ULONG count)
@@ -714,7 +714,7 @@ sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id,
int retry = 0;
int i;
- if (sdb->sdb_flags == SDB_RDONLY) {
+ if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
return CKR_TOKEN_WRITE_PROTECTED;
}
@@ -801,7 +801,7 @@ loser:
return error;
}
-#define DESTROY_CMD "DELETE FROM %s WHERE (id=$ID);"
+static const char DESTROY_CMD[] = "DELETE FROM %s WHERE (id=$ID);";
CK_RV
sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id)
{
@@ -813,7 +813,7 @@ sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id)
CK_RV error = CKR_OK;
int retry = 0;
- if (sdb->sdb_flags == SDB_RDONLY) {
+ if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
return CKR_TOKEN_WRITE_PROTECTED;
}
@@ -858,7 +858,7 @@ loser:
return error;
}
-#define BEGIN_CMD "BEGIN IMMEDIATE TRANSACTION;"
+static const char BEGIN_CMD[] = "BEGIN IMMEDIATE TRANSACTION;";
/*
* start a transaction.
*
@@ -877,7 +877,7 @@ sdb_Begin(SDB *sdb)
int retry = 0;
- if (sdb->sdb_flags == SDB_RDONLY) {
+ if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
return CKR_TOKEN_WRITE_PROTECTED;
}
@@ -957,7 +957,7 @@ sdb_complete(SDB *sdb, const char *cmd)
int retry = 0;
- if (sdb->sdb_flags == SDB_RDONLY) {
+ if ((sdb->sdb_flags & SDB_RDONLY) != 0) {
return CKR_TOKEN_WRITE_PROTECTED;
}
@@ -1011,7 +1011,7 @@ sdb_complete(SDB *sdb, const char *cmd)
return error;
}
-#define COMMIT_CMD "COMMIT TRANSACTION;"
+static const char COMMIT_CMD[] = "COMMIT TRANSACTION;";
CK_RV
sdb_Commit(SDB *sdb)
{
@@ -1022,7 +1022,7 @@ sdb_Commit(SDB *sdb)
return crv;
}
-#define ROLLBACK_CMD "ROLLBACK TRANSACTION;"
+static const char ROLLBACK_CMD[] = "ROLLBACK TRANSACTION;";
CK_RV
sdb_Abort(SDB *sdb)
{
@@ -1033,9 +1033,11 @@ sdb_Abort(SDB *sdb)
return crv;
}
-#define GET_PW_CMD "SELECT ALL * FROM password WHERE id='password';"
+static int tableExists(sqlite3 *sqlDB, const char *tableName);
+
+static const char GET_PW_CMD[] = "SELECT ALL * FROM metaData WHERE id=$ID;";
CK_RV
-sdb_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry)
+sdb_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2)
{
SDBPrivate *sdb_p = sdb->private;
sqlite3 *sqlDB = sdb_p->sqlXactDB;
@@ -1045,7 +1047,7 @@ sdb_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry)
int found = 0;
int retry = 0;
- /* only Key databases have password entries */
+ /* currently only Key databases have meta data entries */
if (sdb_p->type != SDB_KEY) {
return CKR_OBJECT_HANDLE_INVALID;
}
@@ -1056,7 +1058,10 @@ sdb_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry)
goto loser;
}
+ /* handle 'test' versions of the sqlite db */
sqlerr = sqlite3_prepare(sqlDB, GET_PW_CMD, -1, &stmt, NULL);
+ if (sqlerr != SQLITE_OK) goto loser;
+ sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC);
do {
sqlerr = sqlite3_step(stmt);
if (sqlerr == SQLITE_BUSY) {
@@ -1064,22 +1069,22 @@ sdb_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry)
}
if (sqlerr == SQLITE_ROW) {
const char *blobData;
- entry->salt.data = entry->data;
- entry->salt.len = sqlite3_column_bytes(stmt, 1);
- if (entry->salt.len > sizeof(entry->data)) {
+ item1->len = sqlite3_column_bytes(stmt, 1);
+ if (item1->len > SDB_MAX_META_DATA_LEN) {
error = CKR_BUFFER_TOO_SMALL;
continue;
}
blobData = sqlite3_column_blob(stmt, 1);
- PORT_Memcpy(entry->salt.data,blobData, entry->salt.len);
- entry->value.data = &entry->data[entry->salt.len];
- entry->value.len = sqlite3_column_bytes(stmt, 2);
- if ((entry->value.len+entry->salt.len) > sizeof(entry->data)) {
- error = CKR_BUFFER_TOO_SMALL;
- continue;
+ PORT_Memcpy(item1->data,blobData, item1->len);
+ if (item2) {
+ item2->len = sqlite3_column_bytes(stmt, 2);
+ if (item2->len > SDB_MAX_META_DATA_LEN) {
+ error = CKR_BUFFER_TOO_SMALL;
+ continue;
+ }
+ blobData = sqlite3_column_blob(stmt, 2);
+ PORT_Memcpy(item2->data,blobData, item2->len);
}
- blobData = sqlite3_column_blob(stmt, 2);
- PORT_Memcpy(entry->value.data,blobData, entry->value.len);
found = 1;
}
} while (!sdb_done(sqlerr,&retry));
@@ -1106,13 +1111,15 @@ loser:
return error;
}
-static int tableExists(sqlite3 *sqlDB, const char *tableName);
-#define PW_CREATE_TABLE_CMD \
- "CREATE TABLE password (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, salt, value);"
-#define PW_CREATE_CMD \
- "INSERT INTO password (id,salt,value) VALUES('password',$SALT,$VALUE);"
+static const char PW_CREATE_TABLE_CMD[] =
+ "CREATE TABLE metaData (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, item1, item2);";
+static const char PW_CREATE_CMD[] =
+ "INSERT INTO metaData (id,item1,item2) VALUES($ID,$ITEM1,$ITEM2);";
+static const char MD_CREATE_CMD[] =
+ "INSERT INTO metaData (id,item1) VALUES($ID,$ITEM1);";
CK_RV
-sdb_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry)
+sdb_PutMetaData(SDB *sdb, const char *id, const SECItem *item1,
+ const SECItem *item2)
{
SDBPrivate *sdb_p = sdb->private;
sqlite3 *sqlDB = sdb_p->sqlXactDB;
@@ -1120,6 +1127,7 @@ sdb_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry)
int sqlerr = SQLITE_OK;
CK_RV error = CKR_OK;
int retry = 0;
+ const char *cmd = PW_CREATE_CMD;
/* only Key databases have password entries */
if (sdb_p->type != SDB_KEY) {
@@ -1132,18 +1140,24 @@ sdb_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry)
goto loser;
}
- if (!tableExists(sqlDB, "password")) {
+ if (!tableExists(sqlDB, "metaData")) {
sqlerr = sqlite3_exec(sqlDB, PW_CREATE_TABLE_CMD, NULL, 0, NULL);
if (sqlerr != SQLITE_OK) goto loser;
}
- sqlerr = sqlite3_prepare(sqlDB, PW_CREATE_CMD, -1, &stmt, NULL);
+ if (item2 == NULL) {
+ cmd = MD_CREATE_CMD;
+ }
+ sqlerr = sqlite3_prepare(sqlDB, cmd, -1, &stmt, NULL);
if (sqlerr != SQLITE_OK) goto loser;
- sqlerr = sqlite3_bind_blob(stmt, 1, entry->salt.data,
- entry->salt.len, SQLITE_STATIC);
+ sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC);
if (sqlerr != SQLITE_OK) goto loser;
- sqlerr = sqlite3_bind_blob(stmt, 2, entry->value.data,
- entry->value.len, SQLITE_STATIC);
+ sqlerr = sqlite3_bind_blob(stmt, 2, item1->data, item1->len, SQLITE_STATIC);
if (sqlerr != SQLITE_OK) goto loser;
+ if (item2) {
+ sqlerr = sqlite3_bind_blob(stmt, 3, item2->data,
+ item2->len, SQLITE_STATIC);
+ if (sqlerr != SQLITE_OK) goto loser;
+ }
do {
sqlerr = sqlite3_step(stmt);
@@ -1171,7 +1185,7 @@ loser:
return error;
}
-#define RESET_CMD "DROP TABLE IF EXISTS %s;"
+static const char RESET_CMD[] = "DROP TABLE IF EXISTS %s;";
CK_RV
sdb_Reset(SDB *sdb)
{
@@ -1204,7 +1218,7 @@ sdb_Reset(SDB *sdb)
if (sqlerr != SQLITE_OK) goto loser;
/* delete the password entry table */
- sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS password;",
+ sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS metaData;",
NULL, 0, NULL);
loser:
@@ -1241,7 +1255,7 @@ sdb_Close(SDB *sdb)
* functions to support open
*/
-#define CHECK_TABLE_CMD "SELECT ALL * FROM %s LIMIT 0;"
+static const char CHECK_TABLE_CMD[] = "SELECT ALL * FROM %s LIMIT 0;";
/* return 1 if sqlDB contains table 'tableName */
static int tableExists(sqlite3 *sqlDB, const char *tableName)
{
@@ -1261,11 +1275,10 @@ static int tableExists(sqlite3 *sqlDB, const char *tableName)
/*
* initialize a single database
*/
-#define INIT_CMD \
- "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)"
-#define ALTER_CMD \
- "ALTER TABLE %s ADD COLUMN a%x"
-
+static const char INIT_CMD[] =
+ "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)";
+static const char ALTER_CMD[] =
+ "ALTER TABLE %s ADD COLUMN a%x";
CK_RV
sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
@@ -1357,7 +1370,7 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
sdb_p->sqlXactThread = NULL;
sdb->private = sdb_p;
sdb->sdb_type = SDB_SQL;
- sdb->sdb_flags = flags;
+ sdb->sdb_flags = flags | SDB_HAS_META;
sdb->sdb_FindObjectsInit = sdb_FindObjectsInit;
sdb->sdb_FindObjects = sdb_FindObjects;
sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal;
@@ -1365,8 +1378,8 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
sdb->sdb_SetAttributeValue = sdb_SetAttributeValue;
sdb->sdb_CreateObject = sdb_CreateObject;
sdb->sdb_DestroyObject = sdb_DestroyObject;
- sdb->sdb_GetPWEntry = sdb_GetPWEntry;
- sdb->sdb_PutPWEntry = sdb_PutPWEntry;
+ sdb->sdb_GetMetaData = sdb_GetMetaData;
+ sdb->sdb_PutMetaData = sdb_PutMetaData;
sdb->sdb_Begin = sdb_Begin;
sdb->sdb_Commit = sdb_Commit;
sdb->sdb_Abort = sdb_Abort;
diff --git a/security/nss/lib/softoken/sdb.h b/security/nss/lib/softoken/sdb.h
index 818bc4bf1..9e041f476 100644
--- a/security/nss/lib/softoken/sdb.h
+++ b/security/nss/lib/softoken/sdb.h
@@ -66,7 +66,6 @@
typedef struct SDBFindStr SDBFind;
typedef struct SDBStr SDB;
-typedef struct SDBPasswordEntryStr SDBPasswordEntry;
struct SDBStr {
void *private;
@@ -86,8 +85,10 @@ struct SDBStr {
CK_RV (*sdb_CreateObject)(SDB *sdb, CK_OBJECT_HANDLE *object,
const CK_ATTRIBUTE *template, CK_ULONG count);
CK_RV (*sdb_DestroyObject)(SDB *sdb, CK_OBJECT_HANDLE object);
- CK_RV (*sdb_GetPWEntry)(SDB *sdb, SDBPasswordEntry *entry);
- CK_RV (*sdb_PutPWEntry)(SDB *sdb, SDBPasswordEntry *entry);
+ CK_RV (*sdb_GetMetaData)(SDB *sdb, const char *id,
+ SECItem *item1, SECItem *item2);
+ CK_RV (*sdb_PutMetaData)(SDB *sdb, const char *id,
+ const SECItem *item1, const SECItem *item2);
CK_RV (*sdb_Begin)(SDB *sdb);
CK_RV (*sdb_Commit)(SDB *sdb);
CK_RV (*sdb_Abort)(SDB *sdb);
@@ -95,12 +96,6 @@ struct SDBStr {
CK_RV (*sdb_Close)(SDB *sdb);
};
-struct SDBPasswordEntryStr {
- SECItem salt;
- SECItem value;
- unsigned char data[128];
-};
-
CK_RV s_open(const char *directory, const char *certPrefix,
const char *keyPrefix,
int cert_version, int key_version,
@@ -111,5 +106,6 @@ CK_RV s_shutdown();
#define SDB_RDONLY 1
#define SDB_RDWR 2
#define SDB_CREATE 4
+#define SDB_HAS_META 8
#endif
diff --git a/security/nss/lib/softoken/sftkdb.c b/security/nss/lib/softoken/sftkdb.c
index ebb0e5160..e079b8a96 100644
--- a/security/nss/lib/softoken/sftkdb.c
+++ b/security/nss/lib/softoken/sftkdb.c
@@ -64,6 +64,7 @@
#include "secdert.h"
#include "prsystem.h"
#include "lgglue.h"
+#include "secerr.h"
/*
* private defines
@@ -85,10 +86,18 @@ struct SFTKDBHandleStr {
#define SFTK_OBJ_ID_MASK (~SFTK_OBJ_TYPE_MASK)
#define SFTK_TOKEN_TYPE 0x80000000
-static SECStatus sftkdb_decrypt(SECItem *passKey, SECItem *cipherText,
+static SECStatus sftkdb_decryptAttribute(SECItem *passKey, SECItem *cipherText,
SECItem **plainText);
-static SECStatus sftkdb_encrypt(PLArenaPool *arena, SECItem *passKey,
+static SECStatus sftkdb_encryptAttribute(PLArenaPool *arena, SECItem *passKey,
SECItem *plainText, SECItem **cipherText);
+static SECStatus sftkdb_signAttribute(PLArenaPool *arena, SECItem *passKey,
+ CK_OBJECT_HANDLE objectID,
+ CK_ATTRIBUTE_TYPE attrType,
+ SECItem *plainText, SECItem **sigText);
+static SECStatus sftkdb_verifyAttribute(SECItem *passKey,
+ CK_OBJECT_HANDLE objectID,
+ CK_ATTRIBUTE_TYPE attrType,
+ SECItem *plainText, SECItem *sigText);
/*
@@ -104,7 +113,7 @@ static SECStatus sftkdb_encrypt(PLArenaPool *arena, SECItem *passKey,
#define BBP 8
static PRBool
-sftkdb_isULONG(CK_ATTRIBUTE_TYPE type)
+sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type)
{
switch(type) {
case CKA_CLASS:
@@ -140,7 +149,7 @@ sftkdb_isULONG(CK_ATTRIBUTE_TYPE type)
/* are the attributes private? */
static PRBool
-sftkdb_isPrivate(CK_ATTRIBUTE_TYPE type)
+sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type)
{
switch(type) {
case CKA_VALUE:
@@ -157,6 +166,42 @@ sftkdb_isPrivate(CK_ATTRIBUTE_TYPE type)
return PR_FALSE;
}
+/* These attributes must be authenticated with an hmac. */
+static PRBool
+sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type)
+{
+ switch(type) {
+ case CKA_MODULUS:
+ case CKA_PUBLIC_EXPONENT:
+ case CKA_CERT_SHA1_HASH:
+ case CKA_CERT_MD5_HASH:
+ case CKA_TRUST_SERVER_AUTH:
+ case CKA_TRUST_CLIENT_AUTH:
+ case CKA_TRUST_EMAIL_PROTECTION:
+ case CKA_TRUST_CODE_SIGNING:
+ case CKA_TRUST_STEP_UP_APPROVED:
+ case CKA_NSS_OVERRIDE_EXTENSIONS:
+ return PR_TRUE;
+ default:
+ break;
+ }
+ return PR_FALSE;
+}
+
+/*
+ * convert a native ULONG to a database ulong. Database ulong's
+ * are all 4 byte big endian values.
+ */
+static void
+sftk_uLong2DBULong(unsigned char *data, CK_ULONG value)
+{
+ int i;
+
+ for (i=0; i < DB_ULONG_SIZE; i++) {
+ data[i] = (value >> (DB_ULONG_SIZE-1-i)*BBP) & 0xff;
+ }
+}
+
/*
* fix up the input templates. Our fixed up ints are stored in data and must
* be freed by the caller. The new template must also be freed. If there are no
@@ -166,7 +211,7 @@ static CK_ATTRIBUTE *
sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
unsigned char **dataOut)
{
- int i,j;
+ int i;
int ulongCount = 0;
unsigned char *data;
CK_ATTRIBUTE *ntemplate;
@@ -180,7 +225,7 @@ sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
continue;
}
if (template[i].ulValueLen == sizeof (CK_ULONG)) {
- if ( sftkdb_isULONG(template[i].type)) {
+ if ( sftkdb_isULONGAttribute(template[i].type)) {
ulongCount++;
}
}
@@ -211,11 +256,9 @@ sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
continue;
}
if (template[i].ulValueLen == sizeof (CK_ULONG)) {
- if ( sftkdb_isULONG(template[i].type) ) {
+ if ( sftkdb_isULONGAttribute(template[i].type) ) {
CK_ULONG value = *(CK_ULONG *) template[i].pValue;
- for (j=0; j < DB_ULONG_SIZE; j++) {
- data[j] = (value >> (DB_ULONG_SIZE-1-j)*BBP) & 0xff;
- }
+ sftk_uLong2DBULong(data, value);
ntemplate[i].pValue = data;
ntemplate[i].ulValueLen = DB_ULONG_SIZE;
data += DB_ULONG_SIZE;
@@ -225,6 +268,66 @@ sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
return ntemplate;
}
+#define GET_SDB(handle) ((handle)->update ? (handle)->update : (handle)->db)
+
+static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x";
+
+/*
+ * Some attributes are signed with an Hmac and a pbe key generated from
+ * the password. This signature is stored indexed by object handle and
+ * attribute type in the meta data table in the key database.
+ *
+ * Signature entries are indexed by the string
+ * sig_[cert/key]_{ObjectID}_{Attribute}
+ *
+ * This function fetches that pkcs5 signature. Caller supplies a SECItem
+ * pre-allocated to the appropriate size if the SECItem is too small the
+ * function will fail with CKR_BUFFER_TOO_SMALL.
+ */
+static CK_RV
+sftkdb_getAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle,
+ CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
+ SECItem *signText)
+{
+ SDB *db;
+ char id[30];
+ CK_RV crv;
+
+ db = GET_SDB(keyHandle);
+
+ sprintf(id, SFTKDB_META_SIG_TEMPLATE,
+ handle->type == SFTK_KEYDB_TYPE ? "key":"cert",
+ (unsigned int)objectID, (unsigned int)type);
+
+ crv = (*db->sdb_GetMetaData)(db, id, signText, NULL);
+ return crv;
+}
+
+/*
+ * Some attributes are signed with an Hmac and a pbe key generated from
+ * the password. This signature is stored indexed by object handle and
+ * attribute type in the meta data table in the key database.
+ *
+ * Signature entries are indexed by the string
+ * sig_[cert/key]_{ObjectID}_{Attribute}
+ *
+ * This function stores that pkcs5 signature.
+ */
+static CK_RV
+sftkdb_putAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget,
+ CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
+ SECItem *signText)
+{
+ char id[30];
+ CK_RV crv;
+
+ sprintf(id, SFTKDB_META_SIG_TEMPLATE,
+ handle->type == SFTK_KEYDB_TYPE ? "key":"cert",
+ (unsigned int)objectID, (unsigned int)type);
+
+ crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL);
+ return crv;
+}
/*
@@ -232,18 +335,36 @@ sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
* separate data sections for the database ULONG values.
*/
static CK_RV
-sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_ATTRIBUTE *ntemplate,
- int count, SFTKDBHandle *handle)
+sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID,
+ CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle)
{
int i,j;
CK_RV crv = CKR_OK;
+ SFTKDBHandle *keyHandle;
+ PRBool checkSig = PR_TRUE;
+ PRBool checkEnc = PR_TRUE;
+
+ PORT_Assert(handle);
+
+ /* find the key handle */
+ keyHandle = handle;
+ if (handle->type != SFTK_KEYDB_TYPE) {
+ checkEnc = PR_FALSE;
+ keyHandle = handle->peerDB;
+ }
+
+ if ((keyHandle == NULL) ||
+ ((GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0) ||
+ (keyHandle->passwordKey.data == NULL)) {
+ checkSig = PR_FALSE;
+ }
for (i=0; i < count; i++) {
CK_ULONG length = template[i].ulValueLen;
template[i].ulValueLen = ntemplate[i].ulValueLen;
/* fixup ulongs */
if (ntemplate[i].ulValueLen == DB_ULONG_SIZE) {
- if (sftkdb_isULONG(template[i].type)) {
+ if (sftkdb_isULONGAttribute(template[i].type)) {
if (template[i].pValue) {
CK_ULONG value = 0;
unsigned char *data;
@@ -262,10 +383,15 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_ATTRIBUTE *ntemplate,
template[i].ulValueLen = sizeof(CK_ULONG);
}
}
+
+ /* if no data was retrieved, no need to process encrypted or signed
+ * attributes */
+ if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) {
+ continue;
+ }
+
/* fixup private attributes */
- if ((handle != NULL) && (handle->type == SFTK_KEYDB_TYPE) &&
- (template[i].pValue != NULL) && (template[i].ulValueLen != -1)
- && sftkdb_isPrivate(ntemplate[i].type)) {
+ if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) {
/* we have a private attribute */
/* This code depends on the fact that the cipherText is bigger
* than the plain text */
@@ -282,7 +408,8 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_ATTRIBUTE *ntemplate,
crv = CKR_USER_NOT_LOGGED_IN;
continue;
}
- rv = sftkdb_decrypt(&handle->passwordKey, &cipherText, &plainText);
+ rv = sftkdb_decryptAttribute(&handle->passwordKey,
+ &cipherText, &plainText);
PZ_Unlock(handle->passwordLock);
if (rv != SECSuccess) {
PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
@@ -304,12 +431,154 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_ATTRIBUTE *ntemplate,
template[i].ulValueLen = plainText->len;
SECITEM_FreeItem(plainText,PR_TRUE);
}
+ /* make sure signed attributes are valid */
+ if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) {
+ SECStatus rv;
+ SECItem signText;
+ SECItem plainText;
+ unsigned char signData[SDB_MAX_META_DATA_LEN];
+
+ signText.data = signData;
+ signText.len = sizeof(signData);
+
+ rv = sftkdb_getAttributeSignature(handle, keyHandle,
+ objectID, ntemplate[i].type, &signText);
+ if (rv != SECSuccess) {
+ PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
+ template[i].ulValueLen = -1;
+ crv = CKR_DATA_INVALID; /* better error code? */
+ continue;
+ }
+
+ plainText.data = ntemplate[i].pValue;
+ plainText.len = ntemplate[i].ulValueLen;
+
+ /*
+ * we do a second check holding the lock just in case the user
+ * loggout while we were trying to get the signature.
+ */
+ PZ_Lock(keyHandle->passwordLock);
+ if (keyHandle->passwordKey.data == NULL) {
+ /* if we are no longer logged in, no use checking the other
+ * Signatures either. */
+ checkSig = PR_FALSE;
+ PZ_Unlock(keyHandle->passwordLock);
+ continue;
+ }
+
+ rv = sftkdb_verifyAttribute(&keyHandle->passwordKey,
+ objectID, ntemplate[i].type,
+ &plainText, &signText);
+ PZ_Unlock(keyHandle->passwordLock);
+ if (rv != SECSuccess) {
+ PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
+ template[i].ulValueLen = -1;
+ crv = CKR_SIGNATURE_INVALID; /* better error code? */
+ }
+ /* This Attribute is fine */
+ }
}
return crv;
}
+/*
+ * Some attributes are signed with an HMAC and a pbe key generated from
+ * the password. This signature is stored indexed by object handle and
+ *
+ * Those attributes are:
+ * 1) Trust object hashes and trust values.
+ * 2) public key values.
+ *
+ * Certs themselves are considered properly authenticated by virtue of their
+ * signature, or their matching hash with the trust object.
+ *
+ * These signature is only checked for objects coming from shared databases.
+ * Older dbm style databases have such no signature checks. HMACs are also
+ * only checked when the token is logged in, as it requires a pbe generated
+ * from the password.
+ *
+ * Tokens which have no key database (and therefore no master password) do not
+ * have any stored signature values. Signature values are stored in the key
+ * database, since the signature data is tightly coupled to the key database
+ * password.
+ *
+ * This function takes a template of attributes that were either created or
+ * modified. These attributes are checked to see if the need to be signed.
+ * If they do, then this function signs the attributes and writes them
+ * to the meta data store.
+ *
+ * This function can fail if there are attributes that must be signed, but
+ * the token is not logged in.
+ *
+ * The caller is expected to abort any transaction he was in in the
+ * event of a failure of this function.
+ */
static CK_RV
-sftkdb_CreateObject(SFTKDBHandle *handle, SDB *db, CK_OBJECT_HANDLE *objectID,
+sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle,
+ PRBool mayBeUpdateDB,
+ CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE *template,
+ CK_ULONG count)
+{
+ int i;
+ SFTKDBHandle *keyHandle = handle;
+ SDB *keyTarget = NULL;
+
+ PORT_Assert(handle);
+
+ if (handle->type != SFTK_KEYDB_TYPE) {
+ keyHandle = handle->peerDB;
+ }
+
+ /* no key DB defined? then no need to sign anything */
+ if (keyHandle == NULL) {
+ return CKR_OK;
+ }
+
+ /* When we are in a middle of an update, we have an update database set,
+ * but we want to write to the real database. The bool mayBeUpdateDB is
+ * set to TRUE if it's possible that we want to write an update database
+ * rather than a primary */
+ keyTarget = (mayBeUpdateDB && keyHandle->update) ?
+ keyHandle->update : keyHandle->db;
+
+ /* skip the the database does not support meta data */
+ if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
+ return CKR_OK;
+ }
+
+ for (i=0; i < count; i ++) {
+ if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
+ SECStatus rv;
+ SECItem *signText;
+ SECItem plainText;
+
+ plainText.data = template[i].pValue;
+ plainText.len = template[i].ulValueLen;
+ PZ_Lock(keyHandle->passwordLock);
+ if (keyHandle->passwordKey.data == NULL) {
+ PZ_Unlock(keyHandle->passwordLock);
+ return CKR_USER_NOT_LOGGED_IN;
+ }
+ rv = sftkdb_signAttribute(arena, &keyHandle->passwordKey,
+ objectID, template[i].type,
+ &plainText, &signText);
+ PZ_Unlock(keyHandle->passwordLock);
+ if (rv != SECSuccess) {
+ return CKR_GENERAL_ERROR; /* better error code here? */
+ }
+ rv = sftkdb_putAttributeSignature(handle, keyTarget,
+ objectID, template[i].type, signText);
+ if (rv != SECSuccess) {
+ return CKR_GENERAL_ERROR; /* better error code here? */
+ }
+ }
+ }
+ return CKR_OK;
+}
+
+static CK_RV
+sftkdb_CreateObject(PRArenaPool *arena, SFTKDBHandle *handle,
+ SDB *db, CK_OBJECT_HANDLE *objectID,
CK_ATTRIBUTE *template, CK_ULONG count)
{
PRBool inTransaction = PR_FALSE;
@@ -324,6 +593,11 @@ sftkdb_CreateObject(SFTKDBHandle *handle, SDB *db, CK_OBJECT_HANDLE *objectID,
if (crv != CKR_OK) {
goto loser;
}
+ crv = sftk_signTemplate(arena, handle, (db == handle->update),
+ *objectID, template, count);
+ if (crv != CKR_OK) {
+ goto loser;
+ }
crv = (*db->sdb_Commit)(db);
inTransaction = PR_FALSE;
@@ -339,6 +613,7 @@ loser:
return crv;
}
+
CK_ATTRIBUTE *
sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
SFTKDBHandle *handle,CK_ULONG *pcount,
@@ -348,6 +623,7 @@ sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
CK_ATTRIBUTE *template;
int i, templateIndex;
SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
+ PRBool doEnc = PR_TRUE;
*crv = CKR_OK;
@@ -356,6 +632,12 @@ sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
return NULL;
}
+ PORT_Assert(handle);
+ /* find the key handle */
+ if (handle->type != SFTK_KEYDB_TYPE) {
+ doEnc = PR_FALSE;
+ }
+
PZ_Lock(sessObject->attributeLock);
count = 0;
for (i=0; i < sessObject->hashSize; i++) {
@@ -380,7 +662,7 @@ sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
/* fixup ULONG s */
if ((tp->ulValueLen == sizeof (CK_ULONG)) &&
- (sftkdb_isULONG(tp->type)) ) {
+ (sftkdb_isULONGAttribute(tp->type)) ) {
CK_ULONG value = *(CK_ULONG *) tp->pValue;
unsigned char *data;
int j;
@@ -398,8 +680,7 @@ sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
}
/* encrypt private attributes */
- if ((handle != NULL) && (handle->type == SFTK_KEYDB_TYPE) &&
- sftkdb_isPrivate(tp->type)) {
+ if (doEnc && sftkdb_isPrivateAttribute(tp->type)) {
/* we have a private attribute */
SECItem *cipherText;
@@ -414,8 +695,8 @@ sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
*crv = CKR_USER_NOT_LOGGED_IN;
break;
}
- rv = sftkdb_encrypt(arena, &handle->passwordKey, &plainText,
- &cipherText);
+ rv = sftkdb_encryptAttribute(arena, &handle->passwordKey,
+ &plainText, &cipherText);
PZ_Unlock(handle->passwordLock);
if (rv == SECSuccess) {
tp->pValue = cipherText->data;
@@ -441,8 +722,6 @@ sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
}
-#define GET_SDB(handle) ((handle)->update ? (handle)->update : (handle)->db)
-
CK_RV
sftkdb_write(SFTKDBHandle *handle, SFTKObject *object,
CK_OBJECT_HANDLE *objectID)
@@ -470,7 +749,7 @@ sftkdb_write(SFTKDBHandle *handle, SFTKObject *object,
goto loser;
}
- crv = sftkdb_CreateObject(handle, db, objectID, template, count);
+ crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count);
loser:
if (arena) {
@@ -550,7 +829,7 @@ CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find)
}
CK_RV
-sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id,
+sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
CK_ATTRIBUTE *template, CK_ULONG count)
{
CK_RV crv,crv2;
@@ -600,10 +879,11 @@ sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id,
if (ntemplate == NULL) {
return CKR_HOST_MEMORY;
}
- object_id &= SFTK_OBJ_ID_MASK;
- crv = (*db->sdb_GetAttributeValue)(db, object_id,
+ objectID &= SFTK_OBJ_ID_MASK;
+ crv = (*db->sdb_GetAttributeValue)(db, objectID,
ntemplate, count);
- crv2 = sftkdb_fixupTemplateOut(template, ntemplate, count, handle);
+ crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate,
+ count, handle);
if (crv == CKR_OK) crv = crv2;
if (data) {
PORT_Free(ntemplate);
@@ -614,12 +894,13 @@ sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id,
}
CK_RV
-sftkdb_SetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id,
+sftkdb_SetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
const CK_ATTRIBUTE *template, CK_ULONG count)
{
CK_RV crv = CKR_OK;
CK_ATTRIBUTE *ntemplate;
unsigned char *data = NULL;
+ PLArenaPool *arena = NULL;
SDB *db;
if (handle == NULL) {
@@ -631,17 +912,27 @@ sftkdb_SetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id,
if (count == 0) {
return CKR_OK;
}
+
ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
if (ntemplate == NULL) {
return CKR_HOST_MEMORY;
}
- object_id &= SFTK_OBJ_ID_MASK;
+
+ arena = PORT_NewArena(256);
+ if (arena == NULL) {
+ return CKR_HOST_MEMORY;
+ }
+
+ objectID &= SFTK_OBJ_ID_MASK;
crv = (*db->sdb_Begin)(db);
if (crv != CKR_OK) {
goto loser;
}
- crv = (*db->sdb_SetAttributeValue)(db, object_id,
- ntemplate, count);
+ crv = (*db->sdb_SetAttributeValue)(db, objectID, ntemplate, count);
+ if (crv != CKR_OK) {
+ goto loser;
+ }
+ crv = sftk_signTemplate(arena, handle, PR_TRUE, objectID, ntemplate, count);
if (crv != CKR_OK) {
goto loser;
}
@@ -654,11 +945,12 @@ loser:
PORT_Free(ntemplate);
PORT_Free(data);
}
+ PORT_FreeArena(arena, PR_FALSE);
return crv;
}
CK_RV
-sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id)
+sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID)
{
CK_RV crv = CKR_OK;
SDB *db;
@@ -667,12 +959,12 @@ sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id)
return CKR_TOKEN_WRITE_PROTECTED;
}
db = GET_SDB(handle);
- object_id &= SFTK_OBJ_ID_MASK;
+ objectID &= SFTK_OBJ_ID_MASK;
crv = (*db->sdb_Begin)(db);
if (crv != CKR_OK) {
goto loser;
}
- crv = (*db->sdb_DestroyObject)(db, object_id);
+ crv = (*db->sdb_DestroyObject)(db, objectID);
if (crv != CKR_OK) {
goto loser;
}
@@ -1432,7 +1724,7 @@ loser:
* value will be based to a pkcs5 pbe function before it is used
* in an actual encryption */
static SECStatus
-sftkdb_passwordToKey(SFTKDBHandle *keydb, SDBPasswordEntry *entry,
+sftkdb_passwordToKey(SFTKDBHandle *keydb, SECItem *salt,
const char *pw, SECItem *key)
{
SHA1Context *cx = NULL;
@@ -1449,8 +1741,8 @@ sftkdb_passwordToKey(SFTKDBHandle *keydb, SDBPasswordEntry *entry,
goto loser;
}
SHA1_Begin(cx);
- if (entry && entry->salt.data ) {
- SHA1_Update(cx, entry->salt.data, entry->salt.len);
+ if (salt && salt->data ) {
+ SHA1_Update(cx, salt->data, salt->len);
}
SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw));
SHA1_End(cx, key->data, &key->len, key->len);
@@ -1621,7 +1913,7 @@ loser:
* with SECITEM_FreeItem by the caller.
*/
static SECStatus
-sftkdb_decrypt(SECItem *passKey, SECItem *cipherText, SECItem **plain)
+sftkdb_decryptAttribute(SECItem *passKey, SECItem *cipherText, SECItem **plain)
{
SECStatus rv;
sftkCipherValue cipherValue;
@@ -1658,8 +1950,8 @@ loser:
* salt automatically.
*/
static SECStatus
-sftkdb_encrypt(PLArenaPool *arena, SECItem *passKey, SECItem *plainText,
- SECItem **cipherText)
+sftkdb_encryptAttribute(PLArenaPool *arena, SECItem *passKey,
+ SECItem *plainText, SECItem **cipherText)
{
SECStatus rv;
sftkCipherValue cipherValue;
@@ -1700,6 +1992,188 @@ loser:
return rv;
}
+/*
+ * use the password and the pbe parameters to generate an HMAC for the
+ * given plain text data. This is used by sftkdb_verifyAttribute and
+ * sftkdb_signAttribute. Signature is returned in signData. The caller
+ * must preallocate the space in the secitem.
+ */
+static SECStatus
+sftkdb_pbehash(SECOidTag sigOid, SECItem *passKey,
+ NSSPKCS5PBEParameter *param,
+ CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
+ SECItem *plainText, SECItem *signData)
+{
+ SECStatus rv = SECFailure;
+ SECItem *key = NULL;
+ HMACContext *hashCx = NULL;
+ HASH_HashType hashType = HASH_AlgNULL;
+ const SECHashObject *hashObj;
+ unsigned char addressData[DB_ULONG_SIZE];
+
+ hashType = HASH_FromHMACOid(param->encAlg);
+ if (hashType == HASH_AlgNULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return SECFailure;
+ }
+
+ hashObj = HASH_GetRawHashObject(hashType);
+ if (hashObj == NULL) {
+ goto loser;
+ }
+
+ key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE);
+ if (!key) {
+ goto loser;
+ }
+
+ hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE);
+ if (!hashCx) {
+ goto loser;
+ }
+ HMAC_Begin(hashCx);
+ /* Tie this value to a particular object. This is most important for
+ * the trust attributes, where and attacker could copy a value for
+ * 'validCA' from another cert in the database */
+ sftk_uLong2DBULong(addressData, objectID);
+ HMAC_Update(hashCx, addressData, DB_ULONG_SIZE);
+ sftk_uLong2DBULong(addressData, attrType);
+ HMAC_Update(hashCx, addressData, DB_ULONG_SIZE);
+
+ HMAC_Update(hashCx, plainText->data, plainText->len);
+ rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len);
+
+loser:
+ if (hashCx) {
+ HMAC_Destroy(hashCx, PR_TRUE);
+ }
+ if (key) {
+ SECITEM_FreeItem(key,PR_TRUE);
+ }
+ return rv;
+}
+
+/*
+ * Use our key to verify a signText block from the database matches
+ * the plainText from the database. The signText is a PKCS 5 v2 pbe.
+ * plainText is the plainText of the attribute.
+ */
+static SECStatus
+sftkdb_verifyAttribute(SECItem *passKey, CK_OBJECT_HANDLE objectID,
+ CK_ATTRIBUTE_TYPE attrType,
+ SECItem *plainText, SECItem *signText)
+{
+ SECStatus rv;
+ sftkCipherValue signValue;
+ SECItem signature;
+ unsigned char signData[HASH_LENGTH_MAX];
+
+
+ /* First get the cipher type */
+ rv = sftkdb_decodeCipherText(signText, &signValue);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ signature.data = signData;
+ signature.len = sizeof(signData);
+
+ rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param,
+ objectID, attrType, plainText, &signature);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (SECITEM_CompareItem(&signValue.value,&signature) != 0) {
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ rv = SECFailure;
+ }
+
+loser:
+ if (signValue.param) {
+ nsspkcs5_DestroyPBEParameter(signValue.param);
+ }
+ if (signValue.arena) {
+ PORT_FreeArena(signValue.arena,PR_FALSE);
+ }
+ return rv;
+}
+
+/*
+ * Use our key to create a signText block the plain text of an
+ * attribute. The signText is a PKCS 5 v2 pbe.
+ */
+static SECStatus
+sftkdb_signAttribute(PLArenaPool *arena, SECItem *passKey,
+ CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
+ SECItem *plainText, SECItem **signature)
+{
+ SECStatus rv;
+ sftkCipherValue signValue;
+ NSSPKCS5PBEParameter *param = NULL;
+ unsigned char saltData[HASH_LENGTH_MAX];
+ unsigned char signData[HASH_LENGTH_MAX];
+ SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */
+ SECOidTag prfAlg = SEC_OID_HMAC_SHA256; /* hash for pb key generation */
+ HASH_HashType prfType;
+ unsigned int hmacLength;
+ unsigned int prfLength;
+
+ /* this code allows us to fetch the lengths and hashes on the fly
+ * by simply changing the OID above */
+ prfType = HASH_FromHMACOid(prfAlg);
+ PORT_Assert(prfType != HASH_AlgNULL);
+ prfLength = HASH_GetRawHashObject(prfType)->length;
+ PORT_Assert(prfLength <= HASH_LENGTH_MAX);
+
+ hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length;
+ PORT_Assert(hmacLength <= HASH_LENGTH_MAX);
+
+ /* initialize our CipherValue structure */
+ signValue.alg = SEC_OID_PKCS5_PBMAC1;
+ signValue.salt.len = prfLength;
+ signValue.salt.data = saltData;
+ signValue.value.data = signData;
+ signValue.value.len = hmacLength;
+ RNG_GenerateGlobalRandomBytes(saltData,prfLength);
+
+ /* initialize our pkcs5 paramter */
+ param = nsspkcs5_NewParam(signValue.alg, &signValue.salt, 1);
+ if (param == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ param->keyID = pbeBitGenIntegrityKey;
+ /* set the PKCS 5 v2 parameters, not extractable from the
+ * data passed into nsspkcs5_NewParam */
+ param->encAlg = hmacAlg;
+ param->hashType = prfType;
+ param->keyLen = hmacLength;
+ rv = SECOID_SetAlgorithmID(param->poolp, &param->prfAlg, prfAlg, NULL);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+
+ /* calculate the mac */
+ rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType,
+ plainText, &signValue.value);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ signValue.param = param;
+
+ /* write it out */
+ rv = sftkdb_encodeCipherText(arena, &signValue, signature);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+loser:
+ if (param) {
+ nsspkcs5_DestroyPBEParameter(param);
+ }
+ return rv;
+}
+
/*
* stub files for legacy db's to be able to encrypt and decrypt
@@ -1733,7 +2207,7 @@ sftkdb_encrypt_stub(PRArenaPool *arena, SDB *sdb, SECItem *plainText,
return SECFailure;
}
- rv = sftkdb_encrypt(arena,
+ rv = sftkdb_encryptAttribute(arena,
handle->newKey?handle->newKey:&handle->passwordKey,
plainText, cipherText);
PZ_Unlock(handle->passwordLock);
@@ -1771,7 +2245,7 @@ sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText)
/* PORT_SetError */
return SECFailure;
}
- rv = sftkdb_decrypt(&handle->passwordKey, cipherText, plainText);
+ rv = sftkdb_decryptAttribute(&handle->passwordKey, cipherText, plainText);
PZ_Unlock(handle->passwordLock);
return rv;
@@ -1781,8 +2255,8 @@ sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText)
* safely swith the passed in key for the one caches in the keydb handle
*
* A key attached to the handle tells us the the token is logged in.
- * We can used the key attached to the handle in sftkdb_encrypt
- * and sftkdb_decrypt calls.
+ * We can used the key attached to the handle in sftkdb_encryptAttribute
+ * and sftkdb_decryptAttribute calls.
*/
static void
sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey)
@@ -1831,11 +2305,11 @@ static const CK_ATTRIBUTE_TYPE known_attributes[] = {
CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
- CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NETSCAPE_URL, CKA_NETSCAPE_EMAIL,
- CKA_NETSCAPE_SMIME_INFO, CKA_NETSCAPE_SMIME_TIMESTAMP,
- CKA_NETSCAPE_PKCS8_SALT, CKA_NETSCAPE_PASSWORD_CHECK, CKA_NETSCAPE_EXPIRES,
- CKA_NETSCAPE_KRL, CKA_NETSCAPE_PQG_COUNTER, CKA_NETSCAPE_PQG_SEED,
- CKA_NETSCAPE_PQG_H, CKA_NETSCAPE_PQG_SEED_BITS, CKA_NETSCAPE_MODULE_SPEC,
+ CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL,
+ CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
+ CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES,
+ CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED,
+ CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC,
CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION,
CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT,
CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN,
@@ -1919,12 +2393,18 @@ sftkdb_copyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, SECItem *key)
SDB *target = handle->db;
int i;
CK_RV crv;
+ PLArenaPool *arena = NULL;
+
+ arena = PORT_NewArena(256);
+ if (arena == NULL) {
+ return CKR_HOST_MEMORY;
+ }
ptemplate = &template[0];
id &= SFTK_OBJ_ID_MASK;
crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes);
if (crv == CKR_BUFFER_TOO_SMALL) {
- ptemplate = PORT_NewArray(CK_ATTRIBUTE, max_attributes);
+ ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes);
if (ptemplate == NULL) {
crv = CKR_HOST_MEMORY;
} else {
@@ -1937,7 +2417,7 @@ sftkdb_copyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, SECItem *key)
}
for (i=0; i < max_attributes; i++) {
- ptemplate[i].pValue = PORT_Alloc(ptemplate[i].ulValueLen);
+ ptemplate[i].pValue = PORT_ArenaAlloc(arena,ptemplate[i].ulValueLen);
if (ptemplate[i].pValue == NULL) {
crv = CKR_HOST_MEMORY;
goto loser;
@@ -1949,22 +2429,12 @@ sftkdb_copyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, SECItem *key)
goto loser;
}
- crv = sftkdb_CreateObject(handle, target, &id, ptemplate, max_attributes);
- if (ptemplate && ptemplate != template) {
- PORT_Free(ptemplate);
- }
+ crv = sftkdb_CreateObject(arena, handle, target, &id,
+ ptemplate, max_attributes);
loser:
- if (ptemplate) {
- for (i=0; i < max_attributes; i++) {
- if (ptemplate[i].pValue) {
- PORT_Memset(ptemplate[i].pValue, 0, ptemplate[i].ulValueLen);
- PORT_Free(ptemplate[i].pValue);
- }
- }
- if (ptemplate != template) {
- PORT_Free(ptemplate);
- }
+ if (arena) {
+ PORT_FreeArena(arena,PR_TRUE);
}
return crv;
}
@@ -2009,17 +2479,24 @@ sftkdb_update(SFTKDBHandle *handle, SECItem *key)
loser:
/* update Meta data - even if we didn't update objects */
if (handle->type == SFTK_KEYDB_TYPE) {
- SDBPasswordEntry entry;
+ SECItem item1, item2;
+ unsigned char data1[SDB_MAX_META_DATA_LEN];
+ unsigned char data2[SDB_MAX_META_DATA_LEN];
+
crv = (*handle->db->sdb_Begin)(handle->db);
if (crv != CKR_OK) {
goto loser2;
}
inTransaction = PR_TRUE;
- crv = (*handle->update->sdb_GetPWEntry)(handle->update, & entry);
+ item1.data = data1;
+ item2.data = data2;
+ crv = (*handle->update->sdb_GetMetaData)(handle->update, "password",
+ &item1, &item2);
if (crv != CKR_OK) {
goto loser2;
}
- crv = (*handle->db->sdb_PutPWEntry)(handle->db, &entry);
+ crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1,
+ &item2);
if (crv != CKR_OK) {
goto loser2;
}
@@ -2045,7 +2522,9 @@ loser2:
SECStatus
sftkdb_HasPasswordSet(SFTKDBHandle *keydb)
{
- SDBPasswordEntry entry;
+ SECItem item1, item2;
+ unsigned char data1[SDB_MAX_META_DATA_LEN];
+ unsigned char data2[SDB_MAX_META_DATA_LEN];
CK_RV crv;
SDB *db;
@@ -2058,7 +2537,9 @@ sftkdb_HasPasswordSet(SFTKDBHandle *keydb)
return SECFailure;
}
- crv = (*db->sdb_GetPWEntry)(db, &entry);
+ item1.data = data1;
+ item2.data = data2;
+ crv = (*db->sdb_GetMetaData)(db, "password", &item1, &item2);
return (crv == CKR_OK) ? SECSuccess : SECFailure;
}
@@ -2072,7 +2553,9 @@ SECStatus
sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw)
{
SECStatus rv;
- SDBPasswordEntry entry;
+ SECItem salt, value;
+ unsigned char data1[SDB_MAX_META_DATA_LEN];
+ unsigned char data2[SDB_MAX_META_DATA_LEN];
SECItem key;
SECItem *result = NULL;
SDB *db;
@@ -2093,20 +2576,22 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw)
if (pw == NULL) pw="";
/* get the entry from the database */
- crv = (*db->sdb_GetPWEntry)(db, &entry);
+ salt.data = data1;
+ value.data = data2;
+ crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
if (crv != CKR_OK) {
rv = SECFailure;
goto loser;
}
/* get our intermediate key based on the entry salt value */
- rv = sftkdb_passwordToKey(keydb, &entry, pw, &key);
+ rv = sftkdb_passwordToKey(keydb, &salt, pw, &key);
if (rv != SECSuccess) {
goto loser;
}
/* decrypt the entry value */
- rv = sftkdb_decrypt(&key, &entry.value, &result);
+ rv = sftkdb_decryptAttribute(&key, &value, &result);
if (rv != SECSuccess) {
goto loser;
}
@@ -2247,7 +2732,7 @@ sftk_convertPrivateAttributes(SFTKDBHandle *keydb, CK_OBJECT_HANDLE id,
plainText.data = first[i].pValue;
plainText.len = first[i].ulValueLen;
- rv = sftkdb_encrypt(arena, newKey, &plainText, &result);
+ rv = sftkdb_encryptAttribute(arena, newKey, &plainText, &result);
if (rv != SECSuccess) {
goto loser;
}
@@ -2332,7 +2817,9 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb, char *oldPin, char *newPin)
SECItem plainText;
SECItem newKey;
SECItem *result = NULL;
- SDBPasswordEntry entry;
+ SECItem salt, value;
+ unsigned char data1[SDB_MAX_META_DATA_LEN];
+ unsigned char data2[SDB_MAX_META_DATA_LEN];
CK_RV crv;
SDB *db;
@@ -2353,19 +2840,20 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb, char *oldPin, char *newPin)
rv = SECFailure;
goto loser;
}
- crv = (*db->sdb_GetPWEntry)(db, &entry);
+ salt.data = data1;
+ value.data = data2;
+ crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
if (crv == CKR_OK) {
rv = sftkdb_CheckPassword(keydb, oldPin);
if (rv == SECFailure) {
goto loser;
}
} else {
- entry.salt.data = entry.data;
- entry.salt.len = SALT_LENGTH;
- RNG_GenerateGlobalRandomBytes(entry.data,entry.salt.len);
+ salt.len = SALT_LENGTH;
+ RNG_GenerateGlobalRandomBytes(salt.data,salt.len);
}
- rv = sftkdb_passwordToKey(keydb, &entry, newPin, &newKey);
+ rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
if (rv != SECSuccess) {
goto loser;
}
@@ -2383,13 +2871,13 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb, char *oldPin, char *newPin)
plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
plainText.len = SFTK_PW_CHECK_LEN;
- rv = sftkdb_encrypt(NULL, &newKey, &plainText, &result);
+ rv = sftkdb_encryptAttribute(NULL, &newKey, &plainText, &result);
if (rv != SECSuccess) {
goto loser;
}
- entry.value.data = result->data;
- entry.value.len = result->len;
- crv = (*keydb->db->sdb_PutPWEntry)(keydb->db, &entry);
+ value.data = result->data;
+ value.len = result->len;
+ crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value);
if (crv != CKR_OK) {
rv = SECFailure;
goto loser;
diff --git a/security/nss/lib/softoken/sftkdbt.h b/security/nss/lib/softoken/sftkdbt.h
index f9d7c9eaa..3d59514d2 100644
--- a/security/nss/lib/softoken/sftkdbt.h
+++ b/security/nss/lib/softoken/sftkdbt.h
@@ -7,6 +7,8 @@
#define SFTKDBT_H 1
typedef struct SFTKDBHandleStr SFTKDBHandle;
+#define SDB_MAX_META_DATA_LEN 256
+
typedef enum {
SDB_SQL,
SDB_EXTERN,
diff --git a/security/nss/lib/softoken/softoken.h b/security/nss/lib/softoken/softoken.h
index 6078c40b2..c96c75f2f 100644
--- a/security/nss/lib/softoken/softoken.h
+++ b/security/nss/lib/softoken/softoken.h
@@ -155,18 +155,21 @@ extern SECStatus EC_CopyParams(PRArenaPool *arena, ECParams *dstParams,
/*
-** Prepare a buffer for DES encryption, growing to the appropriate boundary,
-** filling with the appropriate padding.
-** We add from 1 to DES_KEY_LENGTH bytes -- we *always* grow.
+** Prepare a buffer for padded CBC encryption, growing to the appropriate
+** boundary, filling with the appropriate padding.
+**
+** blockSize must be a power of 2.
+**
+** We add from 1 to blockSize bytes -- we *always* grow.
** The extra bytes contain the value of the length of the padding:
** if we have 2 bytes of padding, then the padding is "0x02, 0x02".
**
** NOTE: If arena is non-NULL, we re-allocate from there, otherwise
** we assume (and use) PR memory (re)allocation.
-** Maybe this belongs in util?
*/
-extern unsigned char * DES_PadBuffer(PRArenaPool *arena, unsigned char *inbuf,
- unsigned int inlen, unsigned int *outlen);
+extern unsigned char * CBC_PadBuffer(PRArenaPool *arena, unsigned char *inbuf,
+ unsigned int inlen, unsigned int *outlen,
+ int blockSize);
/****************************************/