| OLD | NEW |
| (Empty) |
| 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" | |
| 36 | |
| 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 */ | |
| 48 | |
| 49 | |
| 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; | |
| 60 | |
| 61 key->data = PORT_Alloc(SHA1_LENGTH); | |
| 62 if (key->data == NULL) { | |
| 63 goto loser; | |
| 64 } | |
| 65 key->len = SHA1_LENGTH; | |
| 66 | |
| 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; | |
| 78 | |
| 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 } | |
| 91 | |
| 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 }; | |
| 109 | |
| 110 #define SFTK_CIPHERTEXT_VERSION 3 | |
| 111 | |
| 112 struct SFTKDBEncryptedDataInfoStr { | |
| 113 SECAlgorithmID algorithm; | |
| 114 SECItem encryptedData; | |
| 115 }; | |
| 116 typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo; | |
| 117 | |
| 118 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) | |
| 119 | |
| 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 }; | |
| 130 | |
| 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; | |
| 141 | |
| 142 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 143 if (arena == NULL) { | |
| 144 return SECFailure; | |
| 145 } | |
| 146 cipherValue->arena = NULL; | |
| 147 cipherValue->param = NULL; | |
| 148 | |
| 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; | |
| 161 | |
| 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 } | |
| 173 | |
| 174 | |
| 175 | |
| 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; | |
| 189 | |
| 190 | |
| 191 localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 192 if (localArena == NULL) { | |
| 193 return SECFailure; | |
| 194 } | |
| 195 | |
| 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; | |
| 208 | |
| 209 *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi, | |
| 210 sftkdb_EncryptedDataInfoTemplate); | |
| 211 if (*cipherText == NULL) { | |
| 212 rv = SECFailure; | |
| 213 } | |
| 214 | |
| 215 loser: | |
| 216 if (localArena) { | |
| 217 PORT_FreeArena(localArena,PR_FALSE); | |
| 218 } | |
| 219 | |
| 220 return rv; | |
| 221 } | |
| 222 | |
| 223 | |
| 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; | |
| 235 | |
| 236 /* First get the cipher type */ | |
| 237 rv = sftkdb_decodeCipherText(cipherText, &cipherValue); | |
| 238 if (rv != SECSuccess) { | |
| 239 goto loser; | |
| 240 } | |
| 241 | |
| 242 *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value,
| |
| 243 PR_FALSE, NULL); | |
| 244 if (*plain == NULL) { | |
| 245 rv = SECFailure; | |
| 246 goto loser; | |
| 247 } | |
| 248 | |
| 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 } | |
| 258 | |
| 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]; | |
| 274 | |
| 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); | |
| 279 | |
| 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; | |
| 292 | |
| 293 rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText); | |
| 294 if (rv != SECSuccess) { | |
| 295 goto loser; | |
| 296 } | |
| 297 | |
| 298 loser: | |
| 299 if (cipher) { | |
| 300 SECITEM_FreeItem(cipher, PR_TRUE); | |
| 301 } | |
| 302 if (param) { | |
| 303 nsspkcs5_DestroyPBEParameter(param); | |
| 304 } | |
| 305 return rv; | |
| 306 } | |
| 307 | |
| 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]; | |
| 326 | |
| 327 hashType = HASH_FromHMACOid(param->encAlg); | |
| 328 if (hashType == HASH_AlgNULL) { | |
| 329 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 330 return SECFailure; | |
| 331 } | |
| 332 | |
| 333 hashObj = HASH_GetRawHashObject(hashType); | |
| 334 if (hashObj == NULL) { | |
| 335 goto loser; | |
| 336 } | |
| 337 | |
| 338 key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE); | |
| 339 if (!key) { | |
| 340 goto loser; | |
| 341 } | |
| 342 | |
| 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); | |
| 355 | |
| 356 HMAC_Update(hashCx, plainText->data, plainText->len); | |
| 357 rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len); | |
| 358 | |
| 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 } | |
| 368 | |
| 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]; | |
| 383 | |
| 384 | |
| 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); | |
| 392 | |
| 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 } | |
| 402 | |
| 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 } | |
| 412 | |
| 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; | |
| 432 | |
| 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); | |
| 439 | |
| 440 hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length; | |
| 441 PORT_Assert(hmacLength <= HASH_LENGTH_MAX); | |
| 442 | |
| 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); | |
| 450 | |
| 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, ¶m->prfAlg, prfAlg, NULL); | |
| 464 if (rv != SECSuccess) { | |
| 465 goto loser; | |
| 466 } | |
| 467 | |
| 468 | |
| 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; | |
| 476 | |
| 477 /* write it out */ | |
| 478 rv = sftkdb_encodeCipherText(arena, &signValue, signature); | |
| 479 if (rv != SECSuccess) { | |
| 480 goto loser; | |
| 481 } | |
| 482 | |
| 483 loser: | |
| 484 if (param) { | |
| 485 nsspkcs5_DestroyPBEParameter(param); | |
| 486 } | |
| 487 return rv; | |
| 488 } | |
| 489 | |
| 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; | |
| 502 | |
| 503 if (keydb->passwordLock == NULL) { | |
| 504 PORT_Assert(keydb->type != SFTK_KEYDB_TYPE); | |
| 505 return; | |
| 506 } | |
| 507 | |
| 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 } | |
| 518 | |
| 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 } | |
| 527 | |
| 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 } | |
| 543 | |
| 544 /* | |
| 545 * fetch an update password key from a handle. | |
| 546 */ | |
| 547 SECItem * | |
| 548 sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle) | |
| 549 { | |
| 550 SECItem *key = NULL; | |
| 551 | |
| 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 } | |
| 556 | |
| 557 /* don't have one */ | |
| 558 if (!handle) { | |
| 559 return NULL; | |
| 560 } | |
| 561 | |
| 562 PZ_Lock(handle->passwordLock); | |
| 563 if (handle->updatePasswordKey) { | |
| 564 key = SECITEM_DupItem(handle->updatePasswordKey); | |
| 565 } | |
| 566 PZ_Unlock(handle->passwordLock); | |
| 567 | |
| 568 return key; | |
| 569 } | |
| 570 | |
| 571 /* | |
| 572 * free the update password key from a handle. | |
| 573 */ | |
| 574 void | |
| 575 sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle) | |
| 576 { | |
| 577 SECItem *key = NULL; | |
| 578 | |
| 579 /* don't have one */ | |
| 580 if (!handle) { | |
| 581 return; | |
| 582 } | |
| 583 | |
| 584 /* if we're a cert db, we don't have one */ | |
| 585 if (handle->type == SFTK_CERTDB_TYPE) { | |
| 586 return; | |
| 587 } | |
| 588 | |
| 589 PZ_Lock(handle->passwordLock); | |
| 590 if (handle->updatePasswordKey) { | |
| 591 key = handle->updatePasswordKey; | |
| 592 handle->updatePasswordKey = NULL; | |
| 593 } | |
| 594 PZ_Unlock(handle->passwordLock); | |
| 595 | |
| 596 if (key) { | |
| 597 SECITEM_ZfreeItem(key, PR_TRUE); | |
| 598 } | |
| 599 | |
| 600 return; | |
| 601 } | |
| 602 | |
| 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 } | |
| 626 | |
| 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; | |
| 640 | |
| 641 if (keydb == NULL) { | |
| 642 return SECFailure; | |
| 643 } | |
| 644 | |
| 645 db = sftk_getPWSDB(keydb); | |
| 646 if (db == NULL) { | |
| 647 return SECFailure; | |
| 648 } | |
| 649 | |
| 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); | |
| 655 | |
| 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 } | |
| 667 | |
| 668 #define SFTK_PW_CHECK_STRING "password-check" | |
| 669 #define SFTK_PW_CHECK_LEN 14 | |
| 670 | |
| 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; | |
| 685 | |
| 686 if (keydb == NULL) { | |
| 687 return SECFailure; | |
| 688 } | |
| 689 | |
| 690 db = sftk_getPWSDB(keydb); | |
| 691 if (db == NULL) { | |
| 692 return SECFailure; | |
| 693 } | |
| 694 | |
| 695 key.data = NULL; | |
| 696 key.len = 0; | |
| 697 | |
| 698 if (pw == NULL) pw=""; | |
| 699 | |
| 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 } | |
| 710 | |
| 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 } | |
| 716 | |
| 717 /* decrypt the entry value */ | |
| 718 rv = sftkdb_DecryptAttribute(&key, &value, &result); | |
| 719 if (rv != SECSuccess) { | |
| 720 goto done; | |
| 721 } | |
| 722 | |
| 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 } | |
| 766 | |
| 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; | |
| 770 | |
| 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); | |
| 795 | |
| 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); | |
| 829 | |
| 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 } | |
| 842 | |
| 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 } | |
| 852 | |
| 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 } | |
| 861 | |
| 862 | |
| 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; | |
| 885 | |
| 886 id &= SFTK_OBJ_ID_MASK; | |
| 887 | |
| 888 if (handle->type != SFTK_KEYDB_TYPE) { | |
| 889 keyHandle = handle->peerDB; | |
| 890 } | |
| 891 | |
| 892 if (keyHandle == NULL) { | |
| 893 return CKR_OK; | |
| 894 } | |
| 895 | |
| 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 } | |
| 901 | |
| 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 } | |
| 919 | |
| 920 /* if count was zero, none were found, finished with MACs */ | |
| 921 if (count == 0) { | |
| 922 return CKR_OK; | |
| 923 } | |
| 924 | |
| 925 crv = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount); | |
| 926 /* ignore error code, we expect some possible errors */ | |
| 927 | |
| 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; | |
| 934 | |
| 935 if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){ | |
| 936 continue; | |
| 937 } | |
| 938 | |
| 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 } | |
| 952 | |
| 953 return CKR_OK; | |
| 954 } | |
| 955 | |
| 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; | |
| 973 | |
| 974 /* | |
| 975 * STEP 1. Read the old attributes in the clear. | |
| 976 */ | |
| 977 | |
| 978 /* Get the attribute sizes. | |
| 979 * ignore the error code, we will have unknown attributes here */ | |
| 980 crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount); | |
| 981 | |
| 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; | |
| 1000 } | |
| 1001 if (!first) { | |
| 1002 first = &privAttrs[i]; | |
| 1003 } | |
| 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; | |
| 1009 } | |
| 1010 privAttrs[i].pValue = PORT_ArenaAlloc(arena,privAttrs[i].ulValueLen); | |
| 1011 if (privAttrs[i].pValue == NULL) { | |
| 1012 crv = CKR_HOST_MEMORY; | |
| 1013 break; | |
| 1014 } | |
| 1015 } | |
| 1016 if (first == NULL) { | |
| 1017 /* no valid entries found, return error based on crv2 */ | |
| 1018 return crv2; | |
| 1019 } | |
| 1020 if (last == NULL) { | |
| 1021 last = &privAttrs[privAttrCount-1]; | |
| 1022 } | |
| 1023 if (crv != CKR_OK) { | |
| 1024 return crv; | |
| 1025 } | |
| 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; | |
| 1031 } | |
| 1032 | |
| 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; | |
| 1040 | |
| 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; | |
| 1046 } | |
| 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); | |
| 1051 } | |
| 1052 | |
| 1053 | |
| 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; | |
| 1061 | |
| 1062 return crv; | |
| 1063 } | |
| 1064 | |
| 1065 static CK_RV | |
| 1066 sftk_convertAttributes(SFTKDBHandle *handle, | |
| 1067 CK_OBJECT_HANDLE id, SECItem *newKey) | |
| 1068 { | |
| 1069 CK_RV crv = CKR_OK; | |
| 1070 PLArenaPool *arena = NULL; | |
| 1071 | |
| 1072 /* get a new arena to simplify cleanup */ | |
| 1073 arena = PORT_NewArena(1024); | |
| 1074 if (!arena) { | |
| 1075 return CKR_HOST_MEMORY; | |
| 1076 } | |
| 1077 | |
| 1078 /* | |
| 1079 * first handle the MACS | |
| 1080 */ | |
| 1081 crv = sftk_updateMacs(arena, handle, id, newKey); | |
| 1082 if (crv != CKR_OK) { | |
| 1083 goto loser; | |
| 1084 } | |
| 1085 | |
| 1086 if (handle->type == SFTK_KEYDB_TYPE) { | |
| 1087 crv = sftk_updateEncrypted(arena, handle, id, newKey); | |
| 1088 if (crv != CKR_OK) { | |
| 1089 goto loser; | |
| 1090 } | |
| 1091 } | |
| 1092 | |
| 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; | |
| 1097 | |
| 1098 loser: | |
| 1099 /* there may be unencrypted data, clear it out down */ | |
| 1100 PORT_FreeArena(arena, PR_TRUE); | |
| 1101 return crv; | |
| 1102 } | |
| 1103 | |
| 1104 | |
| 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) | |
| 1111 { | |
| 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; | |
| 1117 | |
| 1118 crv = sftkdb_FindObjectsInit(handle, template, count, &find); | |
| 1119 | |
| 1120 if (crv != CKR_OK) { | |
| 1121 return crv; | |
| 1122 } | |
| 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); | |
| 1127 } | |
| 1128 } | |
| 1129 crv2 = sftkdb_FindObjectsFinal(handle, find); | |
| 1130 if (crv == CKR_OK) crv = crv2; | |
| 1131 | |
| 1132 return crv; | |
| 1133 } | |
| 1134 | |
| 1135 | |
| 1136 /* | |
| 1137 * change the database password. | |
| 1138 */ | |
| 1139 SECStatus | |
| 1140 sftkdb_ChangePassword(SFTKDBHandle *keydb, | |
| 1141 char *oldPin, char *newPin, PRBool *tokenRemoved) | |
| 1142 { | |
| 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; | |
| 1153 | |
| 1154 if (keydb == NULL) { | |
| 1155 return SECFailure; | |
| 1156 } | |
| 1157 | |
| 1158 db = SFTK_GET_SDB(keydb); | |
| 1159 if (db == NULL) { | |
| 1160 return SECFailure; | |
| 1161 } | |
| 1162 | |
| 1163 newKey.data = NULL; | |
| 1164 | |
| 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; | |
| 1170 } | |
| 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; | |
| 1180 } | |
| 1181 } else { | |
| 1182 salt.len = SHA1_LENGTH; | |
| 1183 RNG_GenerateGlobalRandomBytes(salt.data,salt.len); | |
| 1184 } | |
| 1185 | |
| 1186 rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey); | |
| 1187 if (rv != SECSuccess) { | |
| 1188 goto loser; | |
| 1189 } | |
| 1190 | |
| 1191 | |
| 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; | |
| 1199 } | |
| 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; | |
| 1205 | |
| 1206 objectType.pValue = &myClass; | |
| 1207 crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey); | |
| 1208 if (crv != CKR_OK) { | |
| 1209 rv = SECFailure; | |
| 1210 goto loser; | |
| 1211 } | |
| 1212 myClass = CKO_PUBLIC_KEY; | |
| 1213 crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey); | |
| 1214 if (crv != CKR_OK) { | |
| 1215 rv = SECFailure; | |
| 1216 goto loser; | |
| 1217 } | |
| 1218 } | |
| 1219 | |
| 1220 | |
| 1221 plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING; | |
| 1222 plainText.len = SFTK_PW_CHECK_LEN; | |
| 1223 | |
| 1224 rv = sftkdb_EncryptAttribute(NULL, &newKey, &plainText, &result); | |
| 1225 if (rv != SECSuccess) { | |
| 1226 goto loser; | |
| 1227 } | |
| 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; | |
| 1234 } | |
| 1235 crv = (*keydb->db->sdb_Commit)(keydb->db); | |
| 1236 if (crv != CKR_OK) { | |
| 1237 rv = SECFailure; | |
| 1238 goto loser; | |
| 1239 } | |
| 1240 | |
| 1241 keydb->newKey = NULL; | |
| 1242 | |
| 1243 sftkdb_switchKeys(keydb, &newKey); | |
| 1244 | |
| 1245 loser: | |
| 1246 if (newKey.data) { | |
| 1247 PORT_ZFree(newKey.data,newKey.len); | |
| 1248 } | |
| 1249 if (result) { | |
| 1250 SECITEM_FreeItem(result, PR_FALSE); | |
| 1251 } | |
| 1252 if (rv != SECSuccess) { | |
| 1253 (*keydb->db->sdb_Abort)(keydb->db); | |
| 1254 } | |
| 1255 | |
| 1256 return rv; | |
| 1257 } | |
| 1258 | |
| 1259 /* | |
| 1260 * lose our cached password | |
| 1261 */ | |
| 1262 SECStatus | |
| 1263 sftkdb_ClearPassword(SFTKDBHandle *keydb) | |
| 1264 { | |
| 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); | |
| 1271 } | |
| 1272 return SECSuccess; | |
| 1273 } | |
| 1274 | |
| 1275 | |
| OLD | NEW |