1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/sftkpwd.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1275 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * The following code handles the storage of PKCS 11 modules used by the 1.9 + * NSS. For the rest of NSS, only one kind of database handle exists: 1.10 + * 1.11 + * SFTKDBHandle 1.12 + * 1.13 + * There is one SFTKDBHandle for the each key database and one for each cert 1.14 + * database. These databases are opened as associated pairs, one pair per 1.15 + * slot. SFTKDBHandles are reference counted objects. 1.16 + * 1.17 + * Each SFTKDBHandle points to a low level database handle (SDB). This handle 1.18 + * represents the underlying physical database. These objects are not 1.19 + * reference counted, an are 'owned' by their respective SFTKDBHandles. 1.20 + * 1.21 + * 1.22 + */ 1.23 +#include "sftkdb.h" 1.24 +#include "sftkdbti.h" 1.25 +#include "pkcs11t.h" 1.26 +#include "pkcs11i.h" 1.27 +#include "sdb.h" 1.28 +#include "prprf.h" 1.29 +#include "secasn1.h" 1.30 +#include "pratom.h" 1.31 +#include "blapi.h" 1.32 +#include "secoid.h" 1.33 +#include "lowpbe.h" 1.34 +#include "secdert.h" 1.35 +#include "prsystem.h" 1.36 +#include "lgglue.h" 1.37 +#include "secerr.h" 1.38 +#include "softoken.h" 1.39 + 1.40 +/****************************************************************** 1.41 + * 1.42 + * Key DB password handling functions 1.43 + * 1.44 + * These functions manage the key db password (set, reset, initialize, use). 1.45 + * 1.46 + * The key is managed on 'this side' of the database. All private data is 1.47 + * encrypted before it is sent to the database itself. Besides PBE's, the 1.48 + * database management code can also mix in various fixed keys so the data 1.49 + * in the database is no longer considered 'plain text'. 1.50 + */ 1.51 + 1.52 + 1.53 +/* take string password and turn it into a key. The key is dependent 1.54 + * on a global salt entry acquired from the database. This salted 1.55 + * value will be based to a pkcs5 pbe function before it is used 1.56 + * in an actual encryption */ 1.57 +static SECStatus 1.58 +sftkdb_passwordToKey(SFTKDBHandle *keydb, SECItem *salt, 1.59 + const char *pw, SECItem *key) 1.60 +{ 1.61 + SHA1Context *cx = NULL; 1.62 + SECStatus rv = SECFailure; 1.63 + 1.64 + key->data = PORT_Alloc(SHA1_LENGTH); 1.65 + if (key->data == NULL) { 1.66 + goto loser; 1.67 + } 1.68 + key->len = SHA1_LENGTH; 1.69 + 1.70 + cx = SHA1_NewContext(); 1.71 + if ( cx == NULL) { 1.72 + goto loser; 1.73 + } 1.74 + SHA1_Begin(cx); 1.75 + if (salt && salt->data ) { 1.76 + SHA1_Update(cx, salt->data, salt->len); 1.77 + } 1.78 + SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw)); 1.79 + SHA1_End(cx, key->data, &key->len, key->len); 1.80 + rv = SECSuccess; 1.81 + 1.82 +loser: 1.83 + if (cx) { 1.84 + SHA1_DestroyContext(cx, PR_TRUE); 1.85 + } 1.86 + if (rv != SECSuccess) { 1.87 + if (key->data != NULL) { 1.88 + PORT_ZFree(key->data,key->len); 1.89 + } 1.90 + key->data = NULL; 1.91 + } 1.92 + return rv; 1.93 +} 1.94 + 1.95 +/* 1.96 + * Cipher text stored in the database contains 3 elements: 1.97 + * 1) an identifier describing the encryption algorithm. 1.98 + * 2) an entry specific salt value. 1.99 + * 3) the encrypted value. 1.100 + * 1.101 + * The following data structure represents the encrypted data in a decoded 1.102 + * (but still encrypted) form. 1.103 + */ 1.104 +typedef struct sftkCipherValueStr sftkCipherValue; 1.105 +struct sftkCipherValueStr { 1.106 + PLArenaPool *arena; 1.107 + SECOidTag alg; 1.108 + NSSPKCS5PBEParameter *param; 1.109 + SECItem salt; 1.110 + SECItem value; 1.111 +}; 1.112 + 1.113 +#define SFTK_CIPHERTEXT_VERSION 3 1.114 + 1.115 +struct SFTKDBEncryptedDataInfoStr { 1.116 + SECAlgorithmID algorithm; 1.117 + SECItem encryptedData; 1.118 +}; 1.119 +typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo; 1.120 + 1.121 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 1.122 + 1.123 +const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate[] = { 1.124 + { SEC_ASN1_SEQUENCE, 1.125 + 0, NULL, sizeof(SFTKDBEncryptedDataInfo) }, 1.126 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN , 1.127 + offsetof(SFTKDBEncryptedDataInfo,algorithm), 1.128 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1.129 + { SEC_ASN1_OCTET_STRING, 1.130 + offsetof(SFTKDBEncryptedDataInfo,encryptedData) }, 1.131 + { 0 } 1.132 +}; 1.133 + 1.134 +/* 1.135 + * This parses the cipherText into cipher value. NOTE: cipherValue will point 1.136 + * to data in cipherText, if cipherText is freed, cipherValue will be invalid. 1.137 + */ 1.138 +static SECStatus 1.139 +sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue) 1.140 +{ 1.141 + PLArenaPool *arena = NULL; 1.142 + SFTKDBEncryptedDataInfo edi; 1.143 + SECStatus rv; 1.144 + 1.145 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.146 + if (arena == NULL) { 1.147 + return SECFailure; 1.148 + } 1.149 + cipherValue->arena = NULL; 1.150 + cipherValue->param = NULL; 1.151 + 1.152 + rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate, 1.153 + cipherText); 1.154 + if (rv != SECSuccess) { 1.155 + goto loser; 1.156 + } 1.157 + cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm); 1.158 + cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm); 1.159 + if (cipherValue->param == NULL) { 1.160 + goto loser; 1.161 + } 1.162 + cipherValue->value = edi.encryptedData; 1.163 + cipherValue->arena = arena; 1.164 + 1.165 + return SECSuccess; 1.166 +loser: 1.167 + if (cipherValue->param) { 1.168 + nsspkcs5_DestroyPBEParameter(cipherValue->param); 1.169 + cipherValue->param = NULL; 1.170 + } 1.171 + if (arena) { 1.172 + PORT_FreeArena(arena,PR_FALSE); 1.173 + } 1.174 + return SECFailure; 1.175 +} 1.176 + 1.177 + 1.178 + 1.179 +/* 1.180 + * unlike decode, Encode actually allocates a SECItem the caller must free 1.181 + * The caller can pass an optional arena to to indicate where to place 1.182 + * the resultant cipherText. 1.183 + */ 1.184 +static SECStatus 1.185 +sftkdb_encodeCipherText(PLArenaPool *arena, sftkCipherValue *cipherValue, 1.186 + SECItem **cipherText) 1.187 +{ 1.188 + SFTKDBEncryptedDataInfo edi; 1.189 + SECAlgorithmID *algid; 1.190 + SECStatus rv; 1.191 + PLArenaPool *localArena = NULL; 1.192 + 1.193 + 1.194 + localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.195 + if (localArena == NULL) { 1.196 + return SECFailure; 1.197 + } 1.198 + 1.199 + algid = nsspkcs5_CreateAlgorithmID(localArena, cipherValue->alg, 1.200 + cipherValue->param); 1.201 + if (algid == NULL) { 1.202 + rv = SECFailure; 1.203 + goto loser; 1.204 + } 1.205 + rv = SECOID_CopyAlgorithmID(localArena, &edi.algorithm, algid); 1.206 + SECOID_DestroyAlgorithmID(algid, PR_TRUE); 1.207 + if (rv != SECSuccess) { 1.208 + goto loser; 1.209 + } 1.210 + edi.encryptedData = cipherValue->value; 1.211 + 1.212 + *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi, 1.213 + sftkdb_EncryptedDataInfoTemplate); 1.214 + if (*cipherText == NULL) { 1.215 + rv = SECFailure; 1.216 + } 1.217 + 1.218 +loser: 1.219 + if (localArena) { 1.220 + PORT_FreeArena(localArena,PR_FALSE); 1.221 + } 1.222 + 1.223 + return rv; 1.224 +} 1.225 + 1.226 + 1.227 +/* 1.228 + * Use our key to decode a cipherText block from the database. 1.229 + * 1.230 + * plain text is allocated by nsspkcs5_CipherData and must be freed 1.231 + * with SECITEM_FreeItem by the caller. 1.232 + */ 1.233 +SECStatus 1.234 +sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText, SECItem **plain) 1.235 +{ 1.236 + SECStatus rv; 1.237 + sftkCipherValue cipherValue; 1.238 + 1.239 + /* First get the cipher type */ 1.240 + rv = sftkdb_decodeCipherText(cipherText, &cipherValue); 1.241 + if (rv != SECSuccess) { 1.242 + goto loser; 1.243 + } 1.244 + 1.245 + *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value, 1.246 + PR_FALSE, NULL); 1.247 + if (*plain == NULL) { 1.248 + rv = SECFailure; 1.249 + goto loser; 1.250 + } 1.251 + 1.252 +loser: 1.253 + if (cipherValue.param) { 1.254 + nsspkcs5_DestroyPBEParameter(cipherValue.param); 1.255 + } 1.256 + if (cipherValue.arena) { 1.257 + PORT_FreeArena(cipherValue.arena,PR_FALSE); 1.258 + } 1.259 + return rv; 1.260 +} 1.261 + 1.262 +/* 1.263 + * encrypt a block. This function returned the encrypted ciphertext which 1.264 + * the caller must free. If the caller provides an arena, cipherText will 1.265 + * be allocated out of that arena. This also generated the per entry 1.266 + * salt automatically. 1.267 + */ 1.268 +SECStatus 1.269 +sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey, 1.270 + SECItem *plainText, SECItem **cipherText) 1.271 +{ 1.272 + SECStatus rv; 1.273 + sftkCipherValue cipherValue; 1.274 + SECItem *cipher = NULL; 1.275 + NSSPKCS5PBEParameter *param = NULL; 1.276 + unsigned char saltData[HASH_LENGTH_MAX]; 1.277 + 1.278 + cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC; 1.279 + cipherValue.salt.len = SHA1_LENGTH; 1.280 + cipherValue.salt.data = saltData; 1.281 + RNG_GenerateGlobalRandomBytes(saltData,cipherValue.salt.len); 1.282 + 1.283 + param = nsspkcs5_NewParam(cipherValue.alg, &cipherValue.salt, 1); 1.284 + if (param == NULL) { 1.285 + rv = SECFailure; 1.286 + goto loser; 1.287 + } 1.288 + cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL); 1.289 + if (cipher == NULL) { 1.290 + rv = SECFailure; 1.291 + goto loser; 1.292 + } 1.293 + cipherValue.value = *cipher; 1.294 + cipherValue.param = param; 1.295 + 1.296 + rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText); 1.297 + if (rv != SECSuccess) { 1.298 + goto loser; 1.299 + } 1.300 + 1.301 +loser: 1.302 + if (cipher) { 1.303 + SECITEM_FreeItem(cipher, PR_TRUE); 1.304 + } 1.305 + if (param) { 1.306 + nsspkcs5_DestroyPBEParameter(param); 1.307 + } 1.308 + return rv; 1.309 +} 1.310 + 1.311 +/* 1.312 + * use the password and the pbe parameters to generate an HMAC for the 1.313 + * given plain text data. This is used by sftkdb_VerifyAttribute and 1.314 + * sftkdb_SignAttribute. Signature is returned in signData. The caller 1.315 + * must preallocate the space in the secitem. 1.316 + */ 1.317 +static SECStatus 1.318 +sftkdb_pbehash(SECOidTag sigOid, SECItem *passKey, 1.319 + NSSPKCS5PBEParameter *param, 1.320 + CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType, 1.321 + SECItem *plainText, SECItem *signData) 1.322 +{ 1.323 + SECStatus rv = SECFailure; 1.324 + SECItem *key = NULL; 1.325 + HMACContext *hashCx = NULL; 1.326 + HASH_HashType hashType = HASH_AlgNULL; 1.327 + const SECHashObject *hashObj; 1.328 + unsigned char addressData[SDB_ULONG_SIZE]; 1.329 + 1.330 + hashType = HASH_FromHMACOid(param->encAlg); 1.331 + if (hashType == HASH_AlgNULL) { 1.332 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.333 + return SECFailure; 1.334 + } 1.335 + 1.336 + hashObj = HASH_GetRawHashObject(hashType); 1.337 + if (hashObj == NULL) { 1.338 + goto loser; 1.339 + } 1.340 + 1.341 + key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE); 1.342 + if (!key) { 1.343 + goto loser; 1.344 + } 1.345 + 1.346 + hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE); 1.347 + if (!hashCx) { 1.348 + goto loser; 1.349 + } 1.350 + HMAC_Begin(hashCx); 1.351 + /* Tie this value to a particular object. This is most important for 1.352 + * the trust attributes, where and attacker could copy a value for 1.353 + * 'validCA' from another cert in the database */ 1.354 + sftk_ULong2SDBULong(addressData, objectID); 1.355 + HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE); 1.356 + sftk_ULong2SDBULong(addressData, attrType); 1.357 + HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE); 1.358 + 1.359 + HMAC_Update(hashCx, plainText->data, plainText->len); 1.360 + rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len); 1.361 + 1.362 +loser: 1.363 + if (hashCx) { 1.364 + HMAC_Destroy(hashCx, PR_TRUE); 1.365 + } 1.366 + if (key) { 1.367 + SECITEM_FreeItem(key,PR_TRUE); 1.368 + } 1.369 + return rv; 1.370 +} 1.371 + 1.372 +/* 1.373 + * Use our key to verify a signText block from the database matches 1.374 + * the plainText from the database. The signText is a PKCS 5 v2 pbe. 1.375 + * plainText is the plainText of the attribute. 1.376 + */ 1.377 +SECStatus 1.378 +sftkdb_VerifyAttribute(SECItem *passKey, CK_OBJECT_HANDLE objectID, 1.379 + CK_ATTRIBUTE_TYPE attrType, 1.380 + SECItem *plainText, SECItem *signText) 1.381 +{ 1.382 + SECStatus rv; 1.383 + sftkCipherValue signValue; 1.384 + SECItem signature; 1.385 + unsigned char signData[HASH_LENGTH_MAX]; 1.386 + 1.387 + 1.388 + /* First get the cipher type */ 1.389 + rv = sftkdb_decodeCipherText(signText, &signValue); 1.390 + if (rv != SECSuccess) { 1.391 + goto loser; 1.392 + } 1.393 + signature.data = signData; 1.394 + signature.len = sizeof(signData); 1.395 + 1.396 + rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param, 1.397 + objectID, attrType, plainText, &signature); 1.398 + if (rv != SECSuccess) { 1.399 + goto loser; 1.400 + } 1.401 + if (SECITEM_CompareItem(&signValue.value,&signature) != 0) { 1.402 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.403 + rv = SECFailure; 1.404 + } 1.405 + 1.406 +loser: 1.407 + if (signValue.param) { 1.408 + nsspkcs5_DestroyPBEParameter(signValue.param); 1.409 + } 1.410 + if (signValue.arena) { 1.411 + PORT_FreeArena(signValue.arena,PR_FALSE); 1.412 + } 1.413 + return rv; 1.414 +} 1.415 + 1.416 +/* 1.417 + * Use our key to create a signText block the plain text of an 1.418 + * attribute. The signText is a PKCS 5 v2 pbe. 1.419 + */ 1.420 +SECStatus 1.421 +sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey, 1.422 + CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType, 1.423 + SECItem *plainText, SECItem **signature) 1.424 +{ 1.425 + SECStatus rv; 1.426 + sftkCipherValue signValue; 1.427 + NSSPKCS5PBEParameter *param = NULL; 1.428 + unsigned char saltData[HASH_LENGTH_MAX]; 1.429 + unsigned char signData[HASH_LENGTH_MAX]; 1.430 + SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */ 1.431 + SECOidTag prfAlg = SEC_OID_HMAC_SHA256; /* hash for pb key generation */ 1.432 + HASH_HashType prfType; 1.433 + unsigned int hmacLength; 1.434 + unsigned int prfLength; 1.435 + 1.436 + /* this code allows us to fetch the lengths and hashes on the fly 1.437 + * by simply changing the OID above */ 1.438 + prfType = HASH_FromHMACOid(prfAlg); 1.439 + PORT_Assert(prfType != HASH_AlgNULL); 1.440 + prfLength = HASH_GetRawHashObject(prfType)->length; 1.441 + PORT_Assert(prfLength <= HASH_LENGTH_MAX); 1.442 + 1.443 + hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length; 1.444 + PORT_Assert(hmacLength <= HASH_LENGTH_MAX); 1.445 + 1.446 + /* initialize our CipherValue structure */ 1.447 + signValue.alg = SEC_OID_PKCS5_PBMAC1; 1.448 + signValue.salt.len = prfLength; 1.449 + signValue.salt.data = saltData; 1.450 + signValue.value.data = signData; 1.451 + signValue.value.len = hmacLength; 1.452 + RNG_GenerateGlobalRandomBytes(saltData,prfLength); 1.453 + 1.454 + /* initialize our pkcs5 parameter */ 1.455 + param = nsspkcs5_NewParam(signValue.alg, &signValue.salt, 1); 1.456 + if (param == NULL) { 1.457 + rv = SECFailure; 1.458 + goto loser; 1.459 + } 1.460 + param->keyID = pbeBitGenIntegrityKey; 1.461 + /* set the PKCS 5 v2 parameters, not extractable from the 1.462 + * data passed into nsspkcs5_NewParam */ 1.463 + param->encAlg = hmacAlg; 1.464 + param->hashType = prfType; 1.465 + param->keyLen = hmacLength; 1.466 + rv = SECOID_SetAlgorithmID(param->poolp, ¶m->prfAlg, prfAlg, NULL); 1.467 + if (rv != SECSuccess) { 1.468 + goto loser; 1.469 + } 1.470 + 1.471 + 1.472 + /* calculate the mac */ 1.473 + rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType, 1.474 + plainText, &signValue.value); 1.475 + if (rv != SECSuccess) { 1.476 + goto loser; 1.477 + } 1.478 + signValue.param = param; 1.479 + 1.480 + /* write it out */ 1.481 + rv = sftkdb_encodeCipherText(arena, &signValue, signature); 1.482 + if (rv != SECSuccess) { 1.483 + goto loser; 1.484 + } 1.485 + 1.486 +loser: 1.487 + if (param) { 1.488 + nsspkcs5_DestroyPBEParameter(param); 1.489 + } 1.490 + return rv; 1.491 +} 1.492 + 1.493 +/* 1.494 + * safely swith the passed in key for the one caches in the keydb handle 1.495 + * 1.496 + * A key attached to the handle tells us the the token is logged in. 1.497 + * We can used the key attached to the handle in sftkdb_EncryptAttribute 1.498 + * and sftkdb_DecryptAttribute calls. 1.499 + */ 1.500 +static void 1.501 +sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey) 1.502 +{ 1.503 + unsigned char *data; 1.504 + int len; 1.505 + 1.506 + if (keydb->passwordLock == NULL) { 1.507 + PORT_Assert(keydb->type != SFTK_KEYDB_TYPE); 1.508 + return; 1.509 + } 1.510 + 1.511 + /* an atomic pointer set would be nice */ 1.512 + SKIP_AFTER_FORK(PZ_Lock(keydb->passwordLock)); 1.513 + data = keydb->passwordKey.data; 1.514 + len = keydb->passwordKey.len; 1.515 + keydb->passwordKey.data = passKey->data; 1.516 + keydb->passwordKey.len = passKey->len; 1.517 + passKey->data = data; 1.518 + passKey->len = len; 1.519 + SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock)); 1.520 +} 1.521 + 1.522 +/* 1.523 + * returns true if we are in a middle of a merge style update. 1.524 + */ 1.525 +PRBool 1.526 +sftkdb_InUpdateMerge(SFTKDBHandle *keydb) 1.527 +{ 1.528 + return keydb->updateID ? PR_TRUE : PR_FALSE; 1.529 +} 1.530 + 1.531 +/* 1.532 + * returns true if we are looking for the password for the user's old source 1.533 + * database as part of a merge style update. 1.534 + */ 1.535 +PRBool 1.536 +sftkdb_NeedUpdateDBPassword(SFTKDBHandle *keydb) 1.537 +{ 1.538 + if (!sftkdb_InUpdateMerge(keydb)) { 1.539 + return PR_FALSE; 1.540 + } 1.541 + if (keydb->updateDBIsInit && !keydb->updatePasswordKey) { 1.542 + return PR_TRUE; 1.543 + } 1.544 + return PR_FALSE; 1.545 +} 1.546 + 1.547 +/* 1.548 + * fetch an update password key from a handle. 1.549 + */ 1.550 +SECItem * 1.551 +sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle) 1.552 +{ 1.553 + SECItem *key = NULL; 1.554 + 1.555 + /* if we're a cert db, fetch it from our peer key db */ 1.556 + if (handle->type == SFTK_CERTDB_TYPE) { 1.557 + handle = handle->peerDB; 1.558 + } 1.559 + 1.560 + /* don't have one */ 1.561 + if (!handle) { 1.562 + return NULL; 1.563 + } 1.564 + 1.565 + PZ_Lock(handle->passwordLock); 1.566 + if (handle->updatePasswordKey) { 1.567 + key = SECITEM_DupItem(handle->updatePasswordKey); 1.568 + } 1.569 + PZ_Unlock(handle->passwordLock); 1.570 + 1.571 + return key; 1.572 +} 1.573 + 1.574 +/* 1.575 + * free the update password key from a handle. 1.576 + */ 1.577 +void 1.578 +sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle) 1.579 +{ 1.580 + SECItem *key = NULL; 1.581 + 1.582 + /* don't have one */ 1.583 + if (!handle) { 1.584 + return; 1.585 + } 1.586 + 1.587 + /* if we're a cert db, we don't have one */ 1.588 + if (handle->type == SFTK_CERTDB_TYPE) { 1.589 + return; 1.590 + } 1.591 + 1.592 + PZ_Lock(handle->passwordLock); 1.593 + if (handle->updatePasswordKey) { 1.594 + key = handle->updatePasswordKey; 1.595 + handle->updatePasswordKey = NULL; 1.596 + } 1.597 + PZ_Unlock(handle->passwordLock); 1.598 + 1.599 + if (key) { 1.600 + SECITEM_ZfreeItem(key, PR_TRUE); 1.601 + } 1.602 + 1.603 + return; 1.604 +} 1.605 + 1.606 +/* 1.607 + * what password db we use depends heavily on the update state machine 1.608 + * 1.609 + * 1) no update db, return the normal database. 1.610 + * 2) update db and no merge return the update db. 1.611 + * 3) update db and in merge: 1.612 + * return the update db if we need the update db's password, 1.613 + * otherwise return our normal datbase. 1.614 + */ 1.615 +static SDB * 1.616 +sftk_getPWSDB(SFTKDBHandle *keydb) 1.617 +{ 1.618 + if (!keydb->update) { 1.619 + return keydb->db; 1.620 + } 1.621 + if (!sftkdb_InUpdateMerge(keydb)) { 1.622 + return keydb->update; 1.623 + } 1.624 + if (sftkdb_NeedUpdateDBPassword(keydb)) { 1.625 + return keydb->update; 1.626 + } 1.627 + return keydb->db; 1.628 +} 1.629 + 1.630 +/* 1.631 + * return success if we have a valid password entry. 1.632 + * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT 1.633 + * in the token flags. 1.634 + */ 1.635 +SECStatus 1.636 +sftkdb_HasPasswordSet(SFTKDBHandle *keydb) 1.637 +{ 1.638 + SECItem salt, value; 1.639 + unsigned char saltData[SDB_MAX_META_DATA_LEN]; 1.640 + unsigned char valueData[SDB_MAX_META_DATA_LEN]; 1.641 + CK_RV crv; 1.642 + SDB *db; 1.643 + 1.644 + if (keydb == NULL) { 1.645 + return SECFailure; 1.646 + } 1.647 + 1.648 + db = sftk_getPWSDB(keydb); 1.649 + if (db == NULL) { 1.650 + return SECFailure; 1.651 + } 1.652 + 1.653 + salt.data = saltData; 1.654 + salt.len = sizeof(saltData); 1.655 + value.data = valueData; 1.656 + value.len = sizeof(valueData); 1.657 + crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value); 1.658 + 1.659 + /* If no password is set, we can update right away */ 1.660 + if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update 1.661 + && crv != CKR_OK) { 1.662 + /* update the peer certdb if it exists */ 1.663 + if (keydb->peerDB) { 1.664 + sftkdb_Update(keydb->peerDB, NULL); 1.665 + } 1.666 + sftkdb_Update(keydb, NULL); 1.667 + } 1.668 + return (crv == CKR_OK) ? SECSuccess : SECFailure; 1.669 +} 1.670 + 1.671 +#define SFTK_PW_CHECK_STRING "password-check" 1.672 +#define SFTK_PW_CHECK_LEN 14 1.673 + 1.674 +/* 1.675 + * check if the supplied password is valid 1.676 + */ 1.677 +SECStatus 1.678 +sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved) 1.679 +{ 1.680 + SECStatus rv; 1.681 + SECItem salt, value; 1.682 + unsigned char saltData[SDB_MAX_META_DATA_LEN]; 1.683 + unsigned char valueData[SDB_MAX_META_DATA_LEN]; 1.684 + SECItem key; 1.685 + SECItem *result = NULL; 1.686 + SDB *db; 1.687 + CK_RV crv; 1.688 + 1.689 + if (keydb == NULL) { 1.690 + return SECFailure; 1.691 + } 1.692 + 1.693 + db = sftk_getPWSDB(keydb); 1.694 + if (db == NULL) { 1.695 + return SECFailure; 1.696 + } 1.697 + 1.698 + key.data = NULL; 1.699 + key.len = 0; 1.700 + 1.701 + if (pw == NULL) pw=""; 1.702 + 1.703 + /* get the entry from the database */ 1.704 + salt.data = saltData; 1.705 + salt.len = sizeof(saltData); 1.706 + value.data = valueData; 1.707 + value.len = sizeof(valueData); 1.708 + crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value); 1.709 + if (crv != CKR_OK) { 1.710 + rv = SECFailure; 1.711 + goto done; 1.712 + } 1.713 + 1.714 + /* get our intermediate key based on the entry salt value */ 1.715 + rv = sftkdb_passwordToKey(keydb, &salt, pw, &key); 1.716 + if (rv != SECSuccess) { 1.717 + goto done; 1.718 + } 1.719 + 1.720 + /* decrypt the entry value */ 1.721 + rv = sftkdb_DecryptAttribute(&key, &value, &result); 1.722 + if (rv != SECSuccess) { 1.723 + goto done; 1.724 + } 1.725 + 1.726 + /* if it's what we expect, update our key in the database handle and 1.727 + * return Success */ 1.728 + if ((result->len == SFTK_PW_CHECK_LEN) && 1.729 + PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0){ 1.730 + /* 1.731 + * We have a password, now lets handle any potential update cases.. 1.732 + * 1.733 + * First, the normal case: no update. In this case we only need the 1.734 + * the password for our only DB, which we now have, we switch 1.735 + * the keys and fall through. 1.736 + * Second regular (non-merge) update: The target DB does not yet have 1.737 + * a password initialized, we now have the password for the source DB, 1.738 + * so we can switch the keys and simply update the target database. 1.739 + * Merge update case: This one is trickier. 1.740 + * 1) If we need the source DB password, then we just got it here. 1.741 + * We need to save that password, 1.742 + * then we need to check to see if we need or have the target 1.743 + * database password. 1.744 + * If we have it (it's the same as the source), or don't need 1.745 + * it (it's not set or is ""), we can start the update now. 1.746 + * If we don't have it, we need the application to get it from 1.747 + * the user. Clear our sessions out to simulate a token 1.748 + * removal. C_GetTokenInfo will change the token description 1.749 + * and the token will still appear to be logged out. 1.750 + * 2) If we already have the source DB password, this password is 1.751 + * for the target database. We can now move forward with the 1.752 + * update, as we now have both required passwords. 1.753 + * 1.754 + */ 1.755 + PZ_Lock(keydb->passwordLock); 1.756 + if (sftkdb_NeedUpdateDBPassword(keydb)) { 1.757 + /* Squirrel this special key away. 1.758 + * This has the side effect of turning sftkdb_NeedLegacyPW off, 1.759 + * as well as changing which database is returned from 1.760 + * SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword() 1.761 + * and sftkdb_HasPasswordSet()) */ 1.762 + keydb->updatePasswordKey = SECITEM_DupItem(&key); 1.763 + PZ_Unlock(keydb->passwordLock); 1.764 + if (keydb->updatePasswordKey == NULL) { 1.765 + /* PORT_Error set by SECITEM_DupItem */ 1.766 + rv = SECFailure; 1.767 + goto done; 1.768 + } 1.769 + 1.770 + /* Simulate a token removal -- we need to do this any 1.771 + * any case at this point so the token name is correct. */ 1.772 + *tokenRemoved = PR_TRUE; 1.773 + 1.774 + /* 1.775 + * OK, we got the update DB password, see if we need a password 1.776 + * for the target... 1.777 + */ 1.778 + if (sftkdb_HasPasswordSet(keydb) == SECSuccess) { 1.779 + /* We have a password, do we know what the password is? 1.780 + * check 1) for the password the user supplied for the 1.781 + * update DB, 1.782 + * and 2) for the null password. 1.783 + * 1.784 + * RECURSION NOTE: we are calling ourselves here. This means 1.785 + * any updates, switchKeys, etc will have been completed 1.786 + * if these functions return successfully, in those cases 1.787 + * just exit returning Success. We don't recurse infinitely 1.788 + * because we are making this call from a NeedUpdateDBPassword 1.789 + * block and we've already set that update password at this 1.790 + * point. */ 1.791 + rv = sftkdb_CheckPassword(keydb, pw, tokenRemoved); 1.792 + if (rv == SECSuccess) { 1.793 + /* source and target databases have the same password, we 1.794 + * are good to go */ 1.795 + goto done; 1.796 + } 1.797 + sftkdb_CheckPassword(keydb, "", tokenRemoved); 1.798 + 1.799 + /* 1.800 + * Important 'NULL' code here. At this point either we 1.801 + * succeeded in logging in with "" or we didn't. 1.802 + * 1.803 + * If we did succeed at login, our machine state will be set 1.804 + * to logged in appropriately. The application will find that 1.805 + * it's logged in as soon as it opens a new session. We have 1.806 + * also completed the update. Life is good. 1.807 + * 1.808 + * If we did not succeed, well the user still successfully 1.809 + * logged into the update database, since we faked the token 1.810 + * removal it's just like the user logged into his smart card 1.811 + * then removed it. the actual login work, so we report that 1.812 + * success back to the user, but we won't actually be 1.813 + * logged in. The application will find this out when it 1.814 + * checks it's login state, thus triggering another password 1.815 + * prompt so we can get the real target DB password. 1.816 + * 1.817 + * summary, we exit from here with SECSuccess no matter what. 1.818 + */ 1.819 + rv = SECSuccess; 1.820 + goto done; 1.821 + } else { 1.822 + /* there is no password, just fall through to update. 1.823 + * update will write the source DB's password record 1.824 + * into the target DB just like it would in a non-merge 1.825 + * update case. */ 1.826 + } 1.827 + } else { 1.828 + PZ_Unlock(keydb->passwordLock); 1.829 + } 1.830 + /* load the keys, so the keydb can parse it's key set */ 1.831 + sftkdb_switchKeys(keydb, &key); 1.832 + 1.833 + /* we need to update, do it now */ 1.834 + if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) { 1.835 + /* update the peer certdb if it exists */ 1.836 + if (keydb->peerDB) { 1.837 + sftkdb_Update(keydb->peerDB, &key); 1.838 + } 1.839 + sftkdb_Update(keydb, &key); 1.840 + } 1.841 + } else { 1.842 + rv = SECFailure; 1.843 + /*PORT_SetError( bad password); */ 1.844 + } 1.845 + 1.846 +done: 1.847 + if (key.data) { 1.848 + PORT_ZFree(key.data,key.len); 1.849 + } 1.850 + if (result) { 1.851 + SECITEM_FreeItem(result,PR_TRUE); 1.852 + } 1.853 + return rv; 1.854 +} 1.855 + 1.856 +/* 1.857 + * return Success if the there is a cached password key. 1.858 + */ 1.859 +SECStatus 1.860 +sftkdb_PWCached(SFTKDBHandle *keydb) 1.861 +{ 1.862 + return keydb->passwordKey.data ? SECSuccess : SECFailure; 1.863 +} 1.864 + 1.865 + 1.866 +static CK_RV 1.867 +sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle, 1.868 + CK_OBJECT_HANDLE id, SECItem *newKey) 1.869 +{ 1.870 + CK_RV crv = CKR_OK; 1.871 + CK_RV crv2; 1.872 + CK_ATTRIBUTE authAttrs[] = { 1.873 + {CKA_MODULUS, NULL, 0}, 1.874 + {CKA_PUBLIC_EXPONENT, NULL, 0}, 1.875 + {CKA_CERT_SHA1_HASH, NULL, 0}, 1.876 + {CKA_CERT_MD5_HASH, NULL, 0}, 1.877 + {CKA_TRUST_SERVER_AUTH, NULL, 0}, 1.878 + {CKA_TRUST_CLIENT_AUTH, NULL, 0}, 1.879 + {CKA_TRUST_EMAIL_PROTECTION, NULL, 0}, 1.880 + {CKA_TRUST_CODE_SIGNING, NULL, 0}, 1.881 + {CKA_TRUST_STEP_UP_APPROVED, NULL, 0}, 1.882 + {CKA_NSS_OVERRIDE_EXTENSIONS, NULL, 0}, 1.883 + }; 1.884 + CK_ULONG authAttrCount = sizeof(authAttrs)/sizeof(CK_ATTRIBUTE); 1.885 + int i, count; 1.886 + SFTKDBHandle *keyHandle = handle; 1.887 + SDB *keyTarget = NULL; 1.888 + 1.889 + id &= SFTK_OBJ_ID_MASK; 1.890 + 1.891 + if (handle->type != SFTK_KEYDB_TYPE) { 1.892 + keyHandle = handle->peerDB; 1.893 + } 1.894 + 1.895 + if (keyHandle == NULL) { 1.896 + return CKR_OK; 1.897 + } 1.898 + 1.899 + /* old DB's don't have meta data, finished with MACs */ 1.900 + keyTarget = SFTK_GET_SDB(keyHandle); 1.901 + if ((keyTarget->sdb_flags &SDB_HAS_META) == 0) { 1.902 + return CKR_OK; 1.903 + } 1.904 + 1.905 + /* 1.906 + * STEP 1: find the MACed attributes of this object 1.907 + */ 1.908 + crv2 = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount); 1.909 + count = 0; 1.910 + /* allocate space for the attributes */ 1.911 + for (i=0; i < authAttrCount; i++) { 1.912 + if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){ 1.913 + continue; 1.914 + } 1.915 + count++; 1.916 + authAttrs[i].pValue = PORT_ArenaAlloc(arena,authAttrs[i].ulValueLen); 1.917 + if (authAttrs[i].pValue == NULL) { 1.918 + crv = CKR_HOST_MEMORY; 1.919 + break; 1.920 + } 1.921 + } 1.922 + 1.923 + /* if count was zero, none were found, finished with MACs */ 1.924 + if (count == 0) { 1.925 + return CKR_OK; 1.926 + } 1.927 + 1.928 + crv = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount); 1.929 + /* ignore error code, we expect some possible errors */ 1.930 + 1.931 + /* GetAttributeValue just verified the old macs, safe to write 1.932 + * them out then... */ 1.933 + for (i=0; i < authAttrCount; i++) { 1.934 + SECItem *signText; 1.935 + SECItem plainText; 1.936 + SECStatus rv; 1.937 + 1.938 + if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){ 1.939 + continue; 1.940 + } 1.941 + 1.942 + plainText.data = authAttrs[i].pValue; 1.943 + plainText.len = authAttrs[i].ulValueLen; 1.944 + rv = sftkdb_SignAttribute(arena, newKey, id, 1.945 + authAttrs[i].type, &plainText, &signText); 1.946 + if (rv != SECSuccess) { 1.947 + return CKR_GENERAL_ERROR; 1.948 + } 1.949 + rv = sftkdb_PutAttributeSignature(handle, keyTarget, id, 1.950 + authAttrs[i].type, signText); 1.951 + if (rv != SECSuccess) { 1.952 + return CKR_GENERAL_ERROR; 1.953 + } 1.954 + } 1.955 + 1.956 + return CKR_OK; 1.957 +} 1.958 + 1.959 +static CK_RV 1.960 +sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb, 1.961 + CK_OBJECT_HANDLE id, SECItem *newKey) 1.962 +{ 1.963 + CK_RV crv = CKR_OK; 1.964 + CK_RV crv2; 1.965 + CK_ATTRIBUTE *first, *last; 1.966 + CK_ATTRIBUTE privAttrs[] = { 1.967 + {CKA_VALUE, NULL, 0}, 1.968 + {CKA_PRIVATE_EXPONENT, NULL, 0}, 1.969 + {CKA_PRIME_1, NULL, 0}, 1.970 + {CKA_PRIME_2, NULL, 0}, 1.971 + {CKA_EXPONENT_1, NULL, 0}, 1.972 + {CKA_EXPONENT_2, NULL, 0}, 1.973 + {CKA_COEFFICIENT, NULL, 0} }; 1.974 + CK_ULONG privAttrCount = sizeof(privAttrs)/sizeof(CK_ATTRIBUTE); 1.975 + int i, count; 1.976 + 1.977 + /* 1.978 + * STEP 1. Read the old attributes in the clear. 1.979 + */ 1.980 + 1.981 + /* Get the attribute sizes. 1.982 + * ignore the error code, we will have unknown attributes here */ 1.983 + crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount); 1.984 + 1.985 + /* 1.986 + * find the valid block of attributes and fill allocate space for 1.987 + * their data */ 1.988 + first = last = NULL; 1.989 + for (i=0; i < privAttrCount; i++) { 1.990 + /* find the block of attributes that are appropriate for this 1.991 + * objects. There should only be once contiguous block, if not 1.992 + * there's an error. 1.993 + * 1.994 + * find the first and last good entry. 1.995 + */ 1.996 + if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)){ 1.997 + if (!first) continue; 1.998 + if (!last) { 1.999 + /* previous entry was last good entry */ 1.1000 + last= &privAttrs[i-1]; 1.1001 + } 1.1002 + continue; 1.1003 + } 1.1004 + if (!first) { 1.1005 + first = &privAttrs[i]; 1.1006 + } 1.1007 + if (last) { 1.1008 + /* OOPS, we've found another good entry beyond the end of the 1.1009 + * last good entry, we need to fail here. */ 1.1010 + crv = CKR_GENERAL_ERROR; 1.1011 + break; 1.1012 + } 1.1013 + privAttrs[i].pValue = PORT_ArenaAlloc(arena,privAttrs[i].ulValueLen); 1.1014 + if (privAttrs[i].pValue == NULL) { 1.1015 + crv = CKR_HOST_MEMORY; 1.1016 + break; 1.1017 + } 1.1018 + } 1.1019 + if (first == NULL) { 1.1020 + /* no valid entries found, return error based on crv2 */ 1.1021 + return crv2; 1.1022 + } 1.1023 + if (last == NULL) { 1.1024 + last = &privAttrs[privAttrCount-1]; 1.1025 + } 1.1026 + if (crv != CKR_OK) { 1.1027 + return crv; 1.1028 + } 1.1029 + /* read the attributes */ 1.1030 + count = (last-first)+1; 1.1031 + crv = sftkdb_GetAttributeValue(keydb, id, first, count); 1.1032 + if (crv != CKR_OK) { 1.1033 + return crv; 1.1034 + } 1.1035 + 1.1036 + /* 1.1037 + * STEP 2: read the encrypt the attributes with the new key. 1.1038 + */ 1.1039 + for (i=0; i < count; i++) { 1.1040 + SECItem plainText; 1.1041 + SECItem *result; 1.1042 + SECStatus rv; 1.1043 + 1.1044 + plainText.data = first[i].pValue; 1.1045 + plainText.len = first[i].ulValueLen; 1.1046 + rv = sftkdb_EncryptAttribute(arena, newKey, &plainText, &result); 1.1047 + if (rv != SECSuccess) { 1.1048 + return CKR_GENERAL_ERROR; 1.1049 + } 1.1050 + first[i].pValue = result->data; 1.1051 + first[i].ulValueLen = result->len; 1.1052 + /* clear our sensitive data out */ 1.1053 + PORT_Memset(plainText.data, 0, plainText.len); 1.1054 + } 1.1055 + 1.1056 + 1.1057 + /* 1.1058 + * STEP 3: write the newly encrypted attributes out directly 1.1059 + */ 1.1060 + id &= SFTK_OBJ_ID_MASK; 1.1061 + keydb->newKey = newKey; 1.1062 + crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count); 1.1063 + keydb->newKey = NULL; 1.1064 + 1.1065 + return crv; 1.1066 +} 1.1067 + 1.1068 +static CK_RV 1.1069 +sftk_convertAttributes(SFTKDBHandle *handle, 1.1070 + CK_OBJECT_HANDLE id, SECItem *newKey) 1.1071 +{ 1.1072 + CK_RV crv = CKR_OK; 1.1073 + PLArenaPool *arena = NULL; 1.1074 + 1.1075 + /* get a new arena to simplify cleanup */ 1.1076 + arena = PORT_NewArena(1024); 1.1077 + if (!arena) { 1.1078 + return CKR_HOST_MEMORY; 1.1079 + } 1.1080 + 1.1081 + /* 1.1082 + * first handle the MACS 1.1083 + */ 1.1084 + crv = sftk_updateMacs(arena, handle, id, newKey); 1.1085 + if (crv != CKR_OK) { 1.1086 + goto loser; 1.1087 + } 1.1088 + 1.1089 + if (handle->type == SFTK_KEYDB_TYPE) { 1.1090 + crv = sftk_updateEncrypted(arena, handle, id, newKey); 1.1091 + if (crv != CKR_OK) { 1.1092 + goto loser; 1.1093 + } 1.1094 + } 1.1095 + 1.1096 + /* free up our mess */ 1.1097 + /* NOTE: at this point we know we've cleared out any unencrypted data */ 1.1098 + PORT_FreeArena(arena, PR_FALSE); 1.1099 + return CKR_OK; 1.1100 + 1.1101 +loser: 1.1102 + /* there may be unencrypted data, clear it out down */ 1.1103 + PORT_FreeArena(arena, PR_TRUE); 1.1104 + return crv; 1.1105 +} 1.1106 + 1.1107 + 1.1108 +/* 1.1109 + * must be called with the old key active. 1.1110 + */ 1.1111 +CK_RV 1.1112 +sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template, 1.1113 + CK_ULONG count, SECItem *newKey) 1.1114 +{ 1.1115 + SDBFind *find = NULL; 1.1116 + CK_ULONG idCount = SFTK_MAX_IDS; 1.1117 + CK_OBJECT_HANDLE ids[SFTK_MAX_IDS]; 1.1118 + CK_RV crv, crv2; 1.1119 + int i; 1.1120 + 1.1121 + crv = sftkdb_FindObjectsInit(handle, template, count, &find); 1.1122 + 1.1123 + if (crv != CKR_OK) { 1.1124 + return crv; 1.1125 + } 1.1126 + while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) { 1.1127 + crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount); 1.1128 + for (i=0; (crv == CKR_OK) && (i < idCount); i++) { 1.1129 + crv = sftk_convertAttributes(handle, ids[i], newKey); 1.1130 + } 1.1131 + } 1.1132 + crv2 = sftkdb_FindObjectsFinal(handle, find); 1.1133 + if (crv == CKR_OK) crv = crv2; 1.1134 + 1.1135 + return crv; 1.1136 +} 1.1137 + 1.1138 + 1.1139 +/* 1.1140 + * change the database password. 1.1141 + */ 1.1142 +SECStatus 1.1143 +sftkdb_ChangePassword(SFTKDBHandle *keydb, 1.1144 + char *oldPin, char *newPin, PRBool *tokenRemoved) 1.1145 +{ 1.1146 + SECStatus rv = SECSuccess; 1.1147 + SECItem plainText; 1.1148 + SECItem newKey; 1.1149 + SECItem *result = NULL; 1.1150 + SECItem salt, value; 1.1151 + SFTKDBHandle *certdb; 1.1152 + unsigned char saltData[SDB_MAX_META_DATA_LEN]; 1.1153 + unsigned char valueData[SDB_MAX_META_DATA_LEN]; 1.1154 + CK_RV crv; 1.1155 + SDB *db; 1.1156 + 1.1157 + if (keydb == NULL) { 1.1158 + return SECFailure; 1.1159 + } 1.1160 + 1.1161 + db = SFTK_GET_SDB(keydb); 1.1162 + if (db == NULL) { 1.1163 + return SECFailure; 1.1164 + } 1.1165 + 1.1166 + newKey.data = NULL; 1.1167 + 1.1168 + /* make sure we have a valid old pin */ 1.1169 + crv = (*keydb->db->sdb_Begin)(keydb->db); 1.1170 + if (crv != CKR_OK) { 1.1171 + rv = SECFailure; 1.1172 + goto loser; 1.1173 + } 1.1174 + salt.data = saltData; 1.1175 + salt.len = sizeof(saltData); 1.1176 + value.data = valueData; 1.1177 + value.len = sizeof(valueData); 1.1178 + crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value); 1.1179 + if (crv == CKR_OK) { 1.1180 + rv = sftkdb_CheckPassword(keydb, oldPin, tokenRemoved); 1.1181 + if (rv == SECFailure) { 1.1182 + goto loser; 1.1183 + } 1.1184 + } else { 1.1185 + salt.len = SHA1_LENGTH; 1.1186 + RNG_GenerateGlobalRandomBytes(salt.data,salt.len); 1.1187 + } 1.1188 + 1.1189 + rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey); 1.1190 + if (rv != SECSuccess) { 1.1191 + goto loser; 1.1192 + } 1.1193 + 1.1194 + 1.1195 + /* 1.1196 + * convert encrypted entries here. 1.1197 + */ 1.1198 + crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey); 1.1199 + if (crv != CKR_OK) { 1.1200 + rv = SECFailure; 1.1201 + goto loser; 1.1202 + } 1.1203 + /* fix up certdb macs */ 1.1204 + certdb = keydb->peerDB; 1.1205 + if (certdb) { 1.1206 + CK_ATTRIBUTE objectType = { CKA_CLASS, 0, sizeof(CK_OBJECT_CLASS) }; 1.1207 + CK_OBJECT_CLASS myClass = CKO_NETSCAPE_TRUST; 1.1208 + 1.1209 + objectType.pValue = &myClass; 1.1210 + crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey); 1.1211 + if (crv != CKR_OK) { 1.1212 + rv = SECFailure; 1.1213 + goto loser; 1.1214 + } 1.1215 + myClass = CKO_PUBLIC_KEY; 1.1216 + crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey); 1.1217 + if (crv != CKR_OK) { 1.1218 + rv = SECFailure; 1.1219 + goto loser; 1.1220 + } 1.1221 + } 1.1222 + 1.1223 + 1.1224 + plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING; 1.1225 + plainText.len = SFTK_PW_CHECK_LEN; 1.1226 + 1.1227 + rv = sftkdb_EncryptAttribute(NULL, &newKey, &plainText, &result); 1.1228 + if (rv != SECSuccess) { 1.1229 + goto loser; 1.1230 + } 1.1231 + value.data = result->data; 1.1232 + value.len = result->len; 1.1233 + crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value); 1.1234 + if (crv != CKR_OK) { 1.1235 + rv = SECFailure; 1.1236 + goto loser; 1.1237 + } 1.1238 + crv = (*keydb->db->sdb_Commit)(keydb->db); 1.1239 + if (crv != CKR_OK) { 1.1240 + rv = SECFailure; 1.1241 + goto loser; 1.1242 + } 1.1243 + 1.1244 + keydb->newKey = NULL; 1.1245 + 1.1246 + sftkdb_switchKeys(keydb, &newKey); 1.1247 + 1.1248 +loser: 1.1249 + if (newKey.data) { 1.1250 + PORT_ZFree(newKey.data,newKey.len); 1.1251 + } 1.1252 + if (result) { 1.1253 + SECITEM_FreeItem(result, PR_FALSE); 1.1254 + } 1.1255 + if (rv != SECSuccess) { 1.1256 + (*keydb->db->sdb_Abort)(keydb->db); 1.1257 + } 1.1258 + 1.1259 + return rv; 1.1260 +} 1.1261 + 1.1262 +/* 1.1263 + * lose our cached password 1.1264 + */ 1.1265 +SECStatus 1.1266 +sftkdb_ClearPassword(SFTKDBHandle *keydb) 1.1267 +{ 1.1268 + SECItem oldKey; 1.1269 + oldKey.data = NULL; 1.1270 + oldKey.len = 0; 1.1271 + sftkdb_switchKeys(keydb, &oldKey); 1.1272 + if (oldKey.data) { 1.1273 + PORT_ZFree(oldKey.data, oldKey.len); 1.1274 + } 1.1275 + return SECSuccess; 1.1276 +} 1.1277 + 1.1278 +