keydb.c (61987B)
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 #include "lowkeyi.h" 6 #include "secasn1.h" 7 #include "secder.h" 8 #include "secoid.h" 9 #include "blapi.h" 10 #include "secitem.h" 11 #include "pcert.h" 12 #include "mcom_db.h" 13 #include "secerr.h" 14 15 #include "keydbi.h" 16 #include "lgdb.h" 17 18 /* 19 * Record keys for keydb 20 */ 21 #define SALT_STRING "global-salt" 22 #define VERSION_STRING "Version" 23 #define KEYDB_PW_CHECK_STRING "password-check" 24 #define KEYDB_PW_CHECK_LEN 14 25 #define KEYDB_FAKE_PW_CHECK_STRING "fake-password-check" 26 #define KEYDB_FAKE_PW_CHECK_LEN 19 27 28 /* Size of the global salt for key database */ 29 #define SALT_LENGTH 16 30 31 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 32 33 const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = { 34 { SEC_ASN1_SEQUENCE, 35 0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) }, 36 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 37 offsetof(NSSLOWKEYEncryptedPrivateKeyInfo, algorithm), 38 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 39 { SEC_ASN1_OCTET_STRING, 40 offsetof(NSSLOWKEYEncryptedPrivateKeyInfo, encryptedData) }, 41 { 0 } 42 }; 43 44 const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = { 45 { SEC_ASN1_POINTER, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate } 46 }; 47 48 /* ====== Default key databse encryption algorithm ====== */ 49 static void 50 sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey) 51 { 52 if (dbkey && dbkey->arena) { 53 PORT_FreeArena(dbkey->arena, PR_FALSE); 54 } 55 } 56 57 static void 58 free_dbt(DBT *dbt) 59 { 60 if (dbt) { 61 PORT_Free(dbt->data); 62 PORT_Free(dbt); 63 } 64 65 return; 66 } 67 68 static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 69 unsigned int flags); 70 static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 71 unsigned int flags); 72 static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags); 73 static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags); 74 static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 75 unsigned int flags); 76 static void keydb_Close(NSSLOWKEYDBHandle *db); 77 78 /* 79 * format of key database entries for version 3 of database: 80 * byte offset field 81 * ----------- ----- 82 * 0 version 83 * 1 salt-len 84 * 2 nn-len 85 * 3.. salt-data 86 * ... nickname 87 * ... encrypted-key-data 88 */ 89 static DBT * 90 encode_dbkey(NSSLOWKEYDBKey *dbkey, unsigned char version) 91 { 92 DBT *bufitem = NULL; 93 unsigned char *buf; 94 int nnlen; 95 char *nn; 96 97 bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT)); 98 if (bufitem == NULL) { 99 goto loser; 100 } 101 102 if (dbkey->nickname) { 103 nn = dbkey->nickname; 104 nnlen = PORT_Strlen(nn) + 1; 105 } else { 106 nn = ""; 107 nnlen = 1; 108 } 109 110 /* compute the length of the record */ 111 /* 1 + 1 + 1 == version number header + salt length + nn len */ 112 bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1; 113 114 bufitem->data = (void *)PORT_ZAlloc(bufitem->size); 115 if (bufitem->data == NULL) { 116 goto loser; 117 } 118 119 buf = (unsigned char *)bufitem->data; 120 121 /* set version number */ 122 buf[0] = version; 123 124 /* set length of salt */ 125 PORT_Assert(dbkey->salt.len < 256); 126 buf[1] = dbkey->salt.len; 127 128 /* set length of nickname */ 129 PORT_Assert(nnlen < 256); 130 buf[2] = nnlen; 131 132 /* copy salt */ 133 if (dbkey->salt.len > 0) { 134 PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len); 135 } 136 137 /* copy nickname */ 138 PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen); 139 140 /* copy encrypted key */ 141 PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data, 142 dbkey->derPK.len); 143 144 return (bufitem); 145 146 loser: 147 if (bufitem) { 148 free_dbt(bufitem); 149 } 150 151 return (NULL); 152 } 153 154 static NSSLOWKEYDBKey * 155 decode_dbkey(DBT *bufitem, int expectedVersion) 156 { 157 NSSLOWKEYDBKey *dbkey; 158 PLArenaPool *arena = NULL; 159 unsigned char *buf; 160 int version; 161 int keyoff; 162 int nnlen; 163 int saltoff; 164 165 buf = (unsigned char *)bufitem->data; 166 167 version = buf[0]; 168 169 if (version != expectedVersion) { 170 goto loser; 171 } 172 173 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 174 if (arena == NULL) { 175 goto loser; 176 } 177 178 dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey)); 179 if (dbkey == NULL) { 180 goto loser; 181 } 182 183 dbkey->arena = arena; 184 dbkey->salt.data = NULL; 185 dbkey->derPK.data = NULL; 186 187 dbkey->salt.len = buf[1]; 188 dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len); 189 if (dbkey->salt.data == NULL) { 190 goto loser; 191 } 192 193 saltoff = 2; 194 keyoff = 2 + dbkey->salt.len; 195 196 if (expectedVersion >= 3) { 197 nnlen = buf[2]; 198 if (nnlen) { 199 dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1); 200 if (dbkey->nickname) { 201 PORT_Memcpy(dbkey->nickname, &buf[keyoff + 1], nnlen); 202 } 203 } 204 keyoff += (nnlen + 1); 205 saltoff = 3; 206 } 207 208 PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len); 209 210 dbkey->derPK.len = bufitem->size - keyoff; 211 dbkey->derPK.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->derPK.len); 212 if (dbkey->derPK.data == NULL) { 213 goto loser; 214 } 215 216 PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len); 217 218 return (dbkey); 219 220 loser: 221 222 if (arena) { 223 PORT_FreeArena(arena, PR_FALSE); 224 } 225 226 return (NULL); 227 } 228 229 static NSSLOWKEYDBKey * 230 get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index) 231 { 232 NSSLOWKEYDBKey *dbkey; 233 DBT entry; 234 int ret; 235 236 /* get it from the database */ 237 ret = keydb_Get(handle, index, &entry, 0); 238 if (ret) { 239 PORT_SetError(SEC_ERROR_BAD_DATABASE); 240 return NULL; 241 } 242 243 /* set up dbkey struct */ 244 245 dbkey = decode_dbkey(&entry, handle->version); 246 247 return (dbkey); 248 } 249 250 static SECStatus 251 put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update) 252 { 253 DBT *keydata = NULL; 254 int status; 255 256 keydata = encode_dbkey(dbkey, handle->version); 257 if (keydata == NULL) { 258 goto loser; 259 } 260 261 /* put it in the database */ 262 if (update) { 263 status = keydb_Put(handle, index, keydata, 0); 264 } else { 265 status = keydb_Put(handle, index, keydata, R_NOOVERWRITE); 266 } 267 268 if (status) { 269 goto loser; 270 } 271 272 /* sync the database */ 273 status = keydb_Sync(handle, 0); 274 if (status) { 275 goto loser; 276 } 277 278 free_dbt(keydata); 279 return (SECSuccess); 280 281 loser: 282 if (keydata) { 283 free_dbt(keydata); 284 } 285 286 return (SECFailure); 287 } 288 289 SECStatus 290 nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle, 291 SECStatus (*keyfunc)(DBT *k, DBT *d, void *pdata), 292 void *udata) 293 { 294 DBT data; 295 DBT key; 296 SECStatus status; 297 int ret; 298 299 if (handle == NULL) { 300 return (SECFailure); 301 } 302 303 ret = keydb_Seq(handle, &key, &data, R_FIRST); 304 if (ret) { 305 return (SECFailure); 306 } 307 308 do { 309 /* skip version record */ 310 if (data.size > 1) { 311 if (key.size == (sizeof(SALT_STRING) - 1)) { 312 if (PORT_Memcmp(key.data, SALT_STRING, key.size) == 0) { 313 continue; 314 } 315 } 316 317 /* skip password check */ 318 if (key.size == KEYDB_PW_CHECK_LEN) { 319 if (PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING, 320 KEYDB_PW_CHECK_LEN) == 0) { 321 continue; 322 } 323 } 324 325 status = (*keyfunc)(&key, &data, udata); 326 if (status != SECSuccess) { 327 return (status); 328 } 329 } 330 } while (keydb_Seq(handle, &key, &data, R_NEXT) == 0); 331 332 return (SECSuccess); 333 } 334 335 #ifdef notdef 336 typedef struct keyNode { 337 struct keyNode *next; 338 DBT key; 339 } keyNode; 340 341 typedef struct { 342 PLArenaPool *arena; 343 keyNode *head; 344 } keyList; 345 346 static SECStatus 347 sec_add_key_to_list(DBT *key, DBT *data, void *arg) 348 { 349 keyList *keylist; 350 keyNode *node; 351 void *keydata; 352 353 keylist = (keyList *)arg; 354 355 /* allocate the node struct */ 356 node = (keyNode *)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode)); 357 if (node == NULL) { 358 return (SECFailure); 359 } 360 361 /* allocate room for key data */ 362 keydata = PORT_ArenaZAlloc(keylist->arena, key->size); 363 if (keydata == NULL) { 364 return (SECFailure); 365 } 366 367 /* link node into list */ 368 node->next = keylist->head; 369 keylist->head = node; 370 371 /* copy key into node */ 372 PORT_Memcpy(keydata, key->data, key->size); 373 node->key.size = key->size; 374 node->key.data = keydata; 375 376 return (SECSuccess); 377 } 378 #endif 379 380 static SECItem * 381 decodeKeyDBGlobalSalt(DBT *saltData) 382 { 383 SECItem *saltitem; 384 385 saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); 386 if (saltitem == NULL) { 387 return (NULL); 388 } 389 390 saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size); 391 if (saltitem->data == NULL) { 392 PORT_Free(saltitem); 393 return (NULL); 394 } 395 396 saltitem->len = saltData->size; 397 PORT_Memcpy(saltitem->data, saltData->data, saltitem->len); 398 399 return (saltitem); 400 } 401 402 static SECItem * 403 GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle) 404 { 405 DBT saltKey; 406 DBT saltData; 407 int ret; 408 409 saltKey.data = SALT_STRING; 410 saltKey.size = sizeof(SALT_STRING) - 1; 411 412 ret = keydb_Get(handle, &saltKey, &saltData, 0); 413 if (ret) { 414 return (NULL); 415 } 416 417 return (decodeKeyDBGlobalSalt(&saltData)); 418 } 419 420 static SECStatus 421 StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle, SECItem *salt) 422 { 423 DBT saltKey; 424 DBT saltData; 425 int status; 426 427 saltKey.data = SALT_STRING; 428 saltKey.size = sizeof(SALT_STRING) - 1; 429 430 saltData.data = (void *)salt->data; 431 saltData.size = salt->len; 432 433 /* put global salt into the database now */ 434 status = keydb_Put(handle, &saltKey, &saltData, 0); 435 if (status) { 436 return (SECFailure); 437 } 438 439 return (SECSuccess); 440 } 441 442 static SECStatus 443 makeGlobalVersion(NSSLOWKEYDBHandle *handle) 444 { 445 unsigned char version; 446 DBT versionData; 447 DBT versionKey; 448 int status; 449 450 version = NSSLOWKEY_DB_FILE_VERSION; 451 versionData.data = &version; 452 versionData.size = 1; 453 versionKey.data = VERSION_STRING; 454 versionKey.size = sizeof(VERSION_STRING) - 1; 455 456 /* put version string into the database now */ 457 status = keydb_Put(handle, &versionKey, &versionData, 0); 458 if (status) { 459 return (SECFailure); 460 } 461 handle->version = version; 462 463 return (SECSuccess); 464 } 465 466 static SECStatus 467 makeGlobalSalt(NSSLOWKEYDBHandle *handle) 468 { 469 DBT saltKey; 470 DBT saltData; 471 unsigned char saltbuf[16]; 472 int status; 473 474 saltKey.data = SALT_STRING; 475 saltKey.size = sizeof(SALT_STRING) - 1; 476 477 saltData.data = (void *)saltbuf; 478 saltData.size = sizeof(saltbuf); 479 RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf)); 480 481 /* put global salt into the database now */ 482 status = keydb_Put(handle, &saltKey, &saltData, 0); 483 if (status) { 484 return (SECFailure); 485 } 486 487 return (SECSuccess); 488 } 489 490 static SECStatus 491 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg, 492 SECItem *encCheck); 493 494 static unsigned char 495 nsslowkey_version(NSSLOWKEYDBHandle *handle) 496 { 497 DBT versionKey; 498 DBT versionData; 499 int ret; 500 versionKey.data = VERSION_STRING; 501 versionKey.size = sizeof(VERSION_STRING) - 1; 502 503 if (handle->db == NULL) { 504 return 255; 505 } 506 507 /* lookup version string in database */ 508 ret = keydb_Get(handle, &versionKey, &versionData, 0); 509 510 /* error accessing the database */ 511 if (ret < 0) { 512 return 255; 513 } 514 515 if (ret >= 1) { 516 return 0; 517 } 518 return *((unsigned char *)versionData.data); 519 } 520 521 static PRBool 522 seckey_HasAServerKey(NSSLOWKEYDBHandle *handle) 523 { 524 DBT key; 525 DBT data; 526 int ret; 527 PRBool found = PR_FALSE; 528 529 ret = keydb_Seq(handle, &key, &data, R_FIRST); 530 if (ret) { 531 return PR_FALSE; 532 } 533 534 do { 535 /* skip version record */ 536 if (data.size > 1) { 537 /* skip salt */ 538 if (key.size == (sizeof(SALT_STRING) - 1)) { 539 if (PORT_Memcmp(key.data, SALT_STRING, key.size) == 0) { 540 continue; 541 } 542 } 543 /* skip pw check entry */ 544 if (key.size == KEYDB_PW_CHECK_LEN) { 545 if (PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING, 546 KEYDB_PW_CHECK_LEN) == 0) { 547 continue; 548 } 549 } 550 551 /* keys stored by nickname will have 0 as the last byte of the 552 * db key. Other keys must be stored by modulus. We will not 553 * update those because they are left over from a keygen that 554 * never resulted in a cert. 555 */ 556 if (((unsigned char *)key.data)[key.size - 1] != 0) { 557 continue; 558 } 559 560 if (PORT_Strcmp(key.data, "Server-Key") == 0) { 561 found = PR_TRUE; 562 break; 563 } 564 } 565 } while (keydb_Seq(handle, &key, &data, R_NEXT) == 0); 566 567 return found; 568 } 569 570 /* forward declare local create function */ 571 static NSSLOWKEYDBHandle *nsslowkey_NewHandle(DB *dbHandle); 572 573 /* 574 * currently updates key database from v2 to v3 575 */ 576 static SECStatus 577 nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) 578 { 579 SECStatus rv; 580 DBT checkKey; 581 DBT checkData; 582 DBT saltKey; 583 DBT saltData; 584 DBT key; 585 DBT data; 586 unsigned char version; 587 NSSLOWKEYDBKey *dbkey = NULL; 588 NSSLOWKEYDBHandle *update = NULL; 589 SECItem *oldSalt = NULL; 590 int ret; 591 SECItem checkitem; 592 593 if (handle->updatedb == NULL) { 594 return SECSuccess; 595 } 596 597 /* create a full DB Handle for our update so we 598 * can use the correct locks for the db primatives */ 599 update = nsslowkey_NewHandle(handle->updatedb); 600 if (update == NULL) { 601 return SECSuccess; 602 } 603 604 /* update has now inherited the database handle */ 605 handle->updatedb = NULL; 606 607 /* 608 * check the version record 609 */ 610 version = nsslowkey_version(update); 611 if (version != 2) { 612 goto done; 613 } 614 615 saltKey.data = SALT_STRING; 616 saltKey.size = sizeof(SALT_STRING) - 1; 617 618 ret = keydb_Get(update, &saltKey, &saltData, 0); 619 if (ret) { 620 /* no salt in old db, so it is corrupted */ 621 goto done; 622 } 623 624 oldSalt = decodeKeyDBGlobalSalt(&saltData); 625 if (oldSalt == NULL) { 626 /* bad salt in old db, so it is corrupted */ 627 goto done; 628 } 629 630 /* 631 * look for a pw check entry 632 */ 633 checkKey.data = KEYDB_PW_CHECK_STRING; 634 checkKey.size = KEYDB_PW_CHECK_LEN; 635 636 ret = keydb_Get(update, &checkKey, &checkData, 0); 637 if (ret) { 638 /* 639 * if we have a key, but no KEYDB_PW_CHECK_STRING, then this must 640 * be an old server database, and it does have a password associated 641 * with it. Put a fake entry in so we can identify this db when we do 642 * get the password for it. 643 */ 644 if (seckey_HasAServerKey(update)) { 645 DBT fcheckKey; 646 DBT fcheckData; 647 648 /* 649 * include a fake string 650 */ 651 fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING; 652 fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN; 653 fcheckData.data = "1"; 654 fcheckData.size = 1; 655 /* put global salt into the new database now */ 656 ret = keydb_Put(handle, &saltKey, &saltData, 0); 657 if (ret) { 658 goto done; 659 } 660 ret = keydb_Put(handle, &fcheckKey, &fcheckData, 0); 661 if (ret) { 662 goto done; 663 } 664 } else { 665 goto done; 666 } 667 } else { 668 /* put global salt into the new database now */ 669 ret = keydb_Put(handle, &saltKey, &saltData, 0); 670 if (ret) { 671 goto done; 672 } 673 674 dbkey = decode_dbkey(&checkData, 2); 675 if (dbkey == NULL) { 676 goto done; 677 } 678 checkitem = dbkey->derPK; 679 dbkey->derPK.data = NULL; 680 681 /* format the new pw check entry */ 682 rv = encodePWCheckEntry(NULL, &dbkey->derPK, SEC_OID_RC4, &checkitem); 683 if (rv != SECSuccess) { 684 goto done; 685 } 686 687 rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE); 688 if (rv != SECSuccess) { 689 goto done; 690 } 691 692 /* free the dbkey */ 693 sec_destroy_dbkey(dbkey); 694 dbkey = NULL; 695 } 696 697 /* now traverse the database */ 698 ret = keydb_Seq(update, &key, &data, R_FIRST); 699 if (ret) { 700 goto done; 701 } 702 703 do { 704 /* skip version record */ 705 if (data.size > 1) { 706 /* skip salt */ 707 if (key.size == (sizeof(SALT_STRING) - 1)) { 708 if (PORT_Memcmp(key.data, SALT_STRING, key.size) == 0) { 709 continue; 710 } 711 } 712 /* skip pw check entry */ 713 if (key.size == checkKey.size) { 714 if (PORT_Memcmp(key.data, checkKey.data, key.size) == 0) { 715 continue; 716 } 717 } 718 719 /* keys stored by nickname will have 0 as the last byte of the 720 * db key. Other keys must be stored by modulus. We will not 721 * update those because they are left over from a keygen that 722 * never resulted in a cert. 723 */ 724 if (((unsigned char *)key.data)[key.size - 1] != 0) { 725 continue; 726 } 727 728 dbkey = decode_dbkey(&data, 2); 729 if (dbkey == NULL) { 730 continue; 731 } 732 733 /* This puts the key into the new database with the same 734 * index (nickname) that it had before. The second pass 735 * of the update will have the password. It will decrypt 736 * and re-encrypt the entries using a new algorithm. 737 */ 738 dbkey->nickname = (char *)key.data; 739 rv = put_dbkey(handle, &key, dbkey, PR_FALSE); 740 dbkey->nickname = NULL; 741 742 sec_destroy_dbkey(dbkey); 743 } 744 } while (keydb_Seq(update, &key, &data, R_NEXT) == 0); 745 746 dbkey = NULL; 747 748 done: 749 /* sync the database */ 750 ret = keydb_Sync(handle, 0); 751 752 nsslowkey_CloseKeyDB(update); 753 754 if (oldSalt) { 755 SECITEM_FreeItem(oldSalt, PR_TRUE); 756 } 757 758 if (dbkey) { 759 sec_destroy_dbkey(dbkey); 760 } 761 762 return (SECSuccess); 763 } 764 765 static SECStatus 766 openNewDB(const char *appName, const char *prefix, const char *dbname, 767 NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg) 768 { 769 SECStatus rv = SECFailure; 770 int status = RDB_FAIL; 771 char *updname = NULL; 772 DB *updatedb = NULL; 773 PRBool updated = PR_FALSE; 774 int ret; 775 776 if (appName) { 777 handle->db = rdbopen(appName, prefix, "key", NO_CREATE, &status); 778 } else { 779 handle->db = dbopen(dbname, NO_CREATE, 0600, DB_HASH, 0); 780 } 781 /* if create fails then we lose */ 782 if (handle->db == NULL) { 783 return (status == RDB_RETRY) ? SECWouldBlock : SECFailure; 784 } 785 786 /* force a transactional read, which will verify that one and only one 787 * process attempts the update. */ 788 if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION) { 789 /* someone else has already updated the database for us */ 790 db_InitComplete(handle->db); 791 return SECSuccess; 792 } 793 794 /* 795 * if we are creating a multiaccess database, see if there is a 796 * local database we can update from. 797 */ 798 if (appName) { 799 NSSLOWKEYDBHandle *updateHandle; 800 updatedb = dbopen(dbname, NO_RDONLY, 0600, DB_HASH, 0); 801 if (!updatedb) { 802 goto noupdate; 803 } 804 805 /* nsslowkey_version needs a full handle because it calls 806 * the kdb_Get() function, which needs to lock. 807 */ 808 updateHandle = nsslowkey_NewHandle(updatedb); 809 if (!updateHandle) { 810 updatedb->close(updatedb); 811 goto noupdate; 812 } 813 814 handle->version = nsslowkey_version(updateHandle); 815 if (handle->version != NSSLOWKEY_DB_FILE_VERSION) { 816 nsslowkey_CloseKeyDB(updateHandle); 817 goto noupdate; 818 } 819 820 /* copy the new DB from the old one */ 821 db_Copy(handle->db, updatedb); 822 nsslowkey_CloseKeyDB(updateHandle); 823 db_InitComplete(handle->db); 824 return SECSuccess; 825 } 826 noupdate: 827 828 /* update the version number */ 829 rv = makeGlobalVersion(handle); 830 if (rv != SECSuccess) { 831 goto loser; 832 } 833 834 /* 835 * try to update from v2 db 836 */ 837 updname = (*namecb)(cbarg, 2); 838 if (updname != NULL) { 839 handle->updatedb = dbopen(updname, NO_RDONLY, 0600, DB_HASH, 0); 840 PORT_Free(updname); 841 842 if (handle->updatedb) { 843 /* 844 * Try to update the db using a null password. If the db 845 * doesn't have a password, then this will work. If it does 846 * have a password, then this will fail and we will do the 847 * update later 848 */ 849 rv = nsslowkey_UpdateKeyDBPass1(handle); 850 if (rv == SECSuccess) { 851 updated = PR_TRUE; 852 } 853 } 854 } 855 856 /* we are using the old salt if we updated from an old db */ 857 if (!updated) { 858 rv = makeGlobalSalt(handle); 859 if (rv != SECSuccess) { 860 goto loser; 861 } 862 } 863 864 /* sync the database */ 865 ret = keydb_Sync(handle, 0); 866 if (ret) { 867 rv = SECFailure; 868 goto loser; 869 } 870 rv = SECSuccess; 871 872 loser: 873 db_InitComplete(handle->db); 874 return rv; 875 } 876 877 static DB * 878 openOldDB(const char *appName, const char *prefix, const char *dbname, 879 PRBool openflags) 880 { 881 DB *db = NULL; 882 883 if (appName) { 884 db = rdbopen(appName, prefix, "key", openflags, NULL); 885 } else { 886 db = dbopen(dbname, openflags, 0600, DB_HASH, 0); 887 } 888 889 return db; 890 } 891 892 /* check for correct version number */ 893 static PRBool 894 verifyVersion(NSSLOWKEYDBHandle *handle) 895 { 896 int version = nsslowkey_version(handle); 897 898 handle->version = version; 899 if (version != NSSLOWKEY_DB_FILE_VERSION) { 900 if (handle->db) { 901 keydb_Close(handle); 902 handle->db = NULL; 903 } 904 } 905 return handle->db != NULL; 906 } 907 908 static NSSLOWKEYDBHandle * 909 nsslowkey_NewHandle(DB *dbHandle) 910 { 911 NSSLOWKEYDBHandle *handle; 912 handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc(sizeof(NSSLOWKEYDBHandle)); 913 if (handle == NULL) { 914 PORT_SetError(SEC_ERROR_NO_MEMORY); 915 return NULL; 916 } 917 918 handle->appname = NULL; 919 handle->dbname = NULL; 920 handle->global_salt = NULL; 921 handle->updatedb = NULL; 922 handle->db = dbHandle; 923 handle->ref = 1; 924 handle->lock = PZ_NewLock(nssILockKeyDB); 925 926 return handle; 927 } 928 929 NSSLOWKEYDBHandle * 930 nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, 931 NSSLOWKEYDBNameFunc namecb, void *cbarg) 932 { 933 NSSLOWKEYDBHandle *handle = NULL; 934 SECStatus rv; 935 int openflags; 936 char *dbname = NULL; 937 938 handle = nsslowkey_NewHandle(NULL); 939 940 openflags = readOnly ? NO_RDONLY : NO_RDWR; 941 942 dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION); 943 if (dbname == NULL) { 944 goto loser; 945 } 946 handle->appname = appName ? PORT_Strdup(appName) : NULL; 947 handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) : (prefix ? PORT_Strdup(prefix) : NULL); 948 handle->readOnly = readOnly; 949 950 handle->db = openOldDB(appName, prefix, dbname, openflags); 951 if (handle->db) { 952 verifyVersion(handle); 953 if (handle->version == 255) { 954 goto loser; 955 } 956 } 957 958 /* if first open fails, try to create a new DB */ 959 if (handle->db == NULL) { 960 if (readOnly) { 961 goto loser; 962 } 963 964 rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg); 965 /* two processes started to initialize the database at the same time. 966 * The multiprocess code blocked the second one, then had it retry to 967 * see if it can just open the database normally */ 968 if (rv == SECWouldBlock) { 969 handle->db = openOldDB(appName, prefix, dbname, openflags); 970 verifyVersion(handle); 971 if (handle->db == NULL) { 972 goto loser; 973 } 974 } else if (rv != SECSuccess) { 975 goto loser; 976 } 977 } 978 979 handle->global_salt = GetKeyDBGlobalSalt(handle); 980 if (dbname) 981 PORT_Free(dbname); 982 return handle; 983 984 loser: 985 986 if (dbname) 987 PORT_Free(dbname); 988 PORT_SetError(SEC_ERROR_BAD_DATABASE); 989 nsslowkey_CloseKeyDB(handle); 990 return NULL; 991 } 992 993 /* 994 * Close the database 995 */ 996 void 997 nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle) 998 { 999 if (handle != NULL) { 1000 if (handle->db != NULL) { 1001 keydb_Close(handle); 1002 } 1003 if (handle->updatedb) { 1004 handle->updatedb->close(handle->updatedb); 1005 } 1006 if (handle->dbname) 1007 PORT_Free(handle->dbname); 1008 if (handle->appname) 1009 PORT_Free(handle->appname); 1010 if (handle->global_salt) { 1011 SECITEM_FreeItem(handle->global_salt, PR_TRUE); 1012 } 1013 if (handle->lock != NULL) { 1014 SKIP_AFTER_FORK(PZ_DestroyLock(handle->lock)); 1015 } 1016 1017 PORT_Free(handle); 1018 } 1019 } 1020 1021 /* Get the key database version */ 1022 int 1023 nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle) 1024 { 1025 PORT_Assert(handle != NULL); 1026 1027 return handle->version; 1028 } 1029 1030 /* 1031 * Delete a private key that was stored in the database 1032 */ 1033 SECStatus 1034 nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, const SECItem *pubkey) 1035 { 1036 DBT namekey; 1037 int ret; 1038 1039 if (handle == NULL) { 1040 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1041 return (SECFailure); 1042 } 1043 1044 /* set up db key and data */ 1045 namekey.data = pubkey->data; 1046 namekey.size = pubkey->len; 1047 1048 /* delete it from the database */ 1049 ret = keydb_Del(handle, &namekey, 0); 1050 if (ret) { 1051 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1052 return (SECFailure); 1053 } 1054 1055 /* sync the database */ 1056 ret = keydb_Sync(handle, 0); 1057 if (ret) { 1058 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1059 return (SECFailure); 1060 } 1061 1062 return (SECSuccess); 1063 } 1064 1065 /* 1066 * Store a key in the database, indexed by its public key modulus.(value!) 1067 */ 1068 SECStatus 1069 nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle, 1070 NSSLOWKEYPrivateKey *privkey, 1071 SECItem *pubKeyData, 1072 char *nickname, 1073 SDB *sdb) 1074 { 1075 return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 1076 nickname, sdb, PR_FALSE); 1077 } 1078 1079 SECStatus 1080 nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle, 1081 NSSLOWKEYPrivateKey *privkey, 1082 SECItem *pubKeyData, 1083 char *nickname, 1084 SDB *sdb) 1085 { 1086 return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 1087 nickname, sdb, PR_TRUE); 1088 } 1089 1090 /* see if the symetric CKA_ID already Exists. 1091 */ 1092 PRBool 1093 nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id) 1094 { 1095 DBT namekey; 1096 DBT dummy; 1097 int status; 1098 1099 namekey.data = (char *)id->data; 1100 namekey.size = id->len; 1101 status = keydb_Get(handle, &namekey, &dummy, 0); 1102 if (status) { 1103 return PR_FALSE; 1104 } 1105 1106 return PR_TRUE; 1107 } 1108 1109 /* see if the public key for this cert is in the database filed 1110 * by modulus 1111 */ 1112 PRBool 1113 nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert) 1114 { 1115 NSSLOWKEYPublicKey *pubkey = NULL; 1116 DBT namekey; 1117 DBT dummy; 1118 int status; 1119 1120 /* get cert's public key */ 1121 pubkey = nsslowcert_ExtractPublicKey(cert); 1122 if (pubkey == NULL) { 1123 return PR_FALSE; 1124 } 1125 1126 /* TNH - make key from NSSLOWKEYPublicKey */ 1127 switch (pubkey->keyType) { 1128 case NSSLOWKEYRSAKey: 1129 namekey.data = pubkey->u.rsa.modulus.data; 1130 namekey.size = pubkey->u.rsa.modulus.len; 1131 break; 1132 case NSSLOWKEYDSAKey: 1133 namekey.data = pubkey->u.dsa.publicValue.data; 1134 namekey.size = pubkey->u.dsa.publicValue.len; 1135 break; 1136 case NSSLOWKEYDHKey: 1137 namekey.data = pubkey->u.dh.publicValue.data; 1138 namekey.size = pubkey->u.dh.publicValue.len; 1139 break; 1140 case NSSLOWKEYECKey: 1141 namekey.data = pubkey->u.ec.publicValue.data; 1142 namekey.size = pubkey->u.ec.publicValue.len; 1143 break; 1144 default: 1145 /* XXX We don't do Fortezza or DH yet. */ 1146 return PR_FALSE; 1147 } 1148 1149 if (handle->version != 3) { 1150 unsigned char buf[SHA1_LENGTH]; 1151 SHA1_HashBuf(buf, namekey.data, namekey.size); 1152 /* NOTE: don't use pubkey after this! it's now thrashed */ 1153 PORT_Memcpy(namekey.data, buf, sizeof(buf)); 1154 namekey.size = sizeof(buf); 1155 } 1156 1157 status = keydb_Get(handle, &namekey, &dummy, 0); 1158 /* some databases have the key stored as a signed value */ 1159 if (status) { 1160 unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size + 1); 1161 if (buf) { 1162 PORT_Memcpy(&buf[1], namekey.data, namekey.size); 1163 buf[0] = 0; 1164 namekey.data = buf; 1165 namekey.size++; 1166 status = keydb_Get(handle, &namekey, &dummy, 0); 1167 PORT_Free(buf); 1168 } 1169 } 1170 lg_nsslowkey_DestroyPublicKey(pubkey); 1171 if (status) { 1172 return PR_FALSE; 1173 } 1174 1175 return PR_TRUE; 1176 } 1177 1178 typedef struct NSSLowPasswordDataParamStr { 1179 SECItem salt; 1180 SECItem iter; 1181 } NSSLowPasswordDataParam; 1182 1183 static const SEC_ASN1Template NSSLOWPasswordParamTemplate[] = { 1184 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLowPasswordDataParam) }, 1185 { SEC_ASN1_OCTET_STRING, offsetof(NSSLowPasswordDataParam, salt) }, 1186 { SEC_ASN1_INTEGER, offsetof(NSSLowPasswordDataParam, iter) }, 1187 { 0 } 1188 }; 1189 struct LGEncryptedDataInfoStr { 1190 SECAlgorithmID algorithm; 1191 SECItem encryptedData; 1192 }; 1193 typedef struct LGEncryptedDataInfoStr LGEncryptedDataInfo; 1194 1195 const SEC_ASN1Template lg_EncryptedDataInfoTemplate[] = { 1196 { SEC_ASN1_SEQUENCE, 1197 0, NULL, sizeof(LGEncryptedDataInfo) }, 1198 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 1199 offsetof(LGEncryptedDataInfo, algorithm), 1200 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1201 { SEC_ASN1_OCTET_STRING, 1202 offsetof(LGEncryptedDataInfo, encryptedData) }, 1203 { 0 } 1204 }; 1205 1206 static SECItem * 1207 nsslowkey_EncodePW(SECOidTag alg, const SECItem *salt, SECItem *data) 1208 { 1209 NSSLowPasswordDataParam param; 1210 LGEncryptedDataInfo edi; 1211 PLArenaPool *arena; 1212 unsigned char one = 1; 1213 SECItem *epw = NULL; 1214 SECItem *encParam; 1215 int iterLen = 0; 1216 int saltLen; 1217 SECStatus rv; 1218 1219 param.salt = *salt; 1220 param.iter.type = siBuffer; /* encode as signed integer */ 1221 param.iter.data = &one; 1222 param.iter.len = 1; 1223 edi.encryptedData = *data; 1224 1225 iterLen = salt->len > 1 ? salt->data[salt->len - 1] : 2; 1226 saltLen = (salt->len - iterLen) - 1; 1227 /* if the resulting saltLen is a sha hash length, then assume that 1228 * the iteration count is tacked on the end of the buffer */ 1229 if ((saltLen == SHA1_LENGTH) || (saltLen == SHA256_LENGTH) || (saltLen == SHA384_LENGTH) || (saltLen == SHA224_LENGTH) || 1230 (saltLen == SHA512_LENGTH)) { 1231 param.iter.data = &salt->data[saltLen]; 1232 param.iter.len = iterLen; 1233 param.salt.len = saltLen; 1234 } 1235 1236 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1237 if (arena == NULL) { 1238 return NULL; 1239 } 1240 1241 encParam = SEC_ASN1EncodeItem(arena, NULL, ¶m, 1242 NSSLOWPasswordParamTemplate); 1243 if (encParam == NULL) { 1244 goto loser; 1245 } 1246 rv = SECOID_SetAlgorithmID(arena, &edi.algorithm, alg, encParam); 1247 if (rv != SECSuccess) { 1248 goto loser; 1249 } 1250 epw = SEC_ASN1EncodeItem(NULL, NULL, &edi, lg_EncryptedDataInfoTemplate); 1251 1252 loser: 1253 PORT_FreeArena(arena, PR_FALSE); 1254 return epw; 1255 } 1256 1257 static SECItem * 1258 nsslowkey_DecodePW(const SECItem *derData, SECOidTag *alg, SECItem *salt) 1259 { 1260 NSSLowPasswordDataParam param; 1261 LGEncryptedDataInfo edi; 1262 PLArenaPool *arena; 1263 SECItem *pwe = NULL; 1264 SECStatus rv; 1265 1266 salt->data = NULL; 1267 param.iter.type = siBuffer; /* decode as signed integer */ 1268 1269 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1270 if (arena == NULL) { 1271 return NULL; 1272 } 1273 1274 rv = SEC_QuickDERDecodeItem(arena, &edi, lg_EncryptedDataInfoTemplate, 1275 derData); 1276 if (rv != SECSuccess) { 1277 goto loser; 1278 } 1279 *alg = SECOID_GetAlgorithmTag(&edi.algorithm); 1280 rv = SEC_QuickDERDecodeItem(arena, ¶m, NSSLOWPasswordParamTemplate, 1281 &edi.algorithm.parameters); 1282 if (rv != SECSuccess) { 1283 goto loser; 1284 } 1285 /* if the iteration count isn't one, tack it at the end of the salt */ 1286 if (!((param.iter.len == 1) && (param.iter.data[0] == 1))) { 1287 int total_len = param.salt.len + param.iter.len + 1; 1288 salt->data = PORT_Alloc(total_len); 1289 if (salt->data == NULL) { 1290 goto loser; 1291 } 1292 PORT_Memcpy(salt->data, param.salt.data, param.salt.len); 1293 PORT_Memcpy(&salt->data[param.salt.len], param.iter.data, 1294 param.iter.len); 1295 salt->data[total_len - 1] = param.iter.len; 1296 salt->len = total_len; 1297 } else { 1298 rv = SECITEM_CopyItem(NULL, salt, ¶m.salt); 1299 if (rv != SECSuccess) { 1300 goto loser; 1301 } 1302 } 1303 pwe = SECITEM_DupItem(&edi.encryptedData); 1304 1305 loser: 1306 if (!pwe && salt->data) { 1307 PORT_Free(salt->data); 1308 salt->data = NULL; 1309 } 1310 PORT_FreeArena(arena, PR_FALSE); 1311 return pwe; 1312 } 1313 1314 /* 1315 * check to see if the user has a password 1316 */ 1317 static SECStatus 1318 nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle, NSSLOWKEYPasswordEntry *entry) 1319 { 1320 DBT checkkey; /*, checkdata; */ 1321 NSSLOWKEYDBKey *dbkey = NULL; 1322 SECItem *global_salt = NULL; 1323 SECItem *item = NULL; 1324 SECItem entryData, oid; 1325 SECItem none = { siBuffer, NULL, 0 }; 1326 SECStatus rv = SECFailure; 1327 SECOidTag algorithm; 1328 1329 if (handle == NULL) { 1330 /* PORT_SetError */ 1331 return (SECFailure); 1332 } 1333 1334 global_salt = GetKeyDBGlobalSalt(handle); 1335 if (!global_salt) { 1336 global_salt = &none; 1337 } 1338 if (global_salt->len > sizeof(entry->data)) { 1339 /* PORT_SetError */ 1340 goto loser; 1341 } 1342 1343 PORT_Memcpy(entry->data, global_salt->data, global_salt->len); 1344 entry->salt.data = entry->data; 1345 entry->salt.len = global_salt->len; 1346 entry->value.data = &entry->data[entry->salt.len]; 1347 1348 checkkey.data = KEYDB_PW_CHECK_STRING; 1349 checkkey.size = KEYDB_PW_CHECK_LEN; 1350 dbkey = get_dbkey(handle, &checkkey); 1351 if (dbkey == NULL) { 1352 /* handle 'FAKE' check here */ 1353 goto loser; 1354 } 1355 1356 oid.len = dbkey->derPK.data[0]; 1357 oid.data = &dbkey->derPK.data[1]; 1358 1359 if (dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 + oid.len)) { 1360 goto loser; 1361 } 1362 algorithm = SECOID_FindOIDTag(&oid); 1363 entryData.type = siBuffer; 1364 entryData.len = dbkey->derPK.len - (oid.len + 1); 1365 entryData.data = &dbkey->derPK.data[oid.len + 1]; 1366 1367 item = nsslowkey_EncodePW(algorithm, &dbkey->salt, &entryData); 1368 if (!item || (item->len + entry->salt.len) > sizeof(entry->data)) { 1369 goto loser; 1370 } 1371 PORT_Memcpy(entry->value.data, item->data, item->len); 1372 entry->value.len = item->len; 1373 rv = SECSuccess; 1374 1375 loser: 1376 if (item) { 1377 SECITEM_FreeItem(item, PR_TRUE); 1378 } 1379 if (dbkey) { 1380 sec_destroy_dbkey(dbkey); 1381 } 1382 if (global_salt != &none) { 1383 SECITEM_FreeItem(global_salt, PR_TRUE); 1384 } 1385 return rv; 1386 } 1387 1388 /* 1389 * check to see if the user has a password 1390 */ 1391 static SECStatus 1392 nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle, NSSLOWKEYPasswordEntry *entry) 1393 { 1394 DBT checkkey; 1395 NSSLOWKEYDBKey *dbkey = NULL; 1396 SECItem *item = NULL; 1397 SECItem salt; 1398 SECOidTag algid = SEC_OID_UNKNOWN; 1399 SECStatus rv = SECFailure; 1400 PLArenaPool *arena; 1401 int ret; 1402 1403 if (handle == NULL) { 1404 /* PORT_SetError */ 1405 return (SECFailure); 1406 } 1407 1408 checkkey.data = KEYDB_PW_CHECK_STRING; 1409 checkkey.size = KEYDB_PW_CHECK_LEN; 1410 1411 salt.data = NULL; 1412 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1413 if (arena == NULL) { 1414 return SECFailure; 1415 } 1416 1417 item = nsslowkey_DecodePW(&entry->value, &algid, &salt); 1418 if (item == NULL) { 1419 goto loser; 1420 } 1421 1422 dbkey = PORT_ArenaZNew(arena, NSSLOWKEYDBKey); 1423 if (dbkey == NULL) { 1424 goto loser; 1425 } 1426 1427 dbkey->arena = arena; 1428 1429 rv = SECITEM_CopyItem(arena, &dbkey->salt, &salt); 1430 if (rv != SECSuccess) { 1431 goto loser; 1432 } 1433 1434 rv = encodePWCheckEntry(arena, &dbkey->derPK, algid, item); 1435 if (rv != SECSuccess) { 1436 goto loser; 1437 } 1438 1439 rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE); 1440 if (rv != SECSuccess) { 1441 goto loser; 1442 } 1443 1444 if (handle->global_salt) { 1445 SECITEM_FreeItem(handle->global_salt, PR_TRUE); 1446 handle->global_salt = NULL; 1447 } 1448 rv = StoreKeyDBGlobalSalt(handle, &entry->salt); 1449 if (rv != SECSuccess) { 1450 goto loser; 1451 } 1452 ret = keydb_Sync(handle, 0); 1453 if (ret) { 1454 rv = SECFailure; 1455 goto loser; 1456 } 1457 handle->global_salt = GetKeyDBGlobalSalt(handle); 1458 1459 loser: 1460 if (item) { 1461 SECITEM_FreeItem(item, PR_TRUE); 1462 } 1463 if (arena) { 1464 PORT_FreeArena(arena, PR_TRUE); 1465 } 1466 if (salt.data) { 1467 PORT_Free(salt.data); 1468 } 1469 return rv; 1470 } 1471 1472 #ifdef EC_DEBUG 1473 #define SEC_PRINT(str1, str2, num, sitem) \ 1474 printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \ 1475 str1, str2, num, sitem->len); \ 1476 for (i = 0; i < sitem->len; i++) { \ 1477 printf("%02x:", sitem->data[i]); \ 1478 } \ 1479 printf("\n") 1480 #else 1481 #define SEC_PRINT(a, b, c, d) 1482 #endif /* EC_DEBUG */ 1483 1484 SECStatus 1485 seckey_encrypt_private_key(PLArenaPool *permarena, NSSLOWKEYPrivateKey *pk, 1486 SDB *sdbpw, SECItem *result) 1487 { 1488 NSSLOWKEYPrivateKeyInfo *pki = NULL; 1489 SECStatus rv = SECFailure; 1490 PLArenaPool *temparena = NULL; 1491 SECItem *der_item = NULL; 1492 SECItem *cipherText = NULL; 1493 SECItem *dummy = NULL; 1494 #ifdef EC_DEBUG 1495 SECItem *fordebug = NULL; 1496 #endif 1497 int savelen; 1498 1499 temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1500 if (temparena == NULL) 1501 goto loser; 1502 1503 /* allocate structures */ 1504 pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 1505 sizeof(NSSLOWKEYPrivateKeyInfo)); 1506 der_item = (SECItem *)PORT_ArenaZAlloc(temparena, sizeof(SECItem)); 1507 if ((pki == NULL) || (der_item == NULL)) 1508 goto loser; 1509 1510 /* setup private key info */ 1511 dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version), 1512 NSSLOWKEY_PRIVATE_KEY_INFO_VERSION); 1513 if (dummy == NULL) 1514 goto loser; 1515 1516 /* Encode the key, and set the algorithm (with params) */ 1517 switch (pk->keyType) { 1518 case NSSLOWKEYRSAKey: 1519 lg_prepare_low_rsa_priv_key_for_asn1(pk); 1520 dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 1521 lg_nsslowkey_RSAPrivateKeyTemplate); 1522 if (dummy == NULL) { 1523 rv = SECFailure; 1524 goto loser; 1525 } 1526 1527 rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 1528 SEC_OID_PKCS1_RSA_ENCRYPTION, 0); 1529 if (rv == SECFailure) { 1530 goto loser; 1531 } 1532 1533 break; 1534 case NSSLOWKEYDSAKey: 1535 lg_prepare_low_dsa_priv_key_for_asn1(pk); 1536 dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 1537 lg_nsslowkey_DSAPrivateKeyTemplate); 1538 if (dummy == NULL) { 1539 rv = SECFailure; 1540 goto loser; 1541 } 1542 1543 lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params); 1544 dummy = SEC_ASN1EncodeItem(temparena, NULL, &pk->u.dsa.params, 1545 lg_nsslowkey_PQGParamsTemplate); 1546 if (dummy == NULL) { 1547 rv = SECFailure; 1548 goto loser; 1549 } 1550 1551 rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 1552 SEC_OID_ANSIX9_DSA_SIGNATURE, dummy); 1553 if (rv == SECFailure) { 1554 goto loser; 1555 } 1556 1557 break; 1558 case NSSLOWKEYDHKey: 1559 lg_prepare_low_dh_priv_key_for_asn1(pk); 1560 dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 1561 lg_nsslowkey_DHPrivateKeyTemplate); 1562 if (dummy == NULL) { 1563 rv = SECFailure; 1564 goto loser; 1565 } 1566 1567 rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 1568 SEC_OID_X942_DIFFIE_HELMAN_KEY, dummy); 1569 if (rv == SECFailure) { 1570 goto loser; 1571 } 1572 break; 1573 case NSSLOWKEYECKey: 1574 lg_prepare_low_ec_priv_key_for_asn1(pk); 1575 /* Public value is encoded as a bit string so adjust length 1576 * to be in bits before ASN encoding and readjust 1577 * immediately after. 1578 * 1579 * Since the SECG specification recommends not including the 1580 * parameters as part of ECPrivateKey, we zero out the curveOID 1581 * length before encoding and restore it later. 1582 */ 1583 pk->u.ec.publicValue.len <<= 3; 1584 savelen = pk->u.ec.ecParams.curveOID.len; 1585 pk->u.ec.ecParams.curveOID.len = 0; 1586 dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 1587 lg_nsslowkey_ECPrivateKeyTemplate); 1588 pk->u.ec.ecParams.curveOID.len = savelen; 1589 pk->u.ec.publicValue.len >>= 3; 1590 1591 if (dummy == NULL) { 1592 rv = SECFailure; 1593 goto loser; 1594 } 1595 1596 dummy = &pk->u.ec.ecParams.DEREncoding; 1597 1598 /* At this point dummy should contain the encoded params */ 1599 rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 1600 SEC_OID_ANSIX962_EC_PUBLIC_KEY, dummy); 1601 1602 if (rv == SECFailure) { 1603 goto loser; 1604 } 1605 1606 #ifdef EC_DEBUG 1607 fordebug = &(pki->privateKey); 1608 SEC_PRINT("seckey_encrypt_private_key()", "PrivateKey", 1609 pk->keyType, fordebug); 1610 #endif 1611 1612 break; 1613 default: 1614 /* We don't support DH or Fortezza private keys yet */ 1615 PORT_Assert(PR_FALSE); 1616 break; 1617 } 1618 1619 /* setup encrypted private key info */ 1620 dummy = SEC_ASN1EncodeItem(temparena, der_item, pki, 1621 lg_nsslowkey_PrivateKeyInfoTemplate); 1622 1623 SEC_PRINT("seckey_encrypt_private_key()", "PrivateKeyInfo", 1624 pk->keyType, der_item); 1625 1626 if (dummy == NULL) { 1627 rv = SECFailure; 1628 goto loser; 1629 } 1630 1631 rv = lg_util_encrypt(temparena, sdbpw, dummy, &cipherText); 1632 if (rv != SECSuccess) { 1633 goto loser; 1634 } 1635 1636 rv = SECITEM_CopyItem(permarena, result, cipherText); 1637 1638 loser: 1639 1640 if (temparena != NULL) 1641 PORT_FreeArena(temparena, PR_TRUE); 1642 1643 return rv; 1644 } 1645 1646 static SECStatus 1647 seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SDB *sdbpw, 1648 NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update) 1649 { 1650 NSSLOWKEYDBKey *dbkey = NULL; 1651 PLArenaPool *arena = NULL; 1652 SECStatus rv = SECFailure; 1653 1654 if ((keydb == NULL) || (index == NULL) || (sdbpw == NULL) || 1655 (pk == NULL)) 1656 return SECFailure; 1657 1658 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1659 if (arena == NULL) 1660 return SECFailure; 1661 1662 dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey)); 1663 if (dbkey == NULL) 1664 goto loser; 1665 dbkey->arena = arena; 1666 dbkey->nickname = nickname; 1667 1668 rv = seckey_encrypt_private_key(arena, pk, sdbpw, &dbkey->derPK); 1669 if (rv != SECSuccess) 1670 goto loser; 1671 1672 rv = put_dbkey(keydb, index, dbkey, update); 1673 1674 /* let success fall through */ 1675 loser: 1676 if (arena != NULL) 1677 PORT_FreeArena(arena, PR_TRUE); 1678 1679 return rv; 1680 } 1681 1682 /* 1683 * Store a key in the database, indexed by its public key modulus. 1684 * Note that the nickname is optional. It was only used by keyutil. 1685 */ 1686 SECStatus 1687 nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, 1688 NSSLOWKEYPrivateKey *privkey, 1689 SECItem *pubKeyData, 1690 char *nickname, 1691 SDB *sdbpw, 1692 PRBool update) 1693 { 1694 DBT namekey; 1695 SECStatus rv; 1696 1697 if (handle == NULL) { 1698 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1699 return (SECFailure); 1700 } 1701 1702 /* set up db key and data */ 1703 namekey.data = pubKeyData->data; 1704 namekey.size = pubKeyData->len; 1705 1706 /* encrypt the private key */ 1707 rv = seckey_put_private_key(handle, &namekey, sdbpw, privkey, nickname, 1708 update); 1709 1710 return (rv); 1711 } 1712 1713 static NSSLOWKEYPrivateKey * 1714 seckey_decrypt_private_key(SECItem *epki, 1715 SDB *sdbpw) 1716 { 1717 NSSLOWKEYPrivateKey *pk = NULL; 1718 NSSLOWKEYPrivateKeyInfo *pki = NULL; 1719 SECStatus rv = SECFailure; 1720 PLArenaPool *temparena = NULL, *permarena = NULL; 1721 SECItem *dest = NULL; 1722 #ifdef EC_DEBUG 1723 SECItem *fordebug = NULL; 1724 #endif 1725 1726 if ((epki == NULL) || (sdbpw == NULL)) 1727 goto loser; 1728 1729 temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1730 permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1731 if ((temparena == NULL) || (permarena == NULL)) 1732 goto loser; 1733 1734 /* allocate temporary items */ 1735 pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 1736 sizeof(NSSLOWKEYPrivateKeyInfo)); 1737 1738 /* allocate permanent arena items */ 1739 pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(permarena, 1740 sizeof(NSSLOWKEYPrivateKey)); 1741 1742 if ((pk == NULL) || (pki == NULL)) 1743 goto loser; 1744 1745 pk->arena = permarena; 1746 1747 rv = lg_util_decrypt(sdbpw, epki, &dest); 1748 if (rv != SECSuccess) { 1749 goto loser; 1750 } 1751 1752 if (dest != NULL) { 1753 SECItem newPrivateKey; 1754 SECItem newAlgParms; 1755 1756 SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1, 1757 dest); 1758 1759 rv = SEC_QuickDERDecodeItem(temparena, pki, 1760 lg_nsslowkey_PrivateKeyInfoTemplate, dest); 1761 if (rv == SECSuccess) { 1762 switch (SECOID_GetAlgorithmTag(&pki->algorithm)) { 1763 case SEC_OID_X500_RSA_ENCRYPTION: 1764 case SEC_OID_PKCS1_RSA_ENCRYPTION: 1765 pk->keyType = NSSLOWKEYRSAKey; 1766 lg_prepare_low_rsa_priv_key_for_asn1(pk); 1767 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey, 1768 &pki->privateKey)) 1769 break; 1770 rv = SEC_QuickDERDecodeItem(permarena, pk, 1771 lg_nsslowkey_RSAPrivateKeyTemplate, 1772 &newPrivateKey); 1773 if (rv == SECSuccess) { 1774 break; 1775 } 1776 /* Try decoding with the alternative template, but only allow 1777 * a zero-length modulus for a secret key object. 1778 * See bug 715073. 1779 */ 1780 rv = SEC_QuickDERDecodeItem(permarena, pk, 1781 lg_nsslowkey_RSAPrivateKeyTemplate2, 1782 &newPrivateKey); 1783 /* A publicExponent of 0 is the defining property of a secret 1784 * key disguised as an RSA key. When decoding with the 1785 * alternative template, only accept a secret key with an 1786 * improperly encoded modulus and a publicExponent of 0. 1787 */ 1788 if (rv == SECSuccess) { 1789 if (pk->u.rsa.modulus.len == 2 && 1790 pk->u.rsa.modulus.data[0] == SEC_ASN1_INTEGER && 1791 pk->u.rsa.modulus.data[1] == 0 && 1792 pk->u.rsa.publicExponent.len == 1 && 1793 pk->u.rsa.publicExponent.data[0] == 0) { 1794 /* Fix the zero-length integer by setting it to 0. */ 1795 pk->u.rsa.modulus.data = pk->u.rsa.publicExponent.data; 1796 pk->u.rsa.modulus.len = pk->u.rsa.publicExponent.len; 1797 } else { 1798 PORT_SetError(SEC_ERROR_BAD_DER); 1799 rv = SECFailure; 1800 } 1801 } 1802 break; 1803 case SEC_OID_ANSIX9_DSA_SIGNATURE: 1804 pk->keyType = NSSLOWKEYDSAKey; 1805 lg_prepare_low_dsa_priv_key_for_asn1(pk); 1806 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey, 1807 &pki->privateKey)) 1808 break; 1809 rv = SEC_QuickDERDecodeItem(permarena, pk, 1810 lg_nsslowkey_DSAPrivateKeyTemplate, 1811 &newPrivateKey); 1812 if (rv != SECSuccess) 1813 goto loser; 1814 lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params); 1815 if (SECSuccess != SECITEM_CopyItem(permarena, &newAlgParms, 1816 &pki->algorithm.parameters)) 1817 break; 1818 rv = SEC_QuickDERDecodeItem(permarena, &pk->u.dsa.params, 1819 lg_nsslowkey_PQGParamsTemplate, 1820 &newAlgParms); 1821 break; 1822 case SEC_OID_X942_DIFFIE_HELMAN_KEY: 1823 pk->keyType = NSSLOWKEYDHKey; 1824 lg_prepare_low_dh_priv_key_for_asn1(pk); 1825 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey, 1826 &pki->privateKey)) 1827 break; 1828 rv = SEC_QuickDERDecodeItem(permarena, pk, 1829 lg_nsslowkey_DHPrivateKeyTemplate, 1830 &newPrivateKey); 1831 break; 1832 case SEC_OID_ANSIX962_EC_PUBLIC_KEY: 1833 pk->keyType = NSSLOWKEYECKey; 1834 lg_prepare_low_ec_priv_key_for_asn1(pk); 1835 1836 #ifdef EC_DEBUG 1837 fordebug = &pki->privateKey; 1838 SEC_PRINT("seckey_decrypt_private_key()", "PrivateKey", 1839 pk->keyType, fordebug); 1840 #endif 1841 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey, 1842 &pki->privateKey)) 1843 break; 1844 rv = SEC_QuickDERDecodeItem(permarena, pk, 1845 lg_nsslowkey_ECPrivateKeyTemplate, 1846 &newPrivateKey); 1847 if (rv != SECSuccess) 1848 goto loser; 1849 1850 lg_prepare_low_ecparams_for_asn1(&pk->u.ec.ecParams); 1851 1852 rv = SECITEM_CopyItem(permarena, 1853 &pk->u.ec.ecParams.DEREncoding, 1854 &pki->algorithm.parameters); 1855 1856 if (rv != SECSuccess) 1857 goto loser; 1858 1859 /* Fill out the rest of EC params */ 1860 rv = LGEC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding, 1861 &pk->u.ec.ecParams); 1862 1863 if (rv != SECSuccess) 1864 goto loser; 1865 1866 if (pk->u.ec.publicValue.len != 0) { 1867 pk->u.ec.publicValue.len >>= 3; 1868 } 1869 1870 break; 1871 default: 1872 rv = SECFailure; 1873 break; 1874 } 1875 } else if (PORT_GetError() == SEC_ERROR_BAD_DER) { 1876 PORT_SetError(SEC_ERROR_BAD_PASSWORD); 1877 goto loser; 1878 } 1879 } 1880 1881 /* let success fall through */ 1882 loser: 1883 if (temparena != NULL) 1884 PORT_FreeArena(temparena, PR_TRUE); 1885 if (dest != NULL) 1886 SECITEM_ZfreeItem(dest, PR_TRUE); 1887 1888 if (rv != SECSuccess) { 1889 if (permarena != NULL) 1890 PORT_FreeArena(permarena, PR_TRUE); 1891 pk = NULL; 1892 } 1893 1894 return pk; 1895 } 1896 1897 static NSSLOWKEYPrivateKey * 1898 seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SDB *sdbpw) 1899 { 1900 if ((dbkey == NULL) || (sdbpw == NULL)) { 1901 return NULL; 1902 } 1903 1904 return seckey_decrypt_private_key(&(dbkey->derPK), sdbpw); 1905 } 1906 1907 static NSSLOWKEYPrivateKey * 1908 seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname, 1909 SDB *sdbpw) 1910 { 1911 NSSLOWKEYDBKey *dbkey = NULL; 1912 NSSLOWKEYPrivateKey *pk = NULL; 1913 1914 if ((keydb == NULL) || (index == NULL) || (sdbpw == NULL)) { 1915 return NULL; 1916 } 1917 1918 dbkey = get_dbkey(keydb, index); 1919 if (dbkey == NULL) { 1920 goto loser; 1921 } 1922 1923 if (nickname) { 1924 if (dbkey->nickname && (dbkey->nickname[0] != 0)) { 1925 *nickname = PORT_Strdup(dbkey->nickname); 1926 } else { 1927 *nickname = NULL; 1928 } 1929 } 1930 1931 pk = seckey_decode_encrypted_private_key(dbkey, sdbpw); 1932 1933 /* let success fall through */ 1934 loser: 1935 1936 if (dbkey != NULL) { 1937 sec_destroy_dbkey(dbkey); 1938 } 1939 1940 return pk; 1941 } 1942 1943 /* 1944 * Find a key in the database, indexed by its public key modulus 1945 * This is used to find keys that have been stored before their 1946 * certificate arrives. Once the certificate arrives the key 1947 * is looked up by the public modulus in the certificate, and the 1948 * re-stored by its nickname. 1949 */ 1950 NSSLOWKEYPrivateKey * 1951 nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus, 1952 SDB *sdbpw) 1953 { 1954 DBT namekey; 1955 NSSLOWKEYPrivateKey *pk = NULL; 1956 1957 if (handle == NULL) { 1958 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1959 return NULL; 1960 } 1961 1962 /* set up db key */ 1963 namekey.data = modulus->data; 1964 namekey.size = modulus->len; 1965 1966 pk = seckey_get_private_key(handle, &namekey, NULL, sdbpw); 1967 1968 /* no need to free dbkey, since its on the stack, and the data it 1969 * points to is owned by the database 1970 */ 1971 return (pk); 1972 } 1973 1974 char * 1975 nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, 1976 SECItem *modulus, SDB *sdbpw) 1977 { 1978 DBT namekey; 1979 NSSLOWKEYPrivateKey *pk = NULL; 1980 char *nickname = NULL; 1981 1982 if (handle == NULL) { 1983 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1984 return NULL; 1985 } 1986 1987 /* set up db key */ 1988 namekey.data = modulus->data; 1989 namekey.size = modulus->len; 1990 1991 pk = seckey_get_private_key(handle, &namekey, &nickname, sdbpw); 1992 if (pk) { 1993 lg_nsslowkey_DestroyPrivateKey(pk); 1994 } 1995 1996 /* no need to free dbkey, since its on the stack, and the data it 1997 * points to is owned by the database 1998 */ 1999 return (nickname); 2000 } 2001 /* ===== ENCODING ROUTINES ===== */ 2002 2003 static SECStatus 2004 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg, 2005 SECItem *encCheck) 2006 { 2007 SECOidData *oidData; 2008 2009 oidData = SECOID_FindOIDByTag(alg); 2010 if (oidData == NULL) { 2011 return SECFailure; 2012 } 2013 2014 entry->len = 1 + oidData->oid.len + encCheck->len; 2015 if (arena) { 2016 entry->data = (unsigned char *)PORT_ArenaAlloc(arena, entry->len); 2017 } else { 2018 entry->data = (unsigned char *)PORT_Alloc(entry->len); 2019 } 2020 2021 if (entry->data == NULL) { 2022 return SECFailure; 2023 } 2024 2025 /* first length of oid */ 2026 entry->data[0] = (unsigned char)oidData->oid.len; 2027 /* next oid itself */ 2028 PORT_Memcpy(&entry->data[1], oidData->oid.data, oidData->oid.len); 2029 /* finally the encrypted check string */ 2030 PORT_Memcpy(&entry->data[1 + oidData->oid.len], encCheck->data, 2031 encCheck->len); 2032 2033 return SECSuccess; 2034 } 2035 2036 #define MAX_DB_SIZE 0xffff 2037 /* 2038 * Clear out all the keys in the existing database 2039 */ 2040 static SECStatus 2041 nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle) 2042 { 2043 SECStatus rv; 2044 int errors = 0; 2045 2046 if (handle->db == NULL) { 2047 return (SECSuccess); 2048 } 2049 2050 if (handle->readOnly) { 2051 /* set an error code */ 2052 return SECFailure; 2053 } 2054 2055 if (handle->appname == NULL && handle->dbname == NULL) { 2056 return SECFailure; 2057 } 2058 2059 keydb_Close(handle); 2060 if (handle->appname) { 2061 handle->db = 2062 rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL); 2063 } else { 2064 handle->db = dbopen(handle->dbname, NO_CREATE, 0600, DB_HASH, 0); 2065 } 2066 if (handle->db == NULL) { 2067 /* set an error code */ 2068 return SECFailure; 2069 } 2070 2071 rv = makeGlobalVersion(handle); 2072 if (rv != SECSuccess) { 2073 errors++; 2074 goto done; 2075 } 2076 2077 if (handle->global_salt) { 2078 rv = StoreKeyDBGlobalSalt(handle, handle->global_salt); 2079 } else { 2080 rv = makeGlobalSalt(handle); 2081 if (rv == SECSuccess) { 2082 handle->global_salt = GetKeyDBGlobalSalt(handle); 2083 } 2084 } 2085 if (rv != SECSuccess) { 2086 errors++; 2087 } 2088 2089 done: 2090 /* sync the database */ 2091 (void)keydb_Sync(handle, 0); 2092 db_InitComplete(handle->db); 2093 2094 return (errors == 0 ? SECSuccess : SECFailure); 2095 } 2096 2097 static int 2098 keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) 2099 { 2100 int ret; 2101 PRLock *kdbLock = kdb->lock; 2102 DB *db = kdb->db; 2103 2104 PORT_Assert(kdbLock != NULL); 2105 PZ_Lock(kdbLock); 2106 2107 ret = (*db->get)(db, key, data, flags); 2108 2109 (void)PZ_Unlock(kdbLock); 2110 2111 return (ret); 2112 } 2113 2114 static int 2115 keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) 2116 { 2117 int ret = 0; 2118 PRLock *kdbLock = kdb->lock; 2119 DB *db = kdb->db; 2120 2121 PORT_Assert(kdbLock != NULL); 2122 PZ_Lock(kdbLock); 2123 2124 ret = (*db->put)(db, key, data, flags); 2125 2126 (void)PZ_Unlock(kdbLock); 2127 2128 return (ret); 2129 } 2130 2131 static int 2132 keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags) 2133 { 2134 int ret; 2135 PRLock *kdbLock = kdb->lock; 2136 DB *db = kdb->db; 2137 2138 PORT_Assert(kdbLock != NULL); 2139 PZ_Lock(kdbLock); 2140 2141 ret = (*db->sync)(db, flags); 2142 2143 (void)PZ_Unlock(kdbLock); 2144 2145 return (ret); 2146 } 2147 2148 static int 2149 keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags) 2150 { 2151 int ret; 2152 PRLock *kdbLock = kdb->lock; 2153 DB *db = kdb->db; 2154 2155 PORT_Assert(kdbLock != NULL); 2156 PZ_Lock(kdbLock); 2157 2158 ret = (*db->del)(db, key, flags); 2159 2160 (void)PZ_Unlock(kdbLock); 2161 2162 return (ret); 2163 } 2164 2165 static int 2166 keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) 2167 { 2168 int ret; 2169 PRLock *kdbLock = kdb->lock; 2170 DB *db = kdb->db; 2171 2172 PORT_Assert(kdbLock != NULL); 2173 PZ_Lock(kdbLock); 2174 2175 ret = (*db->seq)(db, key, data, flags); 2176 2177 (void)PZ_Unlock(kdbLock); 2178 2179 return (ret); 2180 } 2181 2182 static void 2183 keydb_Close(NSSLOWKEYDBHandle *kdb) 2184 { 2185 PRLock *kdbLock = kdb->lock; 2186 DB *db = kdb->db; 2187 2188 PORT_Assert(kdbLock != NULL); 2189 SKIP_AFTER_FORK(PZ_Lock(kdbLock)); 2190 2191 (*db->close)(db); 2192 2193 SKIP_AFTER_FORK(PZ_Unlock(kdbLock)); 2194 2195 return; 2196 } 2197 2198 /* 2199 * SDB Entry Points for the Key DB 2200 */ 2201 2202 CK_RV 2203 lg_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2) 2204 { 2205 NSSLOWKEYDBHandle *keydb; 2206 NSSLOWKEYPasswordEntry entry; 2207 SECStatus rv; 2208 2209 keydb = lg_getKeyDB(sdb); 2210 if (keydb == NULL) { 2211 return CKR_TOKEN_WRITE_PROTECTED; 2212 } 2213 if (PORT_Strcmp(id, "password") != 0) { 2214 /* shouldn't happen */ 2215 return CKR_GENERAL_ERROR; /* no extra data stored */ 2216 } 2217 rv = nsslowkey_GetPWCheckEntry(keydb, &entry); 2218 if (rv != SECSuccess) { 2219 return CKR_GENERAL_ERROR; 2220 } 2221 item1->len = entry.salt.len; 2222 PORT_Memcpy(item1->data, entry.salt.data, item1->len); 2223 item2->len = entry.value.len; 2224 PORT_Memcpy(item2->data, entry.value.data, item2->len); 2225 return CKR_OK; 2226 } 2227 2228 CK_RV 2229 lg_PutMetaData(SDB *sdb, const char *id, 2230 const SECItem *item1, const SECItem *item2) 2231 { 2232 NSSLOWKEYDBHandle *keydb; 2233 NSSLOWKEYPasswordEntry entry; 2234 SECStatus rv; 2235 2236 keydb = lg_getKeyDB(sdb); 2237 if (keydb == NULL) { 2238 return CKR_TOKEN_WRITE_PROTECTED; 2239 } 2240 if (PORT_Strcmp(id, "password") != 0) { 2241 /* shouldn't happen */ 2242 return CKR_GENERAL_ERROR; /* no extra data stored */ 2243 } 2244 entry.salt = *item1; 2245 entry.value = *item2; 2246 rv = nsslowkey_PutPWCheckEntry(keydb, &entry); 2247 if (rv != SECSuccess) { 2248 return CKR_GENERAL_ERROR; 2249 } 2250 return CKR_OK; 2251 } 2252 2253 CK_RV 2254 lg_DestroyMetaData(SDB *db, const char *id) 2255 { 2256 return CKR_GENERAL_ERROR; /* no extra data stored */ 2257 } 2258 2259 CK_RV 2260 lg_Reset(SDB *sdb) 2261 { 2262 NSSLOWKEYDBHandle *keydb; 2263 SECStatus rv; 2264 2265 keydb = lg_getKeyDB(sdb); 2266 if (keydb == NULL) { 2267 return CKR_TOKEN_WRITE_PROTECTED; 2268 } 2269 rv = nsslowkey_ResetKeyDB(keydb); 2270 if (rv != SECSuccess) { 2271 return CKR_GENERAL_ERROR; 2272 } 2273 return CKR_OK; 2274 }