security/nss/lib/softoken/sftkpwd.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 /* 
     5  *  The following code handles the storage of PKCS 11 modules used by the
     6  * NSS. For the rest of NSS, only one kind of database handle exists:
     7  *
     8  *     SFTKDBHandle
     9  *
    10  * There is one SFTKDBHandle for the each key database and one for each cert 
    11  * database. These databases are opened as associated pairs, one pair per
    12  * slot. SFTKDBHandles are reference counted objects.
    13  *
    14  * Each SFTKDBHandle points to a low level database handle (SDB). This handle
    15  * represents the underlying physical database. These objects are not 
    16  * reference counted, an are 'owned' by their respective SFTKDBHandles.
    17  *
    18  *  
    19  */
    20 #include "sftkdb.h"
    21 #include "sftkdbti.h"
    22 #include "pkcs11t.h"
    23 #include "pkcs11i.h"
    24 #include "sdb.h"
    25 #include "prprf.h" 
    26 #include "secasn1.h"
    27 #include "pratom.h"
    28 #include "blapi.h"
    29 #include "secoid.h"
    30 #include "lowpbe.h"
    31 #include "secdert.h"
    32 #include "prsystem.h"
    33 #include "lgglue.h"
    34 #include "secerr.h"
    35 #include "softoken.h"
    37 /******************************************************************
    38  * 
    39  * Key DB password handling functions
    40  *
    41  * These functions manage the key db password (set, reset, initialize, use).
    42  *
    43  * The key is managed on 'this side' of the database. All private data is
    44  * encrypted before it is sent to the database itself. Besides PBE's, the
    45  * database management code can also mix in various fixed keys so the data
    46  * in the database is no longer considered 'plain text'.
    47  */
    50 /* take string password and turn it into a key. The key is dependent
    51  * on a global salt entry acquired from the database. This salted
    52  * value will be based to a pkcs5 pbe function before it is used
    53  * in an actual encryption */
    54 static SECStatus
    55 sftkdb_passwordToKey(SFTKDBHandle *keydb, SECItem *salt,
    56 			const char *pw, SECItem *key)
    57 {
    58     SHA1Context *cx = NULL;
    59     SECStatus rv = SECFailure;
    61     key->data = PORT_Alloc(SHA1_LENGTH);
    62     if (key->data == NULL) {
    63 	goto loser;
    64     }
    65     key->len = SHA1_LENGTH;
    67     cx = SHA1_NewContext();
    68     if ( cx == NULL) {
    69 	goto loser;
    70     }
    71     SHA1_Begin(cx);
    72     if (salt  && salt->data ) {
    73 	SHA1_Update(cx, salt->data, salt->len);
    74     }
    75     SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw));
    76     SHA1_End(cx, key->data, &key->len, key->len);
    77     rv = SECSuccess;
    79 loser:
    80     if (cx) {
    81 	SHA1_DestroyContext(cx, PR_TRUE);
    82     }
    83     if (rv != SECSuccess) {
    84 	if (key->data != NULL) {
    85 	    PORT_ZFree(key->data,key->len);
    86 	}
    87 	key->data = NULL;
    88     }
    89     return rv;
    90 }
    92 /*
    93  * Cipher text stored in the database contains 3 elements:
    94  * 1) an identifier describing the encryption algorithm.
    95  * 2) an entry specific salt value.
    96  * 3) the encrypted value.
    97  *
    98  * The following data structure represents the encrypted data in a decoded
    99  * (but still encrypted) form.
   100  */
   101 typedef struct sftkCipherValueStr sftkCipherValue;
   102 struct sftkCipherValueStr {
   103     PLArenaPool *arena;
   104     SECOidTag  alg;
   105     NSSPKCS5PBEParameter *param;
   106     SECItem    salt;
   107     SECItem    value;
   108 };
   110 #define SFTK_CIPHERTEXT_VERSION 3
   112 struct SFTKDBEncryptedDataInfoStr {
   113     SECAlgorithmID algorithm;
   114     SECItem encryptedData;
   115 };
   116 typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo;
   118 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
   120 const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate[] = {
   121     { SEC_ASN1_SEQUENCE,
   122         0, NULL, sizeof(SFTKDBEncryptedDataInfo) },
   123     { SEC_ASN1_INLINE | SEC_ASN1_XTRN ,
   124         offsetof(SFTKDBEncryptedDataInfo,algorithm),
   125         SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
   126     { SEC_ASN1_OCTET_STRING,
   127         offsetof(SFTKDBEncryptedDataInfo,encryptedData) },
   128     { 0 }
   129 };
   131 /*
   132  * This parses the cipherText into cipher value. NOTE: cipherValue will point
   133  * to data in cipherText, if cipherText is freed, cipherValue will be invalid.
   134  */
   135 static SECStatus
   136 sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue)
   137 {
   138     PLArenaPool *arena = NULL;
   139     SFTKDBEncryptedDataInfo edi;
   140     SECStatus rv;
   142     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   143     if (arena == NULL) {
   144 	return SECFailure;
   145     }
   146     cipherValue->arena = NULL;
   147     cipherValue->param = NULL;
   149     rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate,
   150                             cipherText);
   151     if (rv != SECSuccess) {
   152 	goto loser;
   153     }
   154     cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm);
   155     cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm);
   156     if (cipherValue->param == NULL) {
   157 	goto loser;
   158     }
   159     cipherValue->value = edi.encryptedData;
   160     cipherValue->arena = arena;
   162     return SECSuccess;
   163 loser:
   164     if (cipherValue->param) {
   165 	nsspkcs5_DestroyPBEParameter(cipherValue->param);
   166 	cipherValue->param = NULL;
   167     }
   168     if (arena) {
   169 	PORT_FreeArena(arena,PR_FALSE);
   170     }
   171     return SECFailure;
   172 }
   176 /* 
   177  * unlike decode, Encode actually allocates a SECItem the caller must free
   178  * The caller can pass an optional arena to to indicate where to place
   179  * the resultant cipherText.
   180  */
   181 static SECStatus
   182 sftkdb_encodeCipherText(PLArenaPool *arena, sftkCipherValue *cipherValue, 
   183                         SECItem **cipherText)
   184 {
   185     SFTKDBEncryptedDataInfo edi;
   186     SECAlgorithmID *algid;
   187     SECStatus rv;
   188     PLArenaPool *localArena = NULL;
   191     localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   192     if (localArena == NULL) {
   193 	return SECFailure;
   194     }
   196     algid = nsspkcs5_CreateAlgorithmID(localArena, cipherValue->alg, 
   197 					cipherValue->param);
   198     if (algid == NULL) {
   199 	rv = SECFailure;
   200 	goto loser;
   201     }
   202     rv = SECOID_CopyAlgorithmID(localArena, &edi.algorithm, algid);
   203     SECOID_DestroyAlgorithmID(algid, PR_TRUE);
   204     if (rv != SECSuccess) {
   205 	goto loser;
   206     }
   207     edi.encryptedData = cipherValue->value;
   209     *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi, 
   210 				    sftkdb_EncryptedDataInfoTemplate);
   211     if (*cipherText == NULL) {
   212 	rv = SECFailure;
   213     }
   215 loser:
   216     if (localArena) {
   217 	PORT_FreeArena(localArena,PR_FALSE);
   218     }
   220     return rv;
   221 }
   224 /*
   225  * Use our key to decode a cipherText block from the database.
   226  *
   227  * plain text is allocated by nsspkcs5_CipherData and must be freed
   228  * with SECITEM_FreeItem by the caller.
   229  */
   230 SECStatus
   231 sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText, SECItem **plain) 
   232 {
   233     SECStatus rv;
   234     sftkCipherValue cipherValue;
   236     /* First get the cipher type */
   237     rv = sftkdb_decodeCipherText(cipherText, &cipherValue);
   238     if (rv != SECSuccess) {
   239 	goto loser;
   240     }
   242     *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value, 
   243 				    PR_FALSE, NULL);
   244     if (*plain == NULL) {
   245 	rv = SECFailure;
   246 	goto loser;
   247     } 
   249 loser:
   250     if (cipherValue.param) {
   251 	nsspkcs5_DestroyPBEParameter(cipherValue.param);
   252     }
   253     if (cipherValue.arena) {
   254 	PORT_FreeArena(cipherValue.arena,PR_FALSE);
   255     }
   256     return rv;
   257 }
   259 /*
   260  * encrypt a block. This function returned the encrypted ciphertext which
   261  * the caller must free. If the caller provides an arena, cipherText will
   262  * be allocated out of that arena. This also generated the per entry
   263  * salt automatically.
   264  */
   265 SECStatus
   266 sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey, 
   267 		SECItem *plainText, SECItem **cipherText) 
   268 {
   269     SECStatus rv;
   270     sftkCipherValue cipherValue;
   271     SECItem *cipher = NULL;
   272     NSSPKCS5PBEParameter *param = NULL;
   273     unsigned char saltData[HASH_LENGTH_MAX];
   275     cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
   276     cipherValue.salt.len = SHA1_LENGTH;
   277     cipherValue.salt.data = saltData;
   278     RNG_GenerateGlobalRandomBytes(saltData,cipherValue.salt.len);
   280     param = nsspkcs5_NewParam(cipherValue.alg, &cipherValue.salt, 1);
   281     if (param == NULL) {
   282 	rv = SECFailure;
   283 	goto loser;
   284     }
   285     cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL);
   286     if (cipher == NULL) {
   287 	rv = SECFailure;
   288 	goto loser;
   289     } 
   290     cipherValue.value = *cipher;
   291     cipherValue.param = param;
   293     rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText);
   294     if (rv != SECSuccess) {
   295 	goto loser;
   296     }
   298 loser:
   299     if (cipher) {
   300 	SECITEM_FreeItem(cipher, PR_TRUE);
   301     }
   302     if (param) {
   303 	nsspkcs5_DestroyPBEParameter(param);
   304     }
   305     return rv;
   306 }
   308 /*
   309  * use the password and the pbe parameters to generate an HMAC for the
   310  * given plain text data. This is used by sftkdb_VerifyAttribute and
   311  * sftkdb_SignAttribute. Signature is returned in signData. The caller
   312  * must preallocate the space in the secitem.
   313  */
   314 static SECStatus
   315 sftkdb_pbehash(SECOidTag sigOid, SECItem *passKey, 
   316 	       NSSPKCS5PBEParameter *param,
   317 	       CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
   318 	       SECItem *plainText, SECItem *signData)
   319 {
   320     SECStatus rv = SECFailure;
   321     SECItem *key = NULL;
   322     HMACContext *hashCx = NULL;
   323     HASH_HashType hashType = HASH_AlgNULL;
   324     const SECHashObject *hashObj;
   325     unsigned char addressData[SDB_ULONG_SIZE];
   327     hashType = HASH_FromHMACOid(param->encAlg);
   328     if (hashType == HASH_AlgNULL) {
   329 	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   330 	return SECFailure;
   331     }
   333     hashObj = HASH_GetRawHashObject(hashType);
   334     if (hashObj == NULL) {
   335 	goto loser;
   336     }
   338     key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE);
   339     if (!key) {
   340 	goto loser;
   341     }
   343     hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE);
   344     if (!hashCx) {
   345 	goto loser;
   346     }
   347     HMAC_Begin(hashCx);
   348     /* Tie this value to a particular object. This is most important for
   349      * the trust attributes, where and attacker could copy a value for
   350      * 'validCA' from another cert in the database */
   351     sftk_ULong2SDBULong(addressData, objectID);
   352     HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
   353     sftk_ULong2SDBULong(addressData, attrType);
   354     HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
   356     HMAC_Update(hashCx, plainText->data, plainText->len);
   357     rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len);
   359 loser:
   360     if (hashCx) {
   361 	HMAC_Destroy(hashCx, PR_TRUE);
   362     }
   363     if (key) {
   364 	SECITEM_FreeItem(key,PR_TRUE);
   365     }
   366     return rv;
   367 }
   369 /*
   370  * Use our key to verify a signText block from the database matches
   371  * the plainText from the database. The signText is a PKCS 5 v2 pbe.
   372  * plainText is the plainText of the attribute.
   373  */
   374 SECStatus
   375 sftkdb_VerifyAttribute(SECItem *passKey, CK_OBJECT_HANDLE objectID, 
   376 	     CK_ATTRIBUTE_TYPE attrType, 
   377 	     SECItem *plainText, SECItem *signText) 
   378 {
   379     SECStatus rv;
   380     sftkCipherValue signValue;
   381     SECItem signature;
   382     unsigned char signData[HASH_LENGTH_MAX];
   385     /* First get the cipher type */
   386     rv = sftkdb_decodeCipherText(signText, &signValue);
   387     if (rv != SECSuccess) {
   388 	goto loser;
   389     }
   390     signature.data = signData;
   391     signature.len = sizeof(signData);
   393     rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param, 
   394 			objectID, attrType, plainText, &signature);
   395     if (rv != SECSuccess) {
   396 	goto loser;
   397     }
   398     if (SECITEM_CompareItem(&signValue.value,&signature) != 0) {
   399 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   400 	rv = SECFailure;
   401     }
   403 loser:
   404     if (signValue.param) {
   405 	nsspkcs5_DestroyPBEParameter(signValue.param);
   406     }
   407     if (signValue.arena) {
   408 	PORT_FreeArena(signValue.arena,PR_FALSE);
   409     }
   410     return rv;
   411 }
   413 /*
   414  * Use our key to create a signText block the plain text of an
   415  * attribute. The signText is a PKCS 5 v2 pbe.
   416  */
   417 SECStatus
   418 sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey, 
   419 	 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType, 
   420 	 SECItem *plainText, SECItem **signature) 
   421 {
   422     SECStatus rv;
   423     sftkCipherValue signValue;
   424     NSSPKCS5PBEParameter *param = NULL;
   425     unsigned char saltData[HASH_LENGTH_MAX];
   426     unsigned char signData[HASH_LENGTH_MAX];
   427     SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */
   428     SECOidTag prfAlg = SEC_OID_HMAC_SHA256;  /* hash for pb key generation */
   429     HASH_HashType prfType;
   430     unsigned int hmacLength;
   431     unsigned int prfLength;
   433     /* this code allows us to fetch the lengths and hashes on the fly
   434      * by simply changing the OID above */
   435     prfType = HASH_FromHMACOid(prfAlg);
   436     PORT_Assert(prfType != HASH_AlgNULL);
   437     prfLength = HASH_GetRawHashObject(prfType)->length;
   438     PORT_Assert(prfLength <= HASH_LENGTH_MAX);
   440     hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length;
   441     PORT_Assert(hmacLength <= HASH_LENGTH_MAX);
   443     /* initialize our CipherValue structure */
   444     signValue.alg = SEC_OID_PKCS5_PBMAC1;
   445     signValue.salt.len = prfLength;
   446     signValue.salt.data = saltData;
   447     signValue.value.data = signData;
   448     signValue.value.len = hmacLength;
   449     RNG_GenerateGlobalRandomBytes(saltData,prfLength);
   451     /* initialize our pkcs5 parameter */
   452     param = nsspkcs5_NewParam(signValue.alg, &signValue.salt, 1);
   453     if (param == NULL) {
   454 	rv = SECFailure;
   455 	goto loser;
   456     }
   457     param->keyID = pbeBitGenIntegrityKey;
   458     /* set the PKCS 5 v2 parameters, not extractable from the
   459      * data passed into nsspkcs5_NewParam */
   460     param->encAlg = hmacAlg;
   461     param->hashType = prfType;
   462     param->keyLen = hmacLength;
   463     rv = SECOID_SetAlgorithmID(param->poolp, &param->prfAlg, prfAlg, NULL);
   464     if (rv != SECSuccess) {
   465 	goto loser;
   466     }
   469     /* calculate the mac */
   470     rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType,
   471 			plainText, &signValue.value);
   472     if (rv != SECSuccess) {
   473 	goto loser;
   474     }
   475     signValue.param = param;
   477     /* write it out */
   478     rv = sftkdb_encodeCipherText(arena, &signValue, signature);
   479     if (rv != SECSuccess) {
   480 	goto loser;
   481     }
   483 loser:
   484     if (param) {
   485 	nsspkcs5_DestroyPBEParameter(param);
   486     }
   487     return rv;
   488 }
   490 /*
   491  * safely swith the passed in key for the one caches in the keydb handle
   492  * 
   493  * A key attached to the handle tells us the the token is logged in.
   494  * We can used the key attached to the handle in sftkdb_EncryptAttribute 
   495  *  and sftkdb_DecryptAttribute calls.
   496  */  
   497 static void 
   498 sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey)
   499 {
   500     unsigned char *data;
   501     int len;
   503     if (keydb->passwordLock == NULL) {
   504 	PORT_Assert(keydb->type != SFTK_KEYDB_TYPE);
   505 	return;
   506     }
   508     /* an atomic pointer set would be nice */
   509     SKIP_AFTER_FORK(PZ_Lock(keydb->passwordLock));
   510     data = keydb->passwordKey.data;
   511     len = keydb->passwordKey.len;
   512     keydb->passwordKey.data = passKey->data;
   513     keydb->passwordKey.len = passKey->len;
   514     passKey->data = data;
   515     passKey->len = len;
   516     SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock));
   517 }
   519 /*
   520  * returns true if we are in a middle of a merge style update.
   521  */
   522 PRBool
   523 sftkdb_InUpdateMerge(SFTKDBHandle *keydb)
   524 {
   525     return keydb->updateID ? PR_TRUE : PR_FALSE;
   526 }
   528 /*
   529  * returns true if we are looking for the password for the user's old source
   530  * database as part of a merge style update.
   531  */
   532 PRBool
   533 sftkdb_NeedUpdateDBPassword(SFTKDBHandle *keydb)
   534 {
   535     if (!sftkdb_InUpdateMerge(keydb)) {
   536 	return PR_FALSE;
   537     }
   538     if (keydb->updateDBIsInit && !keydb->updatePasswordKey) {
   539 	return PR_TRUE;
   540     }
   541     return PR_FALSE;
   542 }
   544 /*
   545  * fetch an update password key from a handle.
   546  */
   547 SECItem *
   548 sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle)
   549 {
   550     SECItem *key = NULL;
   552     /* if we're a cert db, fetch it from our peer key db */
   553     if (handle->type == SFTK_CERTDB_TYPE) {
   554 	handle = handle->peerDB;
   555     }
   557     /* don't have one */
   558     if (!handle) {
   559 	return NULL;
   560     }
   562     PZ_Lock(handle->passwordLock);
   563     if (handle->updatePasswordKey) {
   564 	key = SECITEM_DupItem(handle->updatePasswordKey);
   565     }
   566     PZ_Unlock(handle->passwordLock);
   568     return key;
   569 }
   571 /*
   572  * free the update password key from a handle.
   573  */
   574 void
   575 sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle)
   576 {
   577     SECItem *key = NULL;
   579     /* don't have one */
   580     if (!handle) {
   581 	return;
   582     }
   584     /* if we're a cert db, we don't have one */
   585     if (handle->type == SFTK_CERTDB_TYPE) {
   586 	return;
   587     }
   589     PZ_Lock(handle->passwordLock);
   590     if (handle->updatePasswordKey) {
   591 	key = handle->updatePasswordKey;
   592 	handle->updatePasswordKey = NULL;
   593     }
   594     PZ_Unlock(handle->passwordLock);
   596     if (key) {
   597 	SECITEM_ZfreeItem(key, PR_TRUE);
   598     }
   600     return;
   601 }
   603 /*
   604  * what password db we use depends heavily on the update state machine
   605  * 
   606  *  1) no update db, return the normal database.
   607  *  2) update db and no merge return the update db.
   608  *  3) update db and in merge: 
   609  *      return the update db if we need the update db's password, 
   610  *      otherwise return our normal datbase.
   611  */
   612 static SDB *
   613 sftk_getPWSDB(SFTKDBHandle *keydb)
   614 {
   615     if (!keydb->update) {
   616 	return keydb->db;
   617     }
   618     if (!sftkdb_InUpdateMerge(keydb)) {
   619 	return keydb->update;
   620     }
   621     if (sftkdb_NeedUpdateDBPassword(keydb)) {
   622 	return keydb->update;
   623     }
   624     return keydb->db;
   625 }
   627 /*
   628  * return success if we have a valid password entry.
   629  * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT
   630  * in the token flags.
   631  */
   632 SECStatus 
   633 sftkdb_HasPasswordSet(SFTKDBHandle *keydb)
   634 {
   635     SECItem salt, value;
   636     unsigned char saltData[SDB_MAX_META_DATA_LEN];
   637     unsigned char valueData[SDB_MAX_META_DATA_LEN];
   638     CK_RV crv;
   639     SDB *db;
   641     if (keydb == NULL) {
   642 	return SECFailure;
   643     }
   645     db = sftk_getPWSDB(keydb);
   646     if (db == NULL) {
   647 	return SECFailure;
   648     }
   650     salt.data = saltData;
   651     salt.len = sizeof(saltData);
   652     value.data = valueData;
   653     value.len = sizeof(valueData);
   654     crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
   656     /* If no password is set, we can update right away */
   657     if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update 
   658 	&& crv != CKR_OK) {
   659 	/* update the peer certdb if it exists */
   660 	if (keydb->peerDB) {
   661 	    sftkdb_Update(keydb->peerDB, NULL);
   662 	}
   663 	sftkdb_Update(keydb, NULL);
   664     }
   665     return (crv == CKR_OK) ? SECSuccess : SECFailure;
   666 }
   668 #define SFTK_PW_CHECK_STRING "password-check"
   669 #define SFTK_PW_CHECK_LEN 14
   671 /*
   672  * check if the supplied password is valid
   673  */
   674 SECStatus  
   675 sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
   676 {
   677     SECStatus rv;
   678     SECItem salt, value;
   679     unsigned char saltData[SDB_MAX_META_DATA_LEN];
   680     unsigned char valueData[SDB_MAX_META_DATA_LEN];
   681     SECItem key;
   682     SECItem *result = NULL;
   683     SDB *db;
   684     CK_RV crv;
   686     if (keydb == NULL) {
   687 	return SECFailure;
   688     }
   690     db = sftk_getPWSDB(keydb);
   691     if (db == NULL) {
   692 	return SECFailure;
   693     }
   695     key.data = NULL;
   696     key.len = 0;
   698     if (pw == NULL) pw="";
   700     /* get the entry from the database */
   701     salt.data = saltData;
   702     salt.len = sizeof(saltData);
   703     value.data = valueData;
   704     value.len = sizeof(valueData);
   705     crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
   706     if (crv != CKR_OK) {
   707 	rv = SECFailure;
   708 	goto done;
   709     }
   711     /* get our intermediate key based on the entry salt value */
   712     rv = sftkdb_passwordToKey(keydb, &salt, pw, &key);
   713     if (rv != SECSuccess) {
   714 	goto done;
   715     }
   717     /* decrypt the entry value */
   718     rv = sftkdb_DecryptAttribute(&key, &value, &result);
   719     if (rv != SECSuccess) {
   720 	goto done;
   721     }
   723     /* if it's what we expect, update our key in the database handle and
   724      * return Success */
   725     if ((result->len == SFTK_PW_CHECK_LEN) &&
   726       PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0){
   727 	/*
   728 	 * We have a password, now lets handle any potential update cases..
   729 	 * 
   730 	 * First, the normal case: no update. In this case we only need the
   731 	 *  the password for our only DB, which we now have, we switch 
   732 	 *  the keys and fall through.
   733 	 * Second regular (non-merge) update: The target DB does not yet have
   734 	 *  a password initialized, we now have the password for the source DB,
   735 	 *  so we can switch the keys and simply update the target database.
   736 	 * Merge update case: This one is trickier.
   737 	 *   1) If we need the source DB password, then we just got it here.
   738 	 *       We need to save that password,
   739 	 *       then we need to check to see if we need or have the target 
   740 	 *         database password.
   741 	 *       If we have it (it's the same as the source), or don't need 
   742 	 *         it (it's not set or is ""), we can start the update now.
   743 	 *       If we don't have it, we need the application to get it from 
   744 	 *         the user. Clear our sessions out to simulate a token 
   745 	 *         removal. C_GetTokenInfo will change the token description 
   746 	 *         and the token will still appear to be logged out.
   747 	 *   2) If we already have the source DB  password, this password is 
   748 	 *         for the target database. We can now move forward with the 
   749 	 *         update, as we now have both required passwords.
   750 	 *
   751 	 */
   752         PZ_Lock(keydb->passwordLock);
   753 	if (sftkdb_NeedUpdateDBPassword(keydb)) {
   754 	    /* Squirrel this special key away.
   755 	     * This has the side effect of turning sftkdb_NeedLegacyPW off,
   756 	     * as well as changing which database is returned from 
   757 	     * SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword()
   758 	     * and sftkdb_HasPasswordSet()) */
   759 	    keydb->updatePasswordKey = SECITEM_DupItem(&key);
   760 	    PZ_Unlock(keydb->passwordLock);
   761 	    if (keydb->updatePasswordKey == NULL) {
   762 		/* PORT_Error set by SECITEM_DupItem */
   763 		rv = SECFailure;
   764 		goto done;
   765 	    }
   767 	    /* Simulate a token removal -- we need to do this any
   768              * any case at this point so the token name is correct. */
   769 	    *tokenRemoved = PR_TRUE;
   771 	    /* 
   772 	     * OK, we got the update DB password, see if we need a password
   773 	     * for the target...
   774 	     */
   775 	    if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
   776 		/* We have a password, do we know what the password is?
   777 		 *  check 1) for the password the user supplied for the 
   778 		 *           update DB,
   779 		 *    and 2) for the null password.
   780 		 *
   781 		 * RECURSION NOTE: we are calling ourselves here. This means
   782 		 *  any updates, switchKeys, etc will have been completed
   783 		 *  if these functions return successfully, in those cases
   784 		 *  just exit returning Success. We don't recurse infinitely
   785 		 *  because we are making this call from a NeedUpdateDBPassword
   786 		 *  block and we've already set that update password at this
   787 		 *  point.  */
   788 		rv = sftkdb_CheckPassword(keydb, pw, tokenRemoved);
   789 		if (rv == SECSuccess) {
   790 		    /* source and target databases have the same password, we 
   791 		     * are good to go */
   792 		    goto done;
   793 		}
   794 		sftkdb_CheckPassword(keydb, "", tokenRemoved);
   796 		/*
   797 		 * Important 'NULL' code here. At this point either we 
   798 		 * succeeded in logging in with "" or we didn't.
   799                  *
   800                  *  If we did succeed at login, our machine state will be set
   801 		 * to logged in appropriately. The application will find that 
   802 		 * it's logged in as soon as it opens a new session. We have 
   803 		 * also completed the update. Life is good.
   804 		 * 
   805 		 *  If we did not succeed, well the user still successfully
   806 		 * logged into the update database, since we faked the token 
   807 		 * removal it's just like the user logged into his smart card 
   808 		 * then removed it. the actual login work, so we report that 
   809 		 * success back to the user, but we won't actually be
   810 		 * logged in. The application will find this out when it
   811 		 * checks it's login state, thus triggering another password
   812 		 * prompt so we can get the real target DB password.
   813 		 *
   814 		 * summary, we exit from here with SECSuccess no matter what.
   815 		 */
   816 		rv = SECSuccess;
   817 		goto done;
   818 	    } else {
   819 		/* there is no password, just fall through to update.
   820 		 * update will write the source DB's password record
   821 		 * into the target DB just like it would in a non-merge
   822 		 * update case. */
   823 	    }
   824 	} else {
   825 	    PZ_Unlock(keydb->passwordLock);
   826 	}
   827 	/* load the keys, so the keydb can parse it's key set */
   828 	sftkdb_switchKeys(keydb, &key);
   830 	/* we need to update, do it now */
   831 	if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) {
   832 	    /* update the peer certdb if it exists */
   833 	    if (keydb->peerDB) {
   834 		sftkdb_Update(keydb->peerDB, &key);
   835 	    }
   836 	    sftkdb_Update(keydb, &key);
   837 	}
   838     } else {
   839         rv = SECFailure;
   840 	/*PORT_SetError( bad password); */
   841     }
   843 done:
   844     if (key.data) {
   845 	PORT_ZFree(key.data,key.len);
   846     }
   847     if (result) {
   848 	SECITEM_FreeItem(result,PR_TRUE);
   849     }
   850     return rv;
   851 }
   853 /*
   854  * return Success if the there is a cached password key.
   855  */
   856 SECStatus
   857 sftkdb_PWCached(SFTKDBHandle *keydb)
   858 {
   859     return keydb->passwordKey.data ? SECSuccess : SECFailure;
   860 }
   863 static CK_RV
   864 sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
   865 		       CK_OBJECT_HANDLE id, SECItem *newKey)
   866 {
   867     CK_RV crv = CKR_OK;
   868     CK_RV crv2;
   869     CK_ATTRIBUTE authAttrs[] = {
   870 	{CKA_MODULUS, NULL, 0},
   871 	{CKA_PUBLIC_EXPONENT, NULL, 0},
   872 	{CKA_CERT_SHA1_HASH, NULL, 0},
   873 	{CKA_CERT_MD5_HASH, NULL, 0},
   874 	{CKA_TRUST_SERVER_AUTH, NULL, 0},
   875 	{CKA_TRUST_CLIENT_AUTH, NULL, 0},
   876 	{CKA_TRUST_EMAIL_PROTECTION, NULL, 0},
   877 	{CKA_TRUST_CODE_SIGNING, NULL, 0},
   878 	{CKA_TRUST_STEP_UP_APPROVED, NULL, 0},
   879 	{CKA_NSS_OVERRIDE_EXTENSIONS, NULL, 0},
   880     };
   881     CK_ULONG authAttrCount = sizeof(authAttrs)/sizeof(CK_ATTRIBUTE);
   882     int i, count;
   883     SFTKDBHandle *keyHandle = handle;
   884     SDB *keyTarget = NULL;
   886     id &= SFTK_OBJ_ID_MASK;
   888     if (handle->type != SFTK_KEYDB_TYPE) {
   889 	keyHandle = handle->peerDB;
   890     }
   892     if (keyHandle == NULL) {
   893 	return CKR_OK;
   894     }
   896     /* old DB's don't have meta data, finished with MACs */
   897     keyTarget = SFTK_GET_SDB(keyHandle);
   898     if ((keyTarget->sdb_flags &SDB_HAS_META) == 0) {
   899 	return CKR_OK;
   900     }
   902     /*
   903      * STEP 1: find the MACed attributes of this object 
   904      */
   905     crv2 = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
   906     count = 0;
   907     /* allocate space for the attributes */
   908     for (i=0; i < authAttrCount; i++) {
   909 	if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){
   910 	    continue;
   911 	}
   912 	count++;
   913         authAttrs[i].pValue = PORT_ArenaAlloc(arena,authAttrs[i].ulValueLen);
   914 	if (authAttrs[i].pValue == NULL) {
   915 	    crv = CKR_HOST_MEMORY;
   916 	    break;
   917 	}
   918     }
   920     /* if count was zero, none were found, finished with MACs */
   921     if (count == 0) {
   922 	return CKR_OK;
   923     }
   925     crv = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
   926     /* ignore error code, we expect some possible errors */
   928     /* GetAttributeValue just verified the old macs, safe to write
   929      * them out then... */
   930     for (i=0; i < authAttrCount; i++) {
   931 	SECItem *signText;
   932 	SECItem plainText;
   933 	SECStatus rv;
   935 	if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){
   936 	    continue;
   937 	}
   939 	plainText.data = authAttrs[i].pValue;
   940 	plainText.len = authAttrs[i].ulValueLen;
   941 	rv = sftkdb_SignAttribute(arena, newKey, id, 
   942 			authAttrs[i].type, &plainText, &signText);
   943 	if (rv != SECSuccess) {
   944 	    return CKR_GENERAL_ERROR;
   945 	}
   946 	rv = sftkdb_PutAttributeSignature(handle, keyTarget, id, 
   947 				authAttrs[i].type, signText);
   948 	if (rv != SECSuccess) {
   949 	    return CKR_GENERAL_ERROR;
   950 	}
   951     }
   953     return CKR_OK;
   954 }
   956 static CK_RV
   957 sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
   958 		       CK_OBJECT_HANDLE id, SECItem *newKey)
   959 {
   960     CK_RV crv = CKR_OK;
   961     CK_RV crv2;
   962     CK_ATTRIBUTE *first, *last;
   963     CK_ATTRIBUTE privAttrs[] = {
   964 	{CKA_VALUE, NULL, 0},
   965 	{CKA_PRIVATE_EXPONENT, NULL, 0},
   966 	{CKA_PRIME_1, NULL, 0},
   967 	{CKA_PRIME_2, NULL, 0},
   968 	{CKA_EXPONENT_1, NULL, 0},
   969 	{CKA_EXPONENT_2, NULL, 0},
   970 	{CKA_COEFFICIENT, NULL, 0} };
   971     CK_ULONG privAttrCount = sizeof(privAttrs)/sizeof(CK_ATTRIBUTE);
   972     int i, count;
   974     /*
   975      * STEP 1. Read the old attributes in the clear.
   976      */
   978     /* Get the attribute sizes.
   979      *  ignore the error code, we will have unknown attributes here */
   980     crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount);
   982     /*
   983      * find the valid block of attributes and fill allocate space for
   984      * their data */
   985     first = last = NULL;
   986     for (i=0; i < privAttrCount; i++) {
   987          /* find the block of attributes that are appropriate for this 
   988           * objects. There should only be once contiguous block, if not 
   989           * there's an error.
   990           *
   991           * find the first and last good entry.
   992           */
   993 	if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)){
   994 	    if (!first) continue;
   995 	    if (!last) {
   996 		/* previous entry was last good entry */
   997 		last= &privAttrs[i-1];
   998 	    }
   999 	    continue;
  1001 	if (!first) {
  1002 	    first = &privAttrs[i];
  1004 	if (last) {
  1005 	   /* OOPS, we've found another good entry beyond the end of the
  1006 	    * last good entry, we need to fail here. */
  1007 	   crv = CKR_GENERAL_ERROR;
  1008 	   break;
  1010         privAttrs[i].pValue = PORT_ArenaAlloc(arena,privAttrs[i].ulValueLen);
  1011 	if (privAttrs[i].pValue == NULL) {
  1012 	    crv = CKR_HOST_MEMORY;
  1013 	    break;
  1016     if (first == NULL) {
  1017 	/* no valid entries found, return error based on crv2 */
  1018 	return crv2;
  1020     if (last == NULL) {
  1021 	last = &privAttrs[privAttrCount-1];
  1023     if (crv != CKR_OK) {
  1024 	return crv;
  1026     /* read the attributes */
  1027     count = (last-first)+1;
  1028     crv = sftkdb_GetAttributeValue(keydb, id, first, count);
  1029     if (crv != CKR_OK) {
  1030 	return crv;
  1033     /*
  1034      * STEP 2: read the encrypt the attributes with the new key.
  1035      */
  1036     for (i=0; i < count; i++) {
  1037 	SECItem plainText;
  1038 	SECItem *result;
  1039 	SECStatus rv;
  1041 	plainText.data = first[i].pValue;
  1042 	plainText.len = first[i].ulValueLen;
  1043     	rv = sftkdb_EncryptAttribute(arena, newKey, &plainText, &result);
  1044 	if (rv != SECSuccess) {
  1045 	   return CKR_GENERAL_ERROR;
  1047 	first[i].pValue = result->data;
  1048 	first[i].ulValueLen = result->len;
  1049 	/* clear our sensitive data out */
  1050 	PORT_Memset(plainText.data, 0, plainText.len);
  1054     /*
  1055      * STEP 3: write the newly encrypted attributes out directly
  1056      */
  1057     id &= SFTK_OBJ_ID_MASK;
  1058     keydb->newKey = newKey;
  1059     crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count);
  1060     keydb->newKey = NULL;
  1062     return crv;
  1065 static CK_RV
  1066 sftk_convertAttributes(SFTKDBHandle *handle, 
  1067 			CK_OBJECT_HANDLE id, SECItem *newKey)
  1069     CK_RV crv = CKR_OK;
  1070     PLArenaPool *arena = NULL;
  1072     /* get a new arena to simplify cleanup */
  1073     arena = PORT_NewArena(1024);
  1074     if (!arena) {
  1075 	return CKR_HOST_MEMORY;
  1078     /*
  1079      * first handle the MACS
  1080      */
  1081     crv = sftk_updateMacs(arena, handle, id, newKey);
  1082     if (crv != CKR_OK) {
  1083 	goto loser;
  1086     if (handle->type == SFTK_KEYDB_TYPE) {
  1087 	crv = sftk_updateEncrypted(arena, handle, id, newKey);
  1088 	if (crv != CKR_OK) {
  1089 	    goto loser;
  1093     /* free up our mess */
  1094     /* NOTE: at this point we know we've cleared out any unencrypted data */
  1095     PORT_FreeArena(arena, PR_FALSE);
  1096     return CKR_OK;
  1098 loser:
  1099     /* there may be unencrypted data, clear it out down */
  1100     PORT_FreeArena(arena, PR_TRUE);
  1101     return crv;
  1105 /*
  1106  * must be called with the old key active.
  1107  */
  1108 CK_RV
  1109 sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template, 
  1110 			CK_ULONG count, SECItem *newKey)
  1112     SDBFind *find = NULL;
  1113     CK_ULONG idCount = SFTK_MAX_IDS;
  1114     CK_OBJECT_HANDLE ids[SFTK_MAX_IDS];
  1115     CK_RV crv, crv2;
  1116     int i;
  1118     crv = sftkdb_FindObjectsInit(handle, template, count, &find);
  1120     if (crv != CKR_OK) {
  1121 	return crv;
  1123     while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) {
  1124 	crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount);
  1125 	for (i=0; (crv == CKR_OK) && (i < idCount); i++) {
  1126 	    crv = sftk_convertAttributes(handle, ids[i], newKey);
  1129     crv2 = sftkdb_FindObjectsFinal(handle, find);
  1130     if (crv == CKR_OK) crv = crv2;
  1132     return crv;
  1136 /*
  1137  * change the database password.
  1138  */
  1139 SECStatus
  1140 sftkdb_ChangePassword(SFTKDBHandle *keydb, 
  1141                       char *oldPin, char *newPin, PRBool *tokenRemoved)
  1143     SECStatus rv = SECSuccess;
  1144     SECItem plainText;
  1145     SECItem newKey;
  1146     SECItem *result = NULL;
  1147     SECItem salt, value;
  1148     SFTKDBHandle *certdb;
  1149     unsigned char saltData[SDB_MAX_META_DATA_LEN];
  1150     unsigned char valueData[SDB_MAX_META_DATA_LEN];
  1151     CK_RV crv;
  1152     SDB *db;
  1154     if (keydb == NULL) {
  1155 	return SECFailure;
  1158     db = SFTK_GET_SDB(keydb);
  1159     if (db == NULL) {
  1160 	return SECFailure;
  1163     newKey.data = NULL;
  1165     /* make sure we have a valid old pin */
  1166     crv = (*keydb->db->sdb_Begin)(keydb->db);
  1167     if (crv != CKR_OK) {
  1168 	rv = SECFailure;
  1169 	goto loser;
  1171     salt.data = saltData;
  1172     salt.len = sizeof(saltData);
  1173     value.data = valueData;
  1174     value.len = sizeof(valueData);
  1175     crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
  1176     if (crv == CKR_OK) {
  1177 	rv = sftkdb_CheckPassword(keydb, oldPin, tokenRemoved);
  1178 	if (rv == SECFailure) {
  1179 	    goto loser;
  1181     } else {
  1182 	salt.len = SHA1_LENGTH;
  1183     	RNG_GenerateGlobalRandomBytes(salt.data,salt.len);
  1186     rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
  1187     if (rv != SECSuccess) {
  1188 	goto loser;
  1192     /*
  1193      * convert encrypted entries here.
  1194      */
  1195     crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey);
  1196     if (crv != CKR_OK) {
  1197 	rv = SECFailure;
  1198 	goto loser;
  1200     /* fix up certdb macs */
  1201     certdb = keydb->peerDB;
  1202     if (certdb) {
  1203 	CK_ATTRIBUTE objectType = { CKA_CLASS, 0, sizeof(CK_OBJECT_CLASS) };
  1204 	CK_OBJECT_CLASS myClass = CKO_NETSCAPE_TRUST;
  1206 	objectType.pValue = &myClass;
  1207 	crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
  1208 	if (crv != CKR_OK) {
  1209 	    rv = SECFailure;
  1210 	    goto loser;
  1212 	myClass = CKO_PUBLIC_KEY;
  1213 	crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
  1214 	if (crv != CKR_OK) {
  1215 	    rv = SECFailure;
  1216 	    goto loser;
  1221     plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
  1222     plainText.len = SFTK_PW_CHECK_LEN;
  1224     rv = sftkdb_EncryptAttribute(NULL, &newKey, &plainText, &result);
  1225     if (rv != SECSuccess) {
  1226 	goto loser;
  1228     value.data = result->data;
  1229     value.len = result->len;
  1230     crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value);
  1231     if (crv != CKR_OK) {
  1232 	rv = SECFailure;
  1233 	goto loser;
  1235     crv = (*keydb->db->sdb_Commit)(keydb->db);
  1236     if (crv != CKR_OK) {
  1237 	rv = SECFailure;
  1238 	goto loser;
  1241     keydb->newKey = NULL;
  1243     sftkdb_switchKeys(keydb, &newKey);
  1245 loser:
  1246     if (newKey.data) {
  1247 	PORT_ZFree(newKey.data,newKey.len);
  1249     if (result) {
  1250 	SECITEM_FreeItem(result, PR_FALSE);
  1252     if (rv != SECSuccess) {
  1253         (*keydb->db->sdb_Abort)(keydb->db);
  1256     return rv;
  1259 /*
  1260  * lose our cached password
  1261  */
  1262 SECStatus
  1263 sftkdb_ClearPassword(SFTKDBHandle *keydb)
  1265     SECItem oldKey;
  1266     oldKey.data = NULL;
  1267     oldKey.len = 0;
  1268     sftkdb_switchKeys(keydb, &oldKey);
  1269     if (oldKey.data) {
  1270 	PORT_ZFree(oldKey.data, oldKey.len);
  1272     return SECSuccess;

mercurial