pcertdb.c (144026B)
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 /* 6 * Permanent Certificate database handling code 7 */ 8 #include "lowkeyti.h" 9 #include "pcert.h" 10 #include "mcom_db.h" 11 #include "pcert.h" 12 #include "secitem.h" 13 #include "secder.h" 14 15 #include "secerr.h" 16 #include "lgdb.h" 17 18 /* forward declaration */ 19 NSSLOWCERTCertificate * 20 nsslowcert_FindCertByDERCertNoLocking(NSSLOWCERTCertDBHandle *handle, SECItem *derCert); 21 static SECStatus 22 nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, 23 char *emailAddr, SECItem *derSubject, SECItem *emailProfile, 24 SECItem *profileTime); 25 static SECStatus 26 nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle, 27 NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust); 28 static SECStatus 29 nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 30 SECItem *crlKey, char *url, PRBool isKRL); 31 32 static NSSLOWCERTCertificate *certListHead = NULL; 33 static NSSLOWCERTTrust *trustListHead = NULL; 34 static certDBEntryCert *entryListHead = NULL; 35 static int certListCount = 0; 36 static int trustListCount = 0; 37 static int entryListCount = 0; 38 #define MAX_CERT_LIST_COUNT 10 39 #define MAX_TRUST_LIST_COUNT 10 40 #define MAX_ENTRY_LIST_COUNT 10 41 42 /* 43 * the following functions are wrappers for the db library that implement 44 * a global lock to make the database thread safe. 45 */ 46 static PZLock *dbLock = NULL; 47 static PZLock *certRefCountLock = NULL; 48 static PZLock *certTrustLock = NULL; 49 static PZLock *freeListLock = NULL; 50 51 void 52 certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle) 53 { 54 if (dbLock == NULL) { 55 dbLock = PZ_NewLock(nssILockCertDB); 56 PORT_Assert(dbLock != NULL); 57 } 58 } 59 60 SECStatus 61 nsslowcert_InitLocks(void) 62 { 63 if (freeListLock == NULL) { 64 freeListLock = PZ_NewLock(nssILockRefLock); 65 if (freeListLock == NULL) { 66 return SECFailure; 67 } 68 } 69 if (certRefCountLock == NULL) { 70 certRefCountLock = PZ_NewLock(nssILockRefLock); 71 if (certRefCountLock == NULL) { 72 return SECFailure; 73 } 74 } 75 if (certTrustLock == NULL) { 76 certTrustLock = PZ_NewLock(nssILockCertDB); 77 if (certTrustLock == NULL) { 78 return SECFailure; 79 } 80 } 81 82 return SECSuccess; 83 } 84 85 /* 86 * Acquire the global lock on the cert database. 87 * This lock is currently used for the following operations: 88 * adding or deleting a cert to either the temp or perm databases 89 * converting a temp to perm or perm to temp 90 * changing (maybe just adding!?) the trust of a cert 91 * chaning the DB status checking Configuration 92 */ 93 static void 94 nsslowcert_LockDB(NSSLOWCERTCertDBHandle *handle) 95 { 96 PZ_EnterMonitor(handle->dbMon); 97 return; 98 } 99 100 /* 101 * Free the global cert database lock. 102 */ 103 static void 104 nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle) 105 { 106 #ifdef DEBUG 107 PRStatus prstat = PZ_ExitMonitor(handle->dbMon); 108 PORT_Assert(prstat == PR_SUCCESS); 109 #else 110 PZ_ExitMonitor(handle->dbMon); 111 #endif 112 } 113 114 /* 115 * Acquire the cert reference count lock 116 * There is currently one global lock for all certs, but I'm putting a cert 117 * arg here so that it will be easy to make it per-cert in the future if 118 * that turns out to be necessary. 119 */ 120 static void 121 nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert) 122 { 123 PORT_Assert(certRefCountLock != NULL); 124 125 PZ_Lock(certRefCountLock); 126 return; 127 } 128 129 /* 130 * Free the cert reference count lock 131 */ 132 static void 133 nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert) 134 { 135 PORT_Assert(certRefCountLock != NULL); 136 137 #ifdef DEBUG 138 { 139 PRStatus prstat = PZ_Unlock(certRefCountLock); 140 PORT_Assert(prstat == PR_SUCCESS); 141 } 142 #else 143 PZ_Unlock(certRefCountLock); 144 #endif 145 } 146 147 /* 148 * Acquire the cert trust lock 149 * There is currently one global lock for all certs, but I'm putting a cert 150 * arg here so that it will be easy to make it per-cert in the future if 151 * that turns out to be necessary. 152 */ 153 static void 154 nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert) 155 { 156 PORT_Assert(certTrustLock != NULL); 157 158 PZ_Lock(certTrustLock); 159 return; 160 } 161 162 /* 163 * Free the cert trust lock 164 */ 165 static void 166 nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert) 167 { 168 PORT_Assert(certTrustLock != NULL); 169 170 #ifdef DEBUG 171 { 172 PRStatus prstat = PZ_Unlock(certTrustLock); 173 PORT_Assert(prstat == PR_SUCCESS); 174 } 175 #else 176 PZ_Unlock(certTrustLock); 177 #endif 178 } 179 180 /* 181 * Acquire the cert reference count lock 182 * There is currently one global lock for all certs, but I'm putting a cert 183 * arg here so that it will be easy to make it per-cert in the future if 184 * that turns out to be necessary. 185 */ 186 static void 187 nsslowcert_LockFreeList(void) 188 { 189 PORT_Assert(freeListLock != NULL); 190 191 SKIP_AFTER_FORK(PZ_Lock(freeListLock)); 192 return; 193 } 194 195 /* 196 * Free the cert reference count lock 197 */ 198 static void 199 nsslowcert_UnlockFreeList(void) 200 { 201 PORT_Assert(freeListLock != NULL); 202 203 #ifdef DEBUG 204 { 205 PRStatus prstat = PR_SUCCESS; 206 SKIP_AFTER_FORK(prstat = PZ_Unlock(freeListLock)); 207 PORT_Assert(prstat == PR_SUCCESS); 208 } 209 #else 210 SKIP_AFTER_FORK(PZ_Unlock(freeListLock)); 211 #endif 212 } 213 214 NSSLOWCERTCertificate * 215 nsslowcert_DupCertificate(NSSLOWCERTCertificate *c) 216 { 217 if (c) { 218 nsslowcert_LockCertRefCount(c); 219 ++c->referenceCount; 220 nsslowcert_UnlockCertRefCount(c); 221 } 222 return c; 223 } 224 225 static int 226 certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags) 227 { 228 int ret; 229 230 PORT_Assert(dbLock != NULL); 231 PZ_Lock(dbLock); 232 233 ret = (*db->get)(db, key, data, flags); 234 235 (void)PZ_Unlock(dbLock); 236 237 return (ret); 238 } 239 240 static int 241 certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags) 242 { 243 int ret = 0; 244 245 PORT_Assert(dbLock != NULL); 246 PZ_Lock(dbLock); 247 248 ret = (*db->put)(db, key, data, flags); 249 250 (void)PZ_Unlock(dbLock); 251 252 return (ret); 253 } 254 255 static int 256 certdb_Sync(DB *db, unsigned int flags) 257 { 258 int ret; 259 260 PORT_Assert(dbLock != NULL); 261 PZ_Lock(dbLock); 262 263 ret = (*db->sync)(db, flags); 264 265 (void)PZ_Unlock(dbLock); 266 267 return (ret); 268 } 269 270 #define DB_NOT_FOUND -30991 /* from DBM 3.2 */ 271 static int 272 certdb_Del(DB *db, DBT *key, unsigned int flags) 273 { 274 int ret; 275 276 PORT_Assert(dbLock != NULL); 277 PZ_Lock(dbLock); 278 279 ret = (*db->del)(db, key, flags); 280 281 (void)PZ_Unlock(dbLock); 282 283 /* don't fail if the record is already deleted */ 284 if (ret == DB_NOT_FOUND) { 285 ret = 0; 286 } 287 288 return (ret); 289 } 290 291 static int 292 certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags) 293 { 294 int ret; 295 296 PORT_Assert(dbLock != NULL); 297 PZ_Lock(dbLock); 298 299 ret = (*db->seq)(db, key, data, flags); 300 301 (void)PZ_Unlock(dbLock); 302 303 return (ret); 304 } 305 306 static void 307 certdb_Close(DB *db) 308 { 309 PORT_Assert(dbLock != NULL); 310 SKIP_AFTER_FORK(PZ_Lock(dbLock)); 311 312 (*db->close)(db); 313 314 SKIP_AFTER_FORK(PZ_Unlock(dbLock)); 315 316 return; 317 } 318 319 void 320 pkcs11_freeNickname(char *nickname, char *space) 321 { 322 if (nickname && nickname != space) { 323 PORT_Free(nickname); 324 } 325 } 326 327 char * 328 pkcs11_copyNickname(char *nickname, char *space, int spaceLen) 329 { 330 int len; 331 char *copy = NULL; 332 333 len = PORT_Strlen(nickname) + 1; 334 if (len <= spaceLen) { 335 copy = space; 336 PORT_Memcpy(copy, nickname, len); 337 } else { 338 copy = PORT_Strdup(nickname); 339 } 340 341 return copy; 342 } 343 344 void 345 pkcs11_freeStaticData(unsigned char *data, unsigned char *space) 346 { 347 if (data && data != space) { 348 PORT_Free(data); 349 } 350 } 351 352 unsigned char * 353 pkcs11_allocStaticData(int len, unsigned char *space, int spaceLen) 354 { 355 unsigned char *data = NULL; 356 357 if (len <= spaceLen) { 358 data = space; 359 } else { 360 data = (unsigned char *)PORT_Alloc(len); 361 } 362 363 return data; 364 } 365 366 unsigned char * 367 pkcs11_copyStaticData(unsigned char *data, int len, 368 unsigned char *space, int spaceLen) 369 { 370 unsigned char *copy = pkcs11_allocStaticData(len, space, spaceLen); 371 if (copy) { 372 PORT_Memcpy(copy, data, len); 373 } 374 375 return copy; 376 } 377 378 /* 379 * destroy a database entry 380 */ 381 static void 382 DestroyDBEntry(certDBEntry *entry) 383 { 384 PLArenaPool *arena = entry->common.arena; 385 386 /* must be one of our certDBEntry from the free list */ 387 if (arena == NULL) { 388 certDBEntryCert *certEntry; 389 if (entry->common.type != certDBEntryTypeCert) { 390 return; 391 } 392 certEntry = (certDBEntryCert *)entry; 393 394 pkcs11_freeStaticData(certEntry->derCert.data, certEntry->derCertSpace); 395 pkcs11_freeNickname(certEntry->nickname, certEntry->nicknameSpace); 396 397 nsslowcert_LockFreeList(); 398 if (entryListCount > MAX_ENTRY_LIST_COUNT) { 399 PORT_Free(certEntry); 400 } else { 401 entryListCount++; 402 PORT_Memset(certEntry, 0, sizeof(*certEntry)); 403 certEntry->next = entryListHead; 404 entryListHead = certEntry; 405 } 406 nsslowcert_UnlockFreeList(); 407 return; 408 } 409 410 /* Zero out the entry struct, so that any further attempts to use it 411 * will cause an exception (e.g. null pointer reference). */ 412 PORT_Memset(&entry->common, 0, sizeof entry->common); 413 PORT_FreeArena(arena, PR_FALSE); 414 415 return; 416 } 417 418 /* forward references */ 419 static void nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert); 420 421 static SECStatus 422 DeleteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey) 423 { 424 DBT key; 425 int ret; 426 427 /* init the database key */ 428 key.data = dbkey->data; 429 key.size = dbkey->len; 430 431 dbkey->data[0] = (unsigned char)type; 432 433 /* delete entry from database */ 434 ret = certdb_Del(handle->permCertDB, &key, 0); 435 if (ret != 0) { 436 PORT_SetError(SEC_ERROR_BAD_DATABASE); 437 goto loser; 438 } 439 440 ret = certdb_Sync(handle->permCertDB, 0); 441 if (ret) { 442 PORT_SetError(SEC_ERROR_BAD_DATABASE); 443 goto loser; 444 } 445 446 return (SECSuccess); 447 448 loser: 449 return (SECFailure); 450 } 451 452 static SECStatus 453 ReadDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry, 454 SECItem *dbkey, SECItem *dbentry, PLArenaPool *arena) 455 { 456 DBT data, key; 457 int ret; 458 unsigned char *buf; 459 460 /* init the database key */ 461 key.data = dbkey->data; 462 key.size = dbkey->len; 463 464 dbkey->data[0] = (unsigned char)entry->type; 465 466 /* read entry from database */ 467 ret = certdb_Get(handle->permCertDB, &key, &data, 0); 468 if (ret != 0) { 469 PORT_SetError(SEC_ERROR_BAD_DATABASE); 470 goto loser; 471 } 472 473 /* validate the entry */ 474 if (data.size < SEC_DB_ENTRY_HEADER_LEN) { 475 PORT_SetError(SEC_ERROR_BAD_DATABASE); 476 goto loser; 477 } 478 buf = (unsigned char *)data.data; 479 /* version 7 has the same schema, we may be using a v7 db if we openned 480 * the databases readonly. */ 481 if (!((buf[0] == (unsigned char)CERT_DB_FILE_VERSION) || 482 (buf[0] == (unsigned char)CERT_DB_V7_FILE_VERSION))) { 483 PORT_SetError(SEC_ERROR_BAD_DATABASE); 484 goto loser; 485 } 486 if (buf[1] != (unsigned char)entry->type) { 487 PORT_SetError(SEC_ERROR_BAD_DATABASE); 488 goto loser; 489 } 490 491 /* copy out header information */ 492 entry->version = (unsigned int)buf[0]; 493 entry->type = (certDBEntryType)buf[1]; 494 entry->flags = (unsigned int)buf[2]; 495 496 /* format body of entry for return to caller */ 497 dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN; 498 if (dbentry->len) { 499 if (arena) { 500 dbentry->data = (unsigned char *) 501 PORT_ArenaAlloc(arena, dbentry->len); 502 if (dbentry->data == NULL) { 503 PORT_SetError(SEC_ERROR_NO_MEMORY); 504 goto loser; 505 } 506 507 PORT_Memcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN], 508 dbentry->len); 509 } else { 510 dbentry->data = &buf[SEC_DB_ENTRY_HEADER_LEN]; 511 } 512 } else { 513 dbentry->data = NULL; 514 } 515 516 return (SECSuccess); 517 518 loser: 519 return (SECFailure); 520 } 521 522 /** 523 ** Implement low level database access 524 **/ 525 static SECStatus 526 WriteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry, 527 SECItem *dbkey, SECItem *dbentry) 528 { 529 int ret; 530 DBT data, key; 531 unsigned char *buf; 532 533 data.data = dbentry->data; 534 data.size = dbentry->len; 535 536 buf = (unsigned char *)data.data; 537 538 buf[0] = (unsigned char)entry->version; 539 buf[1] = (unsigned char)entry->type; 540 buf[2] = (unsigned char)entry->flags; 541 542 key.data = dbkey->data; 543 key.size = dbkey->len; 544 545 dbkey->data[0] = (unsigned char)entry->type; 546 547 /* put the record into the database now */ 548 ret = certdb_Put(handle->permCertDB, &key, &data, 0); 549 550 if (ret != 0) { 551 goto loser; 552 } 553 554 ret = certdb_Sync(handle->permCertDB, 0); 555 556 if (ret) { 557 goto loser; 558 } 559 560 return (SECSuccess); 561 562 loser: 563 return (SECFailure); 564 } 565 566 /* 567 * encode a database cert record 568 */ 569 static SECStatus 570 EncodeDBCertEntry(certDBEntryCert *entry, PLArenaPool *arena, SECItem *dbitem) 571 { 572 unsigned int nnlen; 573 unsigned char *buf; 574 char *nn; 575 char zbuf = 0; 576 577 if (entry->nickname) { 578 nn = entry->nickname; 579 } else { 580 nn = &zbuf; 581 } 582 nnlen = PORT_Strlen(nn) + 1; 583 584 /* allocate space for encoded database record, including space 585 * for low level header 586 */ 587 dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN + 588 SEC_DB_ENTRY_HEADER_LEN; 589 590 dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 591 if (dbitem->data == NULL) { 592 PORT_SetError(SEC_ERROR_NO_MEMORY); 593 goto loser; 594 } 595 596 /* fill in database record */ 597 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 598 599 buf[0] = (PRUint8)(entry->trust.sslFlags >> 8); 600 buf[1] = (PRUint8)(entry->trust.sslFlags); 601 buf[2] = (PRUint8)(entry->trust.emailFlags >> 8); 602 buf[3] = (PRUint8)(entry->trust.emailFlags); 603 buf[4] = (PRUint8)(entry->trust.objectSigningFlags >> 8); 604 buf[5] = (PRUint8)(entry->trust.objectSigningFlags); 605 buf[6] = (PRUint8)(entry->derCert.len >> 8); 606 buf[7] = (PRUint8)(entry->derCert.len); 607 buf[8] = (PRUint8)(nnlen >> 8); 608 buf[9] = (PRUint8)(nnlen); 609 610 PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data, 611 entry->derCert.len); 612 613 PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN + entry->derCert.len], 614 nn, nnlen); 615 616 return (SECSuccess); 617 618 loser: 619 return (SECFailure); 620 } 621 622 /* 623 * encode a database key for a cert record 624 */ 625 static SECStatus 626 EncodeDBCertKey(const SECItem *certKey, PLArenaPool *arena, SECItem *dbkey) 627 { 628 unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN; 629 if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) 630 goto loser; 631 if (arena) { 632 dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, len); 633 } else { 634 if (dbkey->len < len) { 635 dbkey->data = (unsigned char *)PORT_Alloc(len); 636 } 637 } 638 dbkey->len = len; 639 if (dbkey->data == NULL) { 640 goto loser; 641 } 642 PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], 643 certKey->data, certKey->len); 644 dbkey->data[0] = certDBEntryTypeCert; 645 646 return (SECSuccess); 647 loser: 648 return (SECFailure); 649 } 650 651 static SECStatus 652 EncodeDBGenericKey(const SECItem *certKey, PLArenaPool *arena, SECItem *dbkey, 653 certDBEntryType entryType) 654 { 655 /* 656 * we only allow _one_ KRL key! 657 */ 658 if (entryType == certDBEntryTypeKeyRevocation) { 659 dbkey->len = SEC_DB_KEY_HEADER_LEN; 660 dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 661 if (dbkey->data == NULL) { 662 goto loser; 663 } 664 dbkey->data[0] = (unsigned char)entryType; 665 return (SECSuccess); 666 } 667 668 dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN; 669 if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) 670 goto loser; 671 dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 672 if (dbkey->data == NULL) { 673 goto loser; 674 } 675 PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], 676 certKey->data, certKey->len); 677 dbkey->data[0] = (unsigned char)entryType; 678 679 return (SECSuccess); 680 loser: 681 return (SECFailure); 682 } 683 684 static SECStatus 685 DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry) 686 { 687 unsigned int nnlen; 688 unsigned int headerlen; 689 int lenoff; 690 691 /* allow updates of old versions of the database */ 692 switch (entry->common.version) { 693 case 5: 694 headerlen = DB_CERT_V5_ENTRY_HEADER_LEN; 695 lenoff = 3; 696 break; 697 case 6: 698 /* should not get here */ 699 PORT_Assert(0); 700 headerlen = DB_CERT_V6_ENTRY_HEADER_LEN; 701 lenoff = 3; 702 break; 703 case 7: 704 case 8: 705 headerlen = DB_CERT_ENTRY_HEADER_LEN; 706 lenoff = 6; 707 break; 708 default: 709 /* better not get here */ 710 PORT_Assert(0); 711 headerlen = DB_CERT_V5_ENTRY_HEADER_LEN; 712 lenoff = 3; 713 break; 714 } 715 716 /* is record long enough for header? */ 717 if (dbentry->len < headerlen) { 718 PORT_SetError(SEC_ERROR_BAD_DATABASE); 719 goto loser; 720 } 721 722 /* is database entry correct length? */ 723 entry->derCert.len = ((dbentry->data[lenoff] << 8) | 724 dbentry->data[lenoff + 1]); 725 nnlen = ((dbentry->data[lenoff + 2] << 8) | dbentry->data[lenoff + 3]); 726 lenoff = dbentry->len - (entry->derCert.len + nnlen + headerlen); 727 if (lenoff) { 728 if (lenoff < 0 || (lenoff & 0xffff) != 0) { 729 PORT_SetError(SEC_ERROR_BAD_DATABASE); 730 goto loser; 731 } 732 /* The cert size exceeded 64KB. Reconstruct the correct length. */ 733 entry->derCert.len += lenoff; 734 } 735 736 /* Is data long enough? */ 737 if (dbentry->len < headerlen + entry->derCert.len) { 738 PORT_SetError(SEC_ERROR_BAD_DATABASE); 739 goto loser; 740 } 741 742 /* copy the dercert */ 743 entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen], 744 entry->derCert.len, entry->derCertSpace, sizeof(entry->derCertSpace)); 745 if (entry->derCert.data == NULL) { 746 PORT_SetError(SEC_ERROR_NO_MEMORY); 747 goto loser; 748 } 749 750 /* copy the nickname */ 751 if (nnlen > 1) { 752 /* Is data long enough? */ 753 if (dbentry->len < headerlen + entry->derCert.len + nnlen) { 754 PORT_SetError(SEC_ERROR_BAD_DATABASE); 755 goto loser; 756 } 757 entry->nickname = (char *)pkcs11_copyStaticData( 758 &dbentry->data[headerlen + entry->derCert.len], nnlen, 759 (unsigned char *)entry->nicknameSpace, 760 sizeof(entry->nicknameSpace)); 761 if (entry->nickname == NULL) { 762 PORT_SetError(SEC_ERROR_NO_MEMORY); 763 goto loser; 764 } 765 } else { 766 entry->nickname = NULL; 767 } 768 769 if (entry->common.version < 7) { 770 /* allow updates of v5 db */ 771 entry->trust.sslFlags = dbentry->data[0]; 772 entry->trust.emailFlags = dbentry->data[1]; 773 entry->trust.objectSigningFlags = dbentry->data[2]; 774 } else { 775 entry->trust.sslFlags = (dbentry->data[0] << 8) | dbentry->data[1]; 776 entry->trust.emailFlags = (dbentry->data[2] << 8) | dbentry->data[3]; 777 entry->trust.objectSigningFlags = 778 (dbentry->data[4] << 8) | dbentry->data[5]; 779 } 780 781 return (SECSuccess); 782 loser: 783 return (SECFailure); 784 } 785 786 /* 787 * Create a new certDBEntryCert from existing data 788 */ 789 static certDBEntryCert * 790 NewDBCertEntry(SECItem *derCert, char *nickname, 791 NSSLOWCERTCertTrust *trust, int flags) 792 { 793 certDBEntryCert *entry; 794 PLArenaPool *arena = NULL; 795 int nnlen; 796 797 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 798 799 if (!arena) { 800 goto loser; 801 } 802 803 entry = PORT_ArenaZNew(arena, certDBEntryCert); 804 if (entry == NULL) { 805 goto loser; 806 } 807 808 /* fill in the dbCert */ 809 entry->common.arena = arena; 810 entry->common.type = certDBEntryTypeCert; 811 entry->common.version = CERT_DB_FILE_VERSION; 812 entry->common.flags = flags; 813 814 if (trust) { 815 entry->trust = *trust; 816 } 817 818 entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, derCert->len); 819 if (!entry->derCert.data) { 820 goto loser; 821 } 822 entry->derCert.len = derCert->len; 823 PORT_Memcpy(entry->derCert.data, derCert->data, derCert->len); 824 825 nnlen = (nickname ? strlen(nickname) + 1 : 0); 826 827 if (nnlen) { 828 entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen); 829 if (!entry->nickname) { 830 goto loser; 831 } 832 PORT_Memcpy(entry->nickname, nickname, nnlen); 833 834 } else { 835 entry->nickname = 0; 836 } 837 838 return (entry); 839 840 loser: 841 842 /* allocation error, free arena and return */ 843 if (arena) { 844 PORT_FreeArena(arena, PR_FALSE); 845 } 846 847 PORT_SetError(SEC_ERROR_NO_MEMORY); 848 return (0); 849 } 850 851 /* 852 * Decode a version 4 DBCert from the byte stream database format 853 * and construct a current database entry struct 854 */ 855 static certDBEntryCert * 856 DecodeV4DBCertEntry(unsigned char *buf, int len) 857 { 858 certDBEntryCert *entry; 859 int certlen; 860 int nnlen; 861 PLArenaPool *arena; 862 863 /* make sure length is at least long enough for the header */ 864 if (len < DBCERT_V4_HEADER_LEN) { 865 PORT_SetError(SEC_ERROR_BAD_DATABASE); 866 return (0); 867 } 868 869 /* get other lengths */ 870 certlen = buf[3] << 8 | buf[4]; 871 nnlen = buf[5] << 8 | buf[6]; 872 873 /* make sure DB entry is the right size */ 874 if ((certlen + nnlen + DBCERT_V4_HEADER_LEN) != len) { 875 PORT_SetError(SEC_ERROR_BAD_DATABASE); 876 return (0); 877 } 878 879 /* allocate arena */ 880 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 881 882 if (!arena) { 883 PORT_SetError(SEC_ERROR_NO_MEMORY); 884 return (0); 885 } 886 887 /* allocate structure and members */ 888 entry = (certDBEntryCert *)PORT_ArenaAlloc(arena, sizeof(certDBEntryCert)); 889 890 if (!entry) { 891 goto loser; 892 } 893 894 entry->common.arena = arena; 895 entry->common.version = CERT_DB_FILE_VERSION; 896 entry->common.type = certDBEntryTypeCert; 897 entry->common.flags = 0; 898 entry->trust.sslFlags = buf[0]; 899 entry->trust.emailFlags = buf[1]; 900 entry->trust.objectSigningFlags = buf[2]; 901 902 entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen); 903 if (!entry->derCert.data) { 904 goto loser; 905 } 906 entry->derCert.len = certlen; 907 PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen); 908 909 if (nnlen) { 910 entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen); 911 if (!entry->nickname) { 912 goto loser; 913 } 914 PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen); 915 916 if (PORT_Strcmp(entry->nickname, "Server-Cert") == 0) { 917 entry->trust.sslFlags |= CERTDB_USER; 918 } 919 } else { 920 entry->nickname = 0; 921 } 922 923 return (entry); 924 925 loser: 926 PORT_FreeArena(arena, PR_FALSE); 927 PORT_SetError(SEC_ERROR_NO_MEMORY); 928 return (0); 929 } 930 931 /* 932 * Encode a Certificate database entry into byte stream suitable for 933 * the database 934 */ 935 static SECStatus 936 WriteDBCertEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry) 937 { 938 SECItem dbitem, dbkey; 939 PLArenaPool *tmparena = NULL; 940 SECItem tmpitem; 941 SECStatus rv; 942 943 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 944 if (tmparena == NULL) { 945 goto loser; 946 } 947 948 rv = EncodeDBCertEntry(entry, tmparena, &dbitem); 949 if (rv != SECSuccess) { 950 goto loser; 951 } 952 953 /* get the database key and format it */ 954 rv = nsslowcert_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem); 955 if (rv == SECFailure) { 956 goto loser; 957 } 958 959 rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey); 960 if (rv == SECFailure) { 961 goto loser; 962 } 963 964 /* now write it to the database */ 965 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 966 if (rv != SECSuccess) { 967 goto loser; 968 } 969 970 PORT_FreeArena(tmparena, PR_FALSE); 971 return (SECSuccess); 972 973 loser: 974 if (tmparena) { 975 PORT_FreeArena(tmparena, PR_FALSE); 976 } 977 return (SECFailure); 978 } 979 980 /* 981 * delete a certificate entry 982 */ 983 static SECStatus 984 DeleteDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey) 985 { 986 SECItem dbkey; 987 SECStatus rv; 988 989 dbkey.data = NULL; 990 dbkey.len = 0; 991 992 rv = EncodeDBCertKey(certKey, NULL, &dbkey); 993 if (rv != SECSuccess) { 994 goto loser; 995 } 996 997 rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey); 998 if (rv == SECFailure) { 999 goto loser; 1000 } 1001 1002 PORT_Free(dbkey.data); 1003 1004 return (SECSuccess); 1005 1006 loser: 1007 if (dbkey.data) { 1008 PORT_Free(dbkey.data); 1009 } 1010 return (SECFailure); 1011 } 1012 1013 static certDBEntryCert * 1014 CreateCertEntry(void) 1015 { 1016 certDBEntryCert *entry; 1017 1018 nsslowcert_LockFreeList(); 1019 entry = entryListHead; 1020 if (entry) { 1021 entryListCount--; 1022 entryListHead = entry->next; 1023 } 1024 PORT_Assert(entryListCount >= 0); 1025 nsslowcert_UnlockFreeList(); 1026 if (entry) { 1027 return entry; 1028 } 1029 1030 return PORT_ZNew(certDBEntryCert); 1031 } 1032 1033 static void 1034 DestroyCertEntryFreeList(void) 1035 { 1036 certDBEntryCert *entry; 1037 1038 nsslowcert_LockFreeList(); 1039 while (NULL != (entry = entryListHead)) { 1040 entryListCount--; 1041 entryListHead = entry->next; 1042 PORT_Free(entry); 1043 } 1044 PORT_Assert(!entryListCount); 1045 entryListCount = 0; 1046 nsslowcert_UnlockFreeList(); 1047 } 1048 1049 /* 1050 * Read a certificate entry 1051 */ 1052 static certDBEntryCert * 1053 ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) 1054 { 1055 certDBEntryCert *entry; 1056 SECItem dbkey; 1057 SECItem dbentry; 1058 SECStatus rv; 1059 unsigned char buf[512]; 1060 1061 dbkey.data = buf; 1062 dbkey.len = sizeof(buf); 1063 1064 entry = CreateCertEntry(); 1065 if (entry == NULL) { 1066 PORT_SetError(SEC_ERROR_NO_MEMORY); 1067 goto loser; 1068 } 1069 entry->common.arena = NULL; 1070 entry->common.type = certDBEntryTypeCert; 1071 1072 rv = EncodeDBCertKey(certKey, NULL, &dbkey); 1073 if (rv != SECSuccess) { 1074 goto loser; 1075 } 1076 1077 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL); 1078 if (rv == SECFailure) { 1079 goto loser; 1080 } 1081 1082 rv = DecodeDBCertEntry(entry, &dbentry); 1083 if (rv != SECSuccess) { 1084 goto loser; 1085 } 1086 1087 pkcs11_freeStaticData(dbkey.data, buf); 1088 dbkey.data = NULL; 1089 return (entry); 1090 1091 loser: 1092 pkcs11_freeStaticData(dbkey.data, buf); 1093 dbkey.data = NULL; 1094 if (entry) { 1095 DestroyDBEntry((certDBEntry *)entry); 1096 } 1097 1098 return (NULL); 1099 } 1100 1101 /* 1102 * encode a database cert record 1103 */ 1104 static SECStatus 1105 EncodeDBCrlEntry(certDBEntryRevocation *entry, PLArenaPool *arena, SECItem *dbitem) 1106 { 1107 unsigned int nnlen = 0; 1108 unsigned char *buf; 1109 1110 if (entry->url) { 1111 nnlen = PORT_Strlen(entry->url) + 1; 1112 } 1113 1114 /* allocate space for encoded database record, including space 1115 * for low level header 1116 */ 1117 dbitem->len = entry->derCrl.len + nnlen + SEC_DB_ENTRY_HEADER_LEN + DB_CRL_ENTRY_HEADER_LEN; 1118 1119 dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 1120 if (dbitem->data == NULL) { 1121 PORT_SetError(SEC_ERROR_NO_MEMORY); 1122 goto loser; 1123 } 1124 1125 /* fill in database record */ 1126 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 1127 1128 buf[0] = (PRUint8)(entry->derCrl.len >> 8); 1129 buf[1] = (PRUint8)(entry->derCrl.len); 1130 buf[2] = (PRUint8)(nnlen >> 8); 1131 buf[3] = (PRUint8)(nnlen); 1132 1133 PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data, 1134 entry->derCrl.len); 1135 1136 if (nnlen != 0) { 1137 PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len], 1138 entry->url, nnlen); 1139 } 1140 1141 return (SECSuccess); 1142 1143 loser: 1144 return (SECFailure); 1145 } 1146 1147 static SECStatus 1148 DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry) 1149 { 1150 unsigned int urlLen; 1151 int lenDiff; 1152 1153 /* is record long enough for header? */ 1154 if (dbentry->len < DB_CRL_ENTRY_HEADER_LEN) { 1155 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1156 goto loser; 1157 } 1158 1159 /* is database entry correct length? */ 1160 entry->derCrl.len = ((dbentry->data[0] << 8) | dbentry->data[1]); 1161 urlLen = ((dbentry->data[2] << 8) | dbentry->data[3]); 1162 lenDiff = dbentry->len - 1163 (entry->derCrl.len + urlLen + DB_CRL_ENTRY_HEADER_LEN); 1164 if (lenDiff) { 1165 if (lenDiff < 0 || (lenDiff & 0xffff) != 0) { 1166 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1167 goto loser; 1168 } 1169 /* CRL entry is greater than 64 K. Hack to make this continue to work */ 1170 entry->derCrl.len += lenDiff; 1171 } 1172 1173 /* copy the der CRL */ 1174 entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1175 entry->derCrl.len); 1176 if (entry->derCrl.data == NULL) { 1177 PORT_SetError(SEC_ERROR_NO_MEMORY); 1178 goto loser; 1179 } 1180 PORT_Memcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN], 1181 entry->derCrl.len); 1182 1183 /* copy the url */ 1184 entry->url = NULL; 1185 if (urlLen != 0) { 1186 entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, urlLen); 1187 if (entry->url == NULL) { 1188 PORT_SetError(SEC_ERROR_NO_MEMORY); 1189 goto loser; 1190 } 1191 PORT_Memcpy(entry->url, 1192 &dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len], 1193 urlLen); 1194 } 1195 1196 return (SECSuccess); 1197 loser: 1198 return (SECFailure); 1199 } 1200 1201 /* 1202 * Create a new certDBEntryRevocation from existing data 1203 */ 1204 static certDBEntryRevocation * 1205 NewDBCrlEntry(SECItem *derCrl, char *url, certDBEntryType crlType, int flags) 1206 { 1207 certDBEntryRevocation *entry; 1208 PLArenaPool *arena = NULL; 1209 int nnlen; 1210 1211 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1212 1213 if (!arena) { 1214 goto loser; 1215 } 1216 1217 entry = PORT_ArenaZNew(arena, certDBEntryRevocation); 1218 if (entry == NULL) { 1219 goto loser; 1220 } 1221 1222 /* fill in the dbRevolcation */ 1223 entry->common.arena = arena; 1224 entry->common.type = crlType; 1225 entry->common.version = CERT_DB_FILE_VERSION; 1226 entry->common.flags = flags; 1227 1228 entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len); 1229 if (!entry->derCrl.data) { 1230 goto loser; 1231 } 1232 1233 if (url) { 1234 nnlen = PORT_Strlen(url) + 1; 1235 entry->url = (char *)PORT_ArenaAlloc(arena, nnlen); 1236 if (!entry->url) { 1237 goto loser; 1238 } 1239 PORT_Memcpy(entry->url, url, nnlen); 1240 } else { 1241 entry->url = NULL; 1242 } 1243 1244 entry->derCrl.len = derCrl->len; 1245 PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len); 1246 1247 return (entry); 1248 1249 loser: 1250 1251 /* allocation error, free arena and return */ 1252 if (arena) { 1253 PORT_FreeArena(arena, PR_FALSE); 1254 } 1255 1256 PORT_SetError(SEC_ERROR_NO_MEMORY); 1257 return (0); 1258 } 1259 1260 static SECStatus 1261 WriteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry, 1262 SECItem *crlKey) 1263 { 1264 SECItem dbkey; 1265 PLArenaPool *tmparena = NULL; 1266 SECItem encodedEntry; 1267 SECStatus rv; 1268 1269 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1270 if (tmparena == NULL) { 1271 goto loser; 1272 } 1273 1274 rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry); 1275 if (rv == SECFailure) { 1276 goto loser; 1277 } 1278 1279 rv = EncodeDBGenericKey(crlKey, tmparena, &dbkey, entry->common.type); 1280 if (rv == SECFailure) { 1281 goto loser; 1282 } 1283 1284 /* now write it to the database */ 1285 rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry); 1286 if (rv != SECSuccess) { 1287 goto loser; 1288 } 1289 1290 PORT_FreeArena(tmparena, PR_FALSE); 1291 return (SECSuccess); 1292 1293 loser: 1294 if (tmparena) { 1295 PORT_FreeArena(tmparena, PR_FALSE); 1296 } 1297 return (SECFailure); 1298 } 1299 /* 1300 * delete a crl entry 1301 */ 1302 static SECStatus 1303 DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *crlKey, 1304 certDBEntryType crlType) 1305 { 1306 SECItem dbkey; 1307 PLArenaPool *arena = NULL; 1308 SECStatus rv; 1309 1310 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1311 if (arena == NULL) { 1312 goto loser; 1313 } 1314 1315 rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType); 1316 if (rv != SECSuccess) { 1317 goto loser; 1318 } 1319 1320 rv = DeleteDBEntry(handle, crlType, &dbkey); 1321 if (rv == SECFailure) { 1322 goto loser; 1323 } 1324 1325 PORT_FreeArena(arena, PR_FALSE); 1326 return (SECSuccess); 1327 1328 loser: 1329 if (arena) { 1330 PORT_FreeArena(arena, PR_FALSE); 1331 } 1332 1333 return (SECFailure); 1334 } 1335 1336 /* 1337 * Read a certificate entry 1338 */ 1339 static certDBEntryRevocation * 1340 ReadDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey, 1341 certDBEntryType crlType) 1342 { 1343 PLArenaPool *arena = NULL; 1344 PLArenaPool *tmparena = NULL; 1345 certDBEntryRevocation *entry; 1346 SECItem dbkey; 1347 SECItem dbentry; 1348 SECStatus rv; 1349 1350 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1351 if (arena == NULL) { 1352 PORT_SetError(SEC_ERROR_NO_MEMORY); 1353 goto loser; 1354 } 1355 1356 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1357 if (tmparena == NULL) { 1358 PORT_SetError(SEC_ERROR_NO_MEMORY); 1359 goto loser; 1360 } 1361 1362 entry = (certDBEntryRevocation *) 1363 PORT_ArenaAlloc(arena, sizeof(certDBEntryRevocation)); 1364 if (entry == NULL) { 1365 PORT_SetError(SEC_ERROR_NO_MEMORY); 1366 goto loser; 1367 } 1368 entry->common.arena = arena; 1369 entry->common.type = crlType; 1370 1371 rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType); 1372 if (rv != SECSuccess) { 1373 goto loser; 1374 } 1375 1376 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL); 1377 if (rv == SECFailure) { 1378 goto loser; 1379 } 1380 1381 rv = DecodeDBCrlEntry(entry, &dbentry); 1382 if (rv != SECSuccess) { 1383 goto loser; 1384 } 1385 1386 PORT_FreeArena(tmparena, PR_FALSE); 1387 return (entry); 1388 1389 loser: 1390 if (tmparena) { 1391 PORT_FreeArena(tmparena, PR_FALSE); 1392 } 1393 if (arena) { 1394 PORT_FreeArena(arena, PR_FALSE); 1395 } 1396 1397 return (NULL); 1398 } 1399 1400 void 1401 nsslowcert_DestroyDBEntry(certDBEntry *entry) 1402 { 1403 DestroyDBEntry(entry); 1404 return; 1405 } 1406 1407 /* 1408 * Encode a database nickname record 1409 */ 1410 static SECStatus 1411 EncodeDBNicknameEntry(certDBEntryNickname *entry, PLArenaPool *arena, 1412 SECItem *dbitem) 1413 { 1414 unsigned char *buf; 1415 1416 /* allocate space for encoded database record, including space 1417 * for low level header 1418 */ 1419 dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN + 1420 SEC_DB_ENTRY_HEADER_LEN; 1421 dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 1422 if (dbitem->data == NULL) { 1423 goto loser; 1424 } 1425 1426 /* fill in database record */ 1427 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 1428 buf[0] = (PRUint8)(entry->subjectName.len >> 8); 1429 buf[1] = (PRUint8)(entry->subjectName.len); 1430 PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data, 1431 entry->subjectName.len); 1432 1433 return (SECSuccess); 1434 1435 loser: 1436 return (SECFailure); 1437 } 1438 1439 /* 1440 * Encode a database key for a nickname record 1441 */ 1442 static SECStatus 1443 EncodeDBNicknameKey(char *nickname, PLArenaPool *arena, 1444 SECItem *dbkey) 1445 { 1446 unsigned int nnlen; 1447 1448 nnlen = PORT_Strlen(nickname) + 1; /* includes null */ 1449 1450 /* now get the database key and format it */ 1451 dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN; 1452 if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) 1453 goto loser; 1454 dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 1455 if (dbkey->data == NULL) { 1456 goto loser; 1457 } 1458 PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], nickname, nnlen); 1459 dbkey->data[0] = certDBEntryTypeNickname; 1460 1461 return (SECSuccess); 1462 1463 loser: 1464 return (SECFailure); 1465 } 1466 1467 static SECStatus 1468 DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry, 1469 char *nickname) 1470 { 1471 int lenDiff; 1472 1473 /* is record long enough for header? */ 1474 if (dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN) { 1475 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1476 goto loser; 1477 } 1478 1479 /* is database entry correct length? */ 1480 entry->subjectName.len = ((dbentry->data[0] << 8) | dbentry->data[1]); 1481 lenDiff = dbentry->len - 1482 (entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN); 1483 if (lenDiff) { 1484 if (lenDiff < 0 || (lenDiff & 0xffff) != 0) { 1485 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1486 goto loser; 1487 } 1488 /* The entry size exceeded 64KB. Reconstruct the correct length. */ 1489 entry->subjectName.len += lenDiff; 1490 } 1491 1492 /* copy the certkey */ 1493 entry->subjectName.data = 1494 (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1495 entry->subjectName.len); 1496 if (entry->subjectName.data == NULL) { 1497 PORT_SetError(SEC_ERROR_NO_MEMORY); 1498 goto loser; 1499 } 1500 PORT_Memcpy(entry->subjectName.data, 1501 &dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN], 1502 entry->subjectName.len); 1503 entry->subjectName.type = siBuffer; 1504 1505 entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena, 1506 PORT_Strlen(nickname) + 1); 1507 if (entry->nickname) { 1508 PORT_Strcpy(entry->nickname, nickname); 1509 } 1510 1511 return (SECSuccess); 1512 1513 loser: 1514 return (SECFailure); 1515 } 1516 1517 /* 1518 * create a new nickname entry 1519 */ 1520 static certDBEntryNickname * 1521 NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags) 1522 { 1523 PLArenaPool *arena = NULL; 1524 certDBEntryNickname *entry; 1525 int nnlen; 1526 SECStatus rv; 1527 1528 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1529 if (arena == NULL) { 1530 PORT_SetError(SEC_ERROR_NO_MEMORY); 1531 goto loser; 1532 } 1533 1534 entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena, 1535 sizeof(certDBEntryNickname)); 1536 if (entry == NULL) { 1537 PORT_SetError(SEC_ERROR_NO_MEMORY); 1538 goto loser; 1539 } 1540 1541 /* init common fields */ 1542 entry->common.arena = arena; 1543 entry->common.type = certDBEntryTypeNickname; 1544 entry->common.version = CERT_DB_FILE_VERSION; 1545 entry->common.flags = flags; 1546 1547 /* copy the nickname */ 1548 nnlen = PORT_Strlen(nickname) + 1; 1549 1550 entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen); 1551 if (entry->nickname == NULL) { 1552 goto loser; 1553 } 1554 1555 PORT_Memcpy(entry->nickname, nickname, nnlen); 1556 1557 rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName); 1558 if (rv != SECSuccess) { 1559 goto loser; 1560 } 1561 1562 return (entry); 1563 loser: 1564 if (arena) { 1565 PORT_FreeArena(arena, PR_FALSE); 1566 } 1567 1568 return (NULL); 1569 } 1570 1571 /* 1572 * delete a nickname entry 1573 */ 1574 static SECStatus 1575 DeleteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname) 1576 { 1577 PLArenaPool *arena = NULL; 1578 SECStatus rv; 1579 SECItem dbkey; 1580 1581 if (nickname == NULL) { 1582 return (SECSuccess); 1583 } 1584 1585 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1586 if (arena == NULL) { 1587 goto loser; 1588 } 1589 1590 rv = EncodeDBNicknameKey(nickname, arena, &dbkey); 1591 if (rv != SECSuccess) { 1592 goto loser; 1593 } 1594 1595 rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey); 1596 if (rv == SECFailure) { 1597 goto loser; 1598 } 1599 1600 PORT_FreeArena(arena, PR_FALSE); 1601 return (SECSuccess); 1602 1603 loser: 1604 if (arena) { 1605 PORT_FreeArena(arena, PR_FALSE); 1606 } 1607 1608 return (SECFailure); 1609 } 1610 1611 /* 1612 * Read a nickname entry 1613 */ 1614 static certDBEntryNickname * 1615 ReadDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname) 1616 { 1617 PLArenaPool *arena = NULL; 1618 PLArenaPool *tmparena = NULL; 1619 certDBEntryNickname *entry; 1620 SECItem dbkey; 1621 SECItem dbentry; 1622 SECStatus rv; 1623 1624 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1625 if (arena == NULL) { 1626 PORT_SetError(SEC_ERROR_NO_MEMORY); 1627 goto loser; 1628 } 1629 1630 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1631 if (tmparena == NULL) { 1632 PORT_SetError(SEC_ERROR_NO_MEMORY); 1633 goto loser; 1634 } 1635 1636 entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena, 1637 sizeof(certDBEntryNickname)); 1638 if (entry == NULL) { 1639 PORT_SetError(SEC_ERROR_NO_MEMORY); 1640 goto loser; 1641 } 1642 entry->common.arena = arena; 1643 entry->common.type = certDBEntryTypeNickname; 1644 1645 rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey); 1646 if (rv != SECSuccess) { 1647 goto loser; 1648 } 1649 1650 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena); 1651 if (rv == SECFailure) { 1652 goto loser; 1653 } 1654 1655 /* is record long enough for header? */ 1656 if (dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN) { 1657 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1658 goto loser; 1659 } 1660 1661 rv = DecodeDBNicknameEntry(entry, &dbentry, nickname); 1662 if (rv != SECSuccess) { 1663 goto loser; 1664 } 1665 1666 PORT_FreeArena(tmparena, PR_FALSE); 1667 return (entry); 1668 1669 loser: 1670 if (tmparena) { 1671 PORT_FreeArena(tmparena, PR_FALSE); 1672 } 1673 if (arena) { 1674 PORT_FreeArena(arena, PR_FALSE); 1675 } 1676 1677 return (NULL); 1678 } 1679 1680 /* 1681 * Encode a nickname entry into byte stream suitable for 1682 * the database 1683 */ 1684 static SECStatus 1685 WriteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryNickname *entry) 1686 { 1687 SECItem dbitem, dbkey; 1688 PLArenaPool *tmparena = NULL; 1689 SECStatus rv; 1690 1691 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1692 if (tmparena == NULL) { 1693 goto loser; 1694 } 1695 1696 rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem); 1697 if (rv != SECSuccess) { 1698 goto loser; 1699 } 1700 1701 rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey); 1702 if (rv != SECSuccess) { 1703 goto loser; 1704 } 1705 1706 /* now write it to the database */ 1707 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 1708 if (rv != SECSuccess) { 1709 goto loser; 1710 } 1711 1712 PORT_FreeArena(tmparena, PR_FALSE); 1713 return (SECSuccess); 1714 1715 loser: 1716 if (tmparena) { 1717 PORT_FreeArena(tmparena, PR_FALSE); 1718 } 1719 return (SECFailure); 1720 } 1721 1722 static SECStatus 1723 EncodeDBSMimeEntry(certDBEntrySMime *entry, PLArenaPool *arena, 1724 SECItem *dbitem) 1725 { 1726 unsigned char *buf; 1727 1728 /* allocate space for encoded database record, including space 1729 * for low level header 1730 */ 1731 dbitem->len = entry->subjectName.len + entry->smimeOptions.len + 1732 entry->optionsDate.len + 1733 DB_SMIME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN; 1734 1735 dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 1736 if (dbitem->data == NULL) { 1737 PORT_SetError(SEC_ERROR_NO_MEMORY); 1738 goto loser; 1739 } 1740 1741 /* fill in database record */ 1742 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 1743 1744 buf[0] = (PRUint8)(entry->subjectName.len >> 8); 1745 buf[1] = (PRUint8)(entry->subjectName.len); 1746 buf[2] = (PRUint8)(entry->smimeOptions.len >> 8); 1747 buf[3] = (PRUint8)(entry->smimeOptions.len); 1748 buf[4] = (PRUint8)(entry->optionsDate.len >> 8); 1749 buf[5] = (PRUint8)(entry->optionsDate.len); 1750 1751 /* if no smime options, then there should not be an options date either */ 1752 PORT_Assert(!((entry->smimeOptions.len == 0) && 1753 (entry->optionsDate.len != 0))); 1754 1755 PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN], entry->subjectName.data, 1756 entry->subjectName.len); 1757 if (entry->smimeOptions.len) { 1758 PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len], 1759 entry->smimeOptions.data, 1760 entry->smimeOptions.len); 1761 PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len + 1762 entry->smimeOptions.len], 1763 entry->optionsDate.data, 1764 entry->optionsDate.len); 1765 } 1766 1767 return (SECSuccess); 1768 1769 loser: 1770 return (SECFailure); 1771 } 1772 1773 /* 1774 * Encode a database key for a SMIME record 1775 */ 1776 static SECStatus 1777 EncodeDBSMimeKey(char *emailAddr, PLArenaPool *arena, 1778 SECItem *dbkey) 1779 { 1780 unsigned int addrlen; 1781 1782 addrlen = PORT_Strlen(emailAddr) + 1; /* includes null */ 1783 1784 /* now get the database key and format it */ 1785 dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN; 1786 if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) 1787 goto loser; 1788 dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 1789 if (dbkey->data == NULL) { 1790 goto loser; 1791 } 1792 PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], emailAddr, addrlen); 1793 dbkey->data[0] = certDBEntryTypeSMimeProfile; 1794 1795 return (SECSuccess); 1796 1797 loser: 1798 return (SECFailure); 1799 } 1800 1801 /* 1802 * Decode a database SMIME record 1803 */ 1804 static SECStatus 1805 DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr) 1806 { 1807 int lenDiff; 1808 1809 /* is record long enough for header? */ 1810 if (dbentry->len < DB_SMIME_ENTRY_HEADER_LEN) { 1811 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1812 goto loser; 1813 } 1814 1815 /* is database entry correct length? */ 1816 entry->subjectName.len = ((dbentry->data[0] << 8) | dbentry->data[1]); 1817 entry->smimeOptions.len = ((dbentry->data[2] << 8) | dbentry->data[3]); 1818 entry->optionsDate.len = ((dbentry->data[4] << 8) | dbentry->data[5]); 1819 lenDiff = dbentry->len - (entry->subjectName.len + 1820 entry->smimeOptions.len + 1821 entry->optionsDate.len + 1822 DB_SMIME_ENTRY_HEADER_LEN); 1823 if (lenDiff) { 1824 if (lenDiff < 0 || (lenDiff & 0xffff) != 0) { 1825 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1826 goto loser; 1827 } 1828 /* The entry size exceeded 64KB. Reconstruct the correct length. */ 1829 entry->subjectName.len += lenDiff; 1830 } 1831 1832 /* copy the subject name */ 1833 entry->subjectName.data = 1834 (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1835 entry->subjectName.len); 1836 if (entry->subjectName.data == NULL) { 1837 PORT_SetError(SEC_ERROR_NO_MEMORY); 1838 goto loser; 1839 } 1840 PORT_Memcpy(entry->subjectName.data, 1841 &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN], 1842 entry->subjectName.len); 1843 1844 /* copy the smime options */ 1845 if (entry->smimeOptions.len) { 1846 entry->smimeOptions.data = 1847 (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1848 entry->smimeOptions.len); 1849 if (entry->smimeOptions.data == NULL) { 1850 PORT_SetError(SEC_ERROR_NO_MEMORY); 1851 goto loser; 1852 } 1853 PORT_Memcpy(entry->smimeOptions.data, 1854 &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN + 1855 entry->subjectName.len], 1856 entry->smimeOptions.len); 1857 } else { 1858 entry->smimeOptions.data = NULL; 1859 } 1860 if (entry->optionsDate.len) { 1861 entry->optionsDate.data = 1862 (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1863 entry->optionsDate.len); 1864 if (entry->optionsDate.data == NULL) { 1865 PORT_SetError(SEC_ERROR_NO_MEMORY); 1866 goto loser; 1867 } 1868 PORT_Memcpy(entry->optionsDate.data, 1869 &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN + 1870 entry->subjectName.len + 1871 entry->smimeOptions.len], 1872 entry->optionsDate.len); 1873 } else { 1874 entry->optionsDate.data = NULL; 1875 } 1876 1877 /* both options and options date must either exist or not exist */ 1878 if (((entry->optionsDate.len == 0) || 1879 (entry->smimeOptions.len == 0)) && 1880 entry->smimeOptions.len != entry->optionsDate.len) { 1881 PORT_SetError(SEC_ERROR_BAD_DATABASE); 1882 goto loser; 1883 } 1884 1885 entry->emailAddr = (char *)PORT_ArenaAlloc(entry->common.arena, 1886 PORT_Strlen(emailAddr) + 1); 1887 if (entry->emailAddr) { 1888 PORT_Strcpy(entry->emailAddr, emailAddr); 1889 } 1890 1891 return (SECSuccess); 1892 1893 loser: 1894 return (SECFailure); 1895 } 1896 1897 /* 1898 * create a new SMIME entry 1899 */ 1900 static certDBEntrySMime * 1901 NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions, 1902 SECItem *optionsDate, unsigned int flags) 1903 { 1904 PLArenaPool *arena = NULL; 1905 certDBEntrySMime *entry; 1906 int addrlen; 1907 SECStatus rv; 1908 1909 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1910 if (arena == NULL) { 1911 PORT_SetError(SEC_ERROR_NO_MEMORY); 1912 goto loser; 1913 } 1914 1915 entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena, 1916 sizeof(certDBEntrySMime)); 1917 if (entry == NULL) { 1918 PORT_SetError(SEC_ERROR_NO_MEMORY); 1919 goto loser; 1920 } 1921 1922 /* init common fields */ 1923 entry->common.arena = arena; 1924 entry->common.type = certDBEntryTypeSMimeProfile; 1925 entry->common.version = CERT_DB_FILE_VERSION; 1926 entry->common.flags = flags; 1927 1928 /* copy the email addr */ 1929 addrlen = PORT_Strlen(emailAddr) + 1; 1930 1931 entry->emailAddr = (char *)PORT_ArenaAlloc(arena, addrlen); 1932 if (entry->emailAddr == NULL) { 1933 goto loser; 1934 } 1935 1936 PORT_Memcpy(entry->emailAddr, emailAddr, addrlen); 1937 1938 /* copy the subject name */ 1939 rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName); 1940 if (rv != SECSuccess) { 1941 goto loser; 1942 } 1943 1944 /* copy the smime options */ 1945 if (smimeOptions) { 1946 rv = SECITEM_CopyItem(arena, &entry->smimeOptions, smimeOptions); 1947 if (rv != SECSuccess) { 1948 goto loser; 1949 } 1950 } else { 1951 PORT_Assert(optionsDate == NULL); 1952 entry->smimeOptions.data = NULL; 1953 entry->smimeOptions.len = 0; 1954 } 1955 1956 /* copy the options date */ 1957 if (optionsDate) { 1958 rv = SECITEM_CopyItem(arena, &entry->optionsDate, optionsDate); 1959 if (rv != SECSuccess) { 1960 goto loser; 1961 } 1962 } else { 1963 PORT_Assert(smimeOptions == NULL); 1964 entry->optionsDate.data = NULL; 1965 entry->optionsDate.len = 0; 1966 } 1967 1968 return (entry); 1969 loser: 1970 if (arena) { 1971 PORT_FreeArena(arena, PR_FALSE); 1972 } 1973 1974 return (NULL); 1975 } 1976 1977 /* 1978 * delete a SMIME entry 1979 */ 1980 static SECStatus 1981 DeleteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr) 1982 { 1983 PLArenaPool *arena = NULL; 1984 SECStatus rv; 1985 SECItem dbkey; 1986 1987 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1988 if (arena == NULL) { 1989 goto loser; 1990 } 1991 1992 rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey); 1993 if (rv != SECSuccess) { 1994 goto loser; 1995 } 1996 1997 rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey); 1998 if (rv == SECFailure) { 1999 goto loser; 2000 } 2001 2002 PORT_FreeArena(arena, PR_FALSE); 2003 return (SECSuccess); 2004 2005 loser: 2006 if (arena) { 2007 PORT_FreeArena(arena, PR_FALSE); 2008 } 2009 2010 return (SECFailure); 2011 } 2012 2013 /* 2014 * Read a SMIME entry 2015 */ 2016 certDBEntrySMime * 2017 nsslowcert_ReadDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr) 2018 { 2019 PLArenaPool *arena = NULL; 2020 PLArenaPool *tmparena = NULL; 2021 certDBEntrySMime *entry = NULL; 2022 SECItem dbkey; 2023 SECItem dbentry; 2024 SECStatus rv; 2025 2026 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2027 if (arena == NULL) { 2028 PORT_SetError(SEC_ERROR_NO_MEMORY); 2029 goto loser; 2030 } 2031 2032 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2033 if (tmparena == NULL) { 2034 PORT_SetError(SEC_ERROR_NO_MEMORY); 2035 goto loser; 2036 } 2037 2038 entry = (certDBEntrySMime *)PORT_ArenaZAlloc(arena, 2039 sizeof(certDBEntrySMime)); 2040 if (entry == NULL) { 2041 PORT_SetError(SEC_ERROR_NO_MEMORY); 2042 goto loser; 2043 } 2044 entry->common.arena = arena; 2045 entry->common.type = certDBEntryTypeSMimeProfile; 2046 2047 rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey); 2048 if (rv != SECSuccess) { 2049 goto loser; 2050 } 2051 2052 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena); 2053 if (rv == SECFailure) { 2054 goto loser; 2055 } 2056 2057 /* is record long enough for header? */ 2058 if (dbentry.len < DB_SMIME_ENTRY_HEADER_LEN) { 2059 PORT_SetError(SEC_ERROR_BAD_DATABASE); 2060 goto loser; 2061 } 2062 2063 rv = DecodeDBSMimeEntry(entry, &dbentry, emailAddr); 2064 if (rv != SECSuccess) { 2065 goto loser; 2066 } 2067 2068 PORT_FreeArena(tmparena, PR_FALSE); 2069 return (entry); 2070 2071 loser: 2072 if (tmparena) { 2073 PORT_FreeArena(tmparena, PR_FALSE); 2074 } 2075 if (arena) { 2076 PORT_FreeArena(arena, PR_FALSE); 2077 } 2078 2079 return (NULL); 2080 } 2081 2082 /* 2083 * Encode a SMIME entry into byte stream suitable for 2084 * the database 2085 */ 2086 static SECStatus 2087 WriteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySMime *entry) 2088 { 2089 SECItem dbitem, dbkey; 2090 PLArenaPool *tmparena = NULL; 2091 SECStatus rv; 2092 2093 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2094 if (tmparena == NULL) { 2095 goto loser; 2096 } 2097 2098 rv = EncodeDBSMimeEntry(entry, tmparena, &dbitem); 2099 if (rv != SECSuccess) { 2100 goto loser; 2101 } 2102 2103 rv = EncodeDBSMimeKey(entry->emailAddr, tmparena, &dbkey); 2104 if (rv != SECSuccess) { 2105 goto loser; 2106 } 2107 2108 /* now write it to the database */ 2109 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 2110 if (rv != SECSuccess) { 2111 goto loser; 2112 } 2113 2114 PORT_FreeArena(tmparena, PR_FALSE); 2115 return (SECSuccess); 2116 2117 loser: 2118 if (tmparena) { 2119 PORT_FreeArena(tmparena, PR_FALSE); 2120 } 2121 return (SECFailure); 2122 } 2123 2124 /* 2125 * Encode a database subject record 2126 */ 2127 static SECStatus 2128 EncodeDBSubjectEntry(certDBEntrySubject *entry, PLArenaPool *arena, 2129 SECItem *dbitem) 2130 { 2131 unsigned char *buf; 2132 int len; 2133 unsigned int ncerts; 2134 unsigned int i; 2135 unsigned char *tmpbuf; 2136 unsigned int nnlen = 0; 2137 unsigned int eaddrslen = 0; 2138 int keyidoff; 2139 SECItem *certKeys = entry->certKeys; 2140 SECItem *keyIDs = entry->keyIDs; 2141 ; 2142 2143 if (entry->nickname) { 2144 nnlen = PORT_Strlen(entry->nickname) + 1; 2145 } 2146 if (entry->emailAddrs) { 2147 eaddrslen = 2; 2148 for (i = 0; i < entry->nemailAddrs; i++) { 2149 eaddrslen += PORT_Strlen(entry->emailAddrs[i]) + 1 + 2; 2150 } 2151 } 2152 2153 ncerts = entry->ncerts; 2154 2155 /* compute the length of the entry */ 2156 keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen; 2157 len = keyidoff + (4 * ncerts) + eaddrslen; 2158 for (i = 0; i < ncerts; i++) { 2159 if (keyIDs[i].len > 0xffff || 2160 (certKeys[i].len > 0xffff)) { 2161 PORT_SetError(SEC_ERROR_INPUT_LEN); 2162 goto loser; 2163 } 2164 len += certKeys[i].len; 2165 len += keyIDs[i].len; 2166 } 2167 2168 /* allocate space for encoded database record, including space 2169 * for low level header 2170 */ 2171 dbitem->len = len + SEC_DB_ENTRY_HEADER_LEN; 2172 2173 dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 2174 if (dbitem->data == NULL) { 2175 PORT_SetError(SEC_ERROR_NO_MEMORY); 2176 goto loser; 2177 } 2178 2179 /* fill in database record */ 2180 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 2181 2182 buf[0] = (PRUint8)(ncerts >> 8); 2183 buf[1] = (PRUint8)(ncerts); 2184 buf[2] = (PRUint8)(nnlen >> 8); 2185 buf[3] = (PRUint8)(nnlen); 2186 /* v7 email field is NULL in v8 */ 2187 buf[4] = 0; 2188 buf[5] = 0; 2189 2190 PORT_Assert(DB_SUBJECT_ENTRY_HEADER_LEN == 6); 2191 2192 if (entry->nickname) { 2193 PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN], entry->nickname, nnlen); 2194 } 2195 tmpbuf = &buf[keyidoff]; 2196 for (i = 0; i < ncerts; i++) { 2197 tmpbuf[0] = (PRUint8)(certKeys[i].len >> 8); 2198 tmpbuf[1] = (PRUint8)(certKeys[i].len); 2199 tmpbuf += 2; 2200 } 2201 for (i = 0; i < ncerts; i++) { 2202 tmpbuf[0] = (PRUint8)(keyIDs[i].len >> 8); 2203 tmpbuf[1] = (PRUint8)(keyIDs[i].len); 2204 tmpbuf += 2; 2205 } 2206 2207 for (i = 0; i < ncerts; i++) { 2208 PORT_Memcpy(tmpbuf, certKeys[i].data, certKeys[i].len); 2209 tmpbuf += certKeys[i].len; 2210 } 2211 for (i = 0; i < ncerts; i++) { 2212 if (keyIDs[i].len) { 2213 PORT_Memcpy(tmpbuf, keyIDs[i].data, keyIDs[i].len); 2214 tmpbuf += keyIDs[i].len; 2215 } 2216 } 2217 2218 if (entry->emailAddrs) { 2219 tmpbuf[0] = (PRUint8)(entry->nemailAddrs >> 8); 2220 tmpbuf[1] = (PRUint8)(entry->nemailAddrs); 2221 tmpbuf += 2; 2222 for (i = 0; i < entry->nemailAddrs; i++) { 2223 int nameLen = PORT_Strlen(entry->emailAddrs[i]) + 1; 2224 tmpbuf[0] = (PRUint8)(nameLen >> 8); 2225 tmpbuf[1] = (PRUint8)(nameLen); 2226 tmpbuf += 2; 2227 PORT_Memcpy(tmpbuf, entry->emailAddrs[i], nameLen); 2228 tmpbuf += nameLen; 2229 } 2230 } 2231 2232 PORT_Assert(tmpbuf == &buf[len]); 2233 2234 return (SECSuccess); 2235 2236 loser: 2237 return (SECFailure); 2238 } 2239 2240 /* 2241 * Encode a database key for a subject record 2242 */ 2243 static SECStatus 2244 EncodeDBSubjectKey(SECItem *derSubject, PLArenaPool *arena, 2245 SECItem *dbkey) 2246 { 2247 dbkey->len = derSubject->len + SEC_DB_KEY_HEADER_LEN; 2248 if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) 2249 goto loser; 2250 dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 2251 if (dbkey->data == NULL) { 2252 goto loser; 2253 } 2254 PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], derSubject->data, 2255 derSubject->len); 2256 dbkey->data[0] = certDBEntryTypeSubject; 2257 2258 return (SECSuccess); 2259 2260 loser: 2261 return (SECFailure); 2262 } 2263 2264 static SECStatus 2265 DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry, 2266 const SECItem *derSubject) 2267 { 2268 PLArenaPool *arena = entry->common.arena; 2269 unsigned char *tmpbuf; 2270 unsigned char *end; 2271 void *mark = PORT_ArenaMark(arena); 2272 unsigned int eaddrlen; 2273 unsigned int i; 2274 unsigned int keyidoff; 2275 unsigned int len; 2276 unsigned int ncerts = 0; 2277 unsigned int nnlen; 2278 SECStatus rv; 2279 2280 rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject); 2281 if (rv != SECSuccess) { 2282 goto loser; 2283 } 2284 2285 /* is record long enough for header? */ 2286 if (dbentry->len < DB_SUBJECT_ENTRY_HEADER_LEN) { 2287 PORT_SetError(SEC_ERROR_BAD_DATABASE); 2288 goto loser; 2289 } 2290 2291 entry->ncerts = ncerts = ((dbentry->data[0] << 8) | dbentry->data[1]); 2292 nnlen = ((dbentry->data[2] << 8) | dbentry->data[3]); 2293 eaddrlen = ((dbentry->data[4] << 8) | dbentry->data[5]); 2294 keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen; 2295 len = keyidoff + (4 * ncerts); 2296 if (dbentry->len < len) { 2297 PORT_SetError(SEC_ERROR_BAD_DATABASE); 2298 goto loser; 2299 } 2300 2301 entry->certKeys = PORT_ArenaNewArray(arena, SECItem, ncerts); 2302 entry->keyIDs = PORT_ArenaNewArray(arena, SECItem, ncerts); 2303 if ((entry->certKeys == NULL) || (entry->keyIDs == NULL)) { 2304 PORT_SetError(SEC_ERROR_NO_MEMORY); 2305 goto loser; 2306 } 2307 2308 if (nnlen > 1) { /* null terminator is stored */ 2309 entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen); 2310 if (entry->nickname == NULL) { 2311 PORT_SetError(SEC_ERROR_NO_MEMORY); 2312 goto loser; 2313 } 2314 PORT_Memcpy(entry->nickname, 2315 &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN], 2316 nnlen); 2317 } else { 2318 entry->nickname = NULL; 2319 } 2320 2321 /* if we have an old style email entry, there is only one */ 2322 entry->nemailAddrs = 0; 2323 if (eaddrlen > 1) { /* null terminator is stored */ 2324 entry->emailAddrs = PORT_ArenaNewArray(arena, char *, 2); 2325 if (entry->emailAddrs == NULL) { 2326 PORT_SetError(SEC_ERROR_NO_MEMORY); 2327 goto loser; 2328 } 2329 entry->emailAddrs[0] = (char *)PORT_ArenaAlloc(arena, eaddrlen); 2330 if (entry->emailAddrs[0] == NULL) { 2331 PORT_SetError(SEC_ERROR_NO_MEMORY); 2332 goto loser; 2333 } 2334 PORT_Memcpy(entry->emailAddrs[0], 2335 &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN + nnlen], 2336 eaddrlen); 2337 entry->nemailAddrs = 1; 2338 } else { 2339 entry->emailAddrs = NULL; 2340 } 2341 2342 /* collect the lengths of the certKeys and keyIDs, and total the 2343 * overall length. 2344 */ 2345 tmpbuf = &dbentry->data[keyidoff]; 2346 for (i = 0; i < ncerts; i++) { 2347 unsigned int itemlen = (tmpbuf[0] << 8) | tmpbuf[1]; 2348 entry->certKeys[i].len = itemlen; 2349 len += itemlen; 2350 tmpbuf += 2; 2351 } 2352 for (i = 0; i < ncerts; i++) { 2353 unsigned int itemlen = (tmpbuf[0] << 8) | tmpbuf[1]; 2354 entry->keyIDs[i].len = itemlen; 2355 len += itemlen; 2356 tmpbuf += 2; 2357 } 2358 2359 /* is encoded entry large enough ? */ 2360 if (len > dbentry->len) { 2361 PORT_SetError(SEC_ERROR_BAD_DATABASE); 2362 goto loser; 2363 } 2364 2365 for (i = 0; i < ncerts; i++) { 2366 unsigned int kLen = entry->certKeys[i].len; 2367 entry->certKeys[i].data = (unsigned char *)PORT_ArenaAlloc(arena, kLen); 2368 if (entry->certKeys[i].data == NULL) { 2369 PORT_SetError(SEC_ERROR_NO_MEMORY); 2370 goto loser; 2371 } 2372 PORT_Memcpy(entry->certKeys[i].data, tmpbuf, kLen); 2373 tmpbuf += kLen; 2374 } 2375 for (i = 0; i < ncerts; i++) { 2376 unsigned int iLen = entry->keyIDs[i].len; 2377 entry->keyIDs[i].data = (unsigned char *)PORT_ArenaAlloc(arena, iLen); 2378 if (entry->keyIDs[i].data == NULL) { 2379 PORT_SetError(SEC_ERROR_NO_MEMORY); 2380 goto loser; 2381 } 2382 PORT_Memcpy(entry->keyIDs[i].data, tmpbuf, iLen); 2383 tmpbuf += iLen; 2384 } 2385 2386 end = dbentry->data + dbentry->len; 2387 if ((eaddrlen == 0) && (end - tmpbuf > 1)) { 2388 /* read in the additional email addresses */ 2389 entry->nemailAddrs = (((unsigned int)tmpbuf[0]) << 8) | tmpbuf[1]; 2390 tmpbuf += 2; 2391 if (end - tmpbuf < 2 * (int)entry->nemailAddrs) 2392 goto loser; 2393 entry->emailAddrs = PORT_ArenaNewArray(arena, char *, entry->nemailAddrs); 2394 if (entry->emailAddrs == NULL) { 2395 PORT_SetError(SEC_ERROR_NO_MEMORY); 2396 goto loser; 2397 } 2398 for (i = 0; i < entry->nemailAddrs; i++) { 2399 int nameLen; 2400 if (end - tmpbuf < 2) { 2401 goto loser; 2402 } 2403 nameLen = (((int)tmpbuf[0]) << 8) | tmpbuf[1]; 2404 tmpbuf += 2; 2405 if (end - tmpbuf < nameLen) { 2406 goto loser; 2407 } 2408 entry->emailAddrs[i] = PORT_ArenaAlloc(arena, nameLen); 2409 if (entry->emailAddrs == NULL) { 2410 PORT_SetError(SEC_ERROR_NO_MEMORY); 2411 goto loser; 2412 } 2413 PORT_Memcpy(entry->emailAddrs[i], tmpbuf, nameLen); 2414 tmpbuf += nameLen; 2415 } 2416 if (tmpbuf != end) 2417 goto loser; 2418 } 2419 PORT_ArenaUnmark(arena, mark); 2420 return (SECSuccess); 2421 2422 loser: 2423 PORT_ArenaRelease(arena, mark); /* discard above allocations */ 2424 return (SECFailure); 2425 } 2426 2427 /* 2428 * create a new subject entry with a single cert 2429 */ 2430 static certDBEntrySubject * 2431 NewDBSubjectEntry(SECItem *derSubject, SECItem *certKey, 2432 SECItem *keyID, char *nickname, char *emailAddr, 2433 unsigned int flags) 2434 { 2435 PLArenaPool *arena = NULL; 2436 certDBEntrySubject *entry; 2437 SECStatus rv; 2438 unsigned int nnlen; 2439 2440 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2441 if (arena == NULL) { 2442 PORT_SetError(SEC_ERROR_NO_MEMORY); 2443 goto loser; 2444 } 2445 2446 entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena, 2447 sizeof(certDBEntrySubject)); 2448 if (entry == NULL) { 2449 PORT_SetError(SEC_ERROR_NO_MEMORY); 2450 goto loser; 2451 } 2452 2453 /* init common fields */ 2454 entry->common.arena = arena; 2455 entry->common.type = certDBEntryTypeSubject; 2456 entry->common.version = CERT_DB_FILE_VERSION; 2457 entry->common.flags = flags; 2458 2459 /* copy the subject */ 2460 rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject); 2461 if (rv != SECSuccess) { 2462 goto loser; 2463 } 2464 2465 entry->ncerts = 1; 2466 entry->nemailAddrs = 0; 2467 /* copy nickname */ 2468 if (nickname && (*nickname != '\0')) { 2469 nnlen = PORT_Strlen(nickname) + 1; 2470 entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen); 2471 if (entry->nickname == NULL) { 2472 goto loser; 2473 } 2474 2475 PORT_Memcpy(entry->nickname, nickname, nnlen); 2476 } else { 2477 entry->nickname = NULL; 2478 } 2479 2480 /* copy email addr */ 2481 if (emailAddr && (*emailAddr != '\0')) { 2482 emailAddr = nsslowcert_FixupEmailAddr(emailAddr); 2483 if (emailAddr == NULL) { 2484 entry->emailAddrs = NULL; 2485 goto loser; 2486 } 2487 2488 entry->emailAddrs = (char **)PORT_ArenaAlloc(arena, sizeof(char *)); 2489 if (entry->emailAddrs == NULL) { 2490 PORT_Free(emailAddr); 2491 goto loser; 2492 } 2493 entry->emailAddrs[0] = PORT_ArenaStrdup(arena, emailAddr); 2494 if (entry->emailAddrs[0]) { 2495 entry->nemailAddrs = 1; 2496 } 2497 2498 PORT_Free(emailAddr); 2499 } else { 2500 entry->emailAddrs = NULL; 2501 } 2502 2503 /* allocate space for certKeys and keyIDs */ 2504 entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem)); 2505 entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem)); 2506 if ((entry->certKeys == NULL) || (entry->keyIDs == NULL)) { 2507 goto loser; 2508 } 2509 2510 /* copy the certKey and keyID */ 2511 rv = SECITEM_CopyItem(arena, &entry->certKeys[0], certKey); 2512 if (rv != SECSuccess) { 2513 goto loser; 2514 } 2515 rv = SECITEM_CopyItem(arena, &entry->keyIDs[0], keyID); 2516 if (rv != SECSuccess) { 2517 goto loser; 2518 } 2519 2520 return (entry); 2521 loser: 2522 if (arena) { 2523 PORT_FreeArena(arena, PR_FALSE); 2524 } 2525 2526 return (NULL); 2527 } 2528 2529 /* 2530 * delete a subject entry 2531 */ 2532 static SECStatus 2533 DeleteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject) 2534 { 2535 SECItem dbkey; 2536 PLArenaPool *arena = NULL; 2537 SECStatus rv; 2538 2539 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2540 if (arena == NULL) { 2541 goto loser; 2542 } 2543 2544 rv = EncodeDBSubjectKey(derSubject, arena, &dbkey); 2545 if (rv != SECSuccess) { 2546 goto loser; 2547 } 2548 2549 rv = DeleteDBEntry(handle, certDBEntryTypeSubject, &dbkey); 2550 if (rv == SECFailure) { 2551 goto loser; 2552 } 2553 2554 PORT_FreeArena(arena, PR_FALSE); 2555 return (SECSuccess); 2556 2557 loser: 2558 if (arena) { 2559 PORT_FreeArena(arena, PR_FALSE); 2560 } 2561 2562 return (SECFailure); 2563 } 2564 2565 /* 2566 * Read the subject entry 2567 */ 2568 static certDBEntrySubject * 2569 ReadDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject) 2570 { 2571 /* |arena| isn't function-bounded, so cannot be a PORTCheapArenaPool. */ 2572 PLArenaPool *arena = NULL; 2573 PORTCheapArenaPool tmpArena; 2574 2575 certDBEntrySubject *entry; 2576 SECItem dbkey; 2577 SECItem dbentry; 2578 SECStatus rv; 2579 2580 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); 2581 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2582 if (arena == NULL) { 2583 PORT_SetError(SEC_ERROR_NO_MEMORY); 2584 goto loser; 2585 } 2586 2587 entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena, 2588 sizeof(certDBEntrySubject)); 2589 if (entry == NULL) { 2590 PORT_SetError(SEC_ERROR_NO_MEMORY); 2591 goto loser; 2592 } 2593 entry->common.arena = arena; 2594 entry->common.type = certDBEntryTypeSubject; 2595 2596 rv = EncodeDBSubjectKey(derSubject, &tmpArena.arena, &dbkey); 2597 if (rv != SECSuccess) { 2598 goto loser; 2599 } 2600 2601 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, &tmpArena.arena); 2602 if (rv == SECFailure) { 2603 goto loser; 2604 } 2605 2606 rv = DecodeDBSubjectEntry(entry, &dbentry, derSubject); 2607 if (rv == SECFailure) { 2608 goto loser; 2609 } 2610 2611 PORT_DestroyCheapArena(&tmpArena); 2612 return (entry); 2613 2614 loser: 2615 PORT_DestroyCheapArena(&tmpArena); 2616 if (arena) { 2617 PORT_FreeArena(arena, PR_FALSE); 2618 } 2619 2620 return (NULL); 2621 } 2622 2623 /* 2624 * Encode a subject name entry into byte stream suitable for 2625 * the database 2626 */ 2627 static SECStatus 2628 WriteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySubject *entry) 2629 { 2630 SECItem dbitem, dbkey; 2631 PLArenaPool *tmparena = NULL; 2632 SECStatus rv; 2633 2634 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2635 if (tmparena == NULL) { 2636 goto loser; 2637 } 2638 2639 rv = EncodeDBSubjectEntry(entry, tmparena, &dbitem); 2640 if (rv != SECSuccess) { 2641 goto loser; 2642 } 2643 2644 rv = EncodeDBSubjectKey(&entry->derSubject, tmparena, &dbkey); 2645 if (rv != SECSuccess) { 2646 goto loser; 2647 } 2648 2649 /* now write it to the database */ 2650 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 2651 if (rv != SECSuccess) { 2652 goto loser; 2653 } 2654 2655 PORT_FreeArena(tmparena, PR_FALSE); 2656 return (SECSuccess); 2657 2658 loser: 2659 if (tmparena) { 2660 PORT_FreeArena(tmparena, PR_FALSE); 2661 } 2662 return (SECFailure); 2663 } 2664 2665 typedef enum { nsslowcert_remove, 2666 nsslowcert_add } nsslowcertUpdateType; 2667 2668 static SECStatus 2669 nsslowcert_UpdateSubjectEmailAddr(NSSLOWCERTCertDBHandle *dbhandle, 2670 SECItem *derSubject, char *emailAddr, nsslowcertUpdateType updateType) 2671 { 2672 certDBEntrySubject *entry = NULL; 2673 int index = -1, i; 2674 SECStatus rv; 2675 2676 if (emailAddr) { 2677 emailAddr = nsslowcert_FixupEmailAddr(emailAddr); 2678 if (emailAddr == NULL) { 2679 return SECFailure; 2680 } 2681 } else { 2682 return SECSuccess; 2683 } 2684 2685 entry = ReadDBSubjectEntry(dbhandle, derSubject); 2686 if (entry == NULL) { 2687 rv = SECFailure; 2688 goto done; 2689 } 2690 2691 for (i = 0; i < (int)(entry->nemailAddrs); i++) { 2692 if (PORT_Strcmp(entry->emailAddrs[i], emailAddr) == 0) { 2693 index = i; 2694 } 2695 } 2696 2697 if (updateType == nsslowcert_remove) { 2698 if (index == -1) { 2699 rv = SECSuccess; 2700 goto done; 2701 } 2702 entry->nemailAddrs--; 2703 for (i = index; i < (int)(entry->nemailAddrs); i++) { 2704 entry->emailAddrs[i] = entry->emailAddrs[i + 1]; 2705 } 2706 } else { 2707 char **newAddrs = NULL; 2708 2709 if (index != -1) { 2710 rv = SECSuccess; 2711 goto done; 2712 } 2713 newAddrs = (char **)PORT_ArenaAlloc(entry->common.arena, 2714 (entry->nemailAddrs + 1) * sizeof(char *)); 2715 if (!newAddrs) { 2716 rv = SECFailure; 2717 goto done; 2718 } 2719 for (i = 0; i < (int)(entry->nemailAddrs); i++) { 2720 newAddrs[i] = entry->emailAddrs[i]; 2721 } 2722 newAddrs[entry->nemailAddrs] = 2723 PORT_ArenaStrdup(entry->common.arena, emailAddr); 2724 if (!newAddrs[entry->nemailAddrs]) { 2725 rv = SECFailure; 2726 goto done; 2727 } 2728 entry->emailAddrs = newAddrs; 2729 entry->nemailAddrs++; 2730 } 2731 2732 /* delete the subject entry */ 2733 DeleteDBSubjectEntry(dbhandle, derSubject); 2734 2735 /* write the new one */ 2736 rv = WriteDBSubjectEntry(dbhandle, entry); 2737 2738 done: 2739 if (entry) 2740 DestroyDBEntry((certDBEntry *)entry); 2741 if (emailAddr) 2742 PORT_Free(emailAddr); 2743 return rv; 2744 } 2745 2746 /* 2747 * writes a nickname to an existing subject entry that does not currently 2748 * have one 2749 */ 2750 static SECStatus 2751 AddNicknameToSubject(NSSLOWCERTCertDBHandle *dbhandle, 2752 NSSLOWCERTCertificate *cert, char *nickname) 2753 { 2754 certDBEntrySubject *entry; 2755 SECStatus rv; 2756 2757 if (nickname == NULL) { 2758 return (SECFailure); 2759 } 2760 2761 entry = ReadDBSubjectEntry(dbhandle, &cert->derSubject); 2762 PORT_Assert(entry != NULL); 2763 if (entry == NULL) { 2764 goto loser; 2765 } 2766 2767 PORT_Assert(entry->nickname == NULL); 2768 if (entry->nickname != NULL) { 2769 goto loser; 2770 } 2771 2772 entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname); 2773 2774 if (entry->nickname == NULL) { 2775 goto loser; 2776 } 2777 2778 /* delete the subject entry */ 2779 DeleteDBSubjectEntry(dbhandle, &cert->derSubject); 2780 2781 /* write the new one */ 2782 rv = WriteDBSubjectEntry(dbhandle, entry); 2783 if (rv != SECSuccess) { 2784 goto loser; 2785 } 2786 2787 DestroyDBEntry((certDBEntry *)entry); 2788 return (SECSuccess); 2789 2790 loser: 2791 DestroyDBEntry((certDBEntry *)entry); 2792 return (SECFailure); 2793 } 2794 2795 /* 2796 * create a new version entry 2797 */ 2798 static certDBEntryVersion * 2799 NewDBVersionEntry(unsigned int flags) 2800 { 2801 PLArenaPool *arena = NULL; 2802 certDBEntryVersion *entry; 2803 2804 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2805 if (arena == NULL) { 2806 PORT_SetError(SEC_ERROR_NO_MEMORY); 2807 goto loser; 2808 } 2809 2810 entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena, 2811 sizeof(certDBEntryVersion)); 2812 if (entry == NULL) { 2813 PORT_SetError(SEC_ERROR_NO_MEMORY); 2814 goto loser; 2815 } 2816 entry->common.arena = arena; 2817 entry->common.type = certDBEntryTypeVersion; 2818 entry->common.version = CERT_DB_FILE_VERSION; 2819 entry->common.flags = flags; 2820 2821 return (entry); 2822 loser: 2823 if (arena) { 2824 PORT_FreeArena(arena, PR_FALSE); 2825 } 2826 2827 return (NULL); 2828 } 2829 2830 /* 2831 * Read the version entry 2832 */ 2833 static certDBEntryVersion * 2834 ReadDBVersionEntry(NSSLOWCERTCertDBHandle *handle) 2835 { 2836 PLArenaPool *arena = NULL; 2837 PLArenaPool *tmparena = NULL; 2838 certDBEntryVersion *entry; 2839 SECItem dbkey; 2840 SECItem dbentry; 2841 SECStatus rv; 2842 2843 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2844 if (arena == NULL) { 2845 PORT_SetError(SEC_ERROR_NO_MEMORY); 2846 goto loser; 2847 } 2848 2849 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2850 if (tmparena == NULL) { 2851 PORT_SetError(SEC_ERROR_NO_MEMORY); 2852 goto loser; 2853 } 2854 2855 entry = PORT_ArenaZNew(arena, certDBEntryVersion); 2856 if (entry == NULL) { 2857 PORT_SetError(SEC_ERROR_NO_MEMORY); 2858 goto loser; 2859 } 2860 entry->common.arena = arena; 2861 entry->common.type = certDBEntryTypeVersion; 2862 2863 /* now get the database key and format it */ 2864 dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN; 2865 dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len); 2866 if (dbkey.data == NULL) { 2867 goto loser; 2868 } 2869 PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY, 2870 SEC_DB_VERSION_KEY_LEN); 2871 2872 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena); 2873 if (rv != SECSuccess) { 2874 goto loser; 2875 } 2876 2877 PORT_FreeArena(tmparena, PR_FALSE); 2878 return (entry); 2879 2880 loser: 2881 if (tmparena) { 2882 PORT_FreeArena(tmparena, PR_FALSE); 2883 } 2884 if (arena) { 2885 PORT_FreeArena(arena, PR_FALSE); 2886 } 2887 2888 return (NULL); 2889 } 2890 2891 /* 2892 * Encode a version entry into byte stream suitable for 2893 * the database 2894 */ 2895 static SECStatus 2896 WriteDBVersionEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryVersion *entry) 2897 { 2898 SECItem dbitem, dbkey; 2899 PLArenaPool *tmparena = NULL; 2900 SECStatus rv; 2901 2902 tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2903 if (tmparena == NULL) { 2904 goto loser; 2905 } 2906 2907 /* allocate space for encoded database record, including space 2908 * for low level header 2909 */ 2910 dbitem.len = SEC_DB_ENTRY_HEADER_LEN; 2911 2912 dbitem.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbitem.len); 2913 if (dbitem.data == NULL) { 2914 PORT_SetError(SEC_ERROR_NO_MEMORY); 2915 goto loser; 2916 } 2917 2918 /* now get the database key and format it */ 2919 dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN; 2920 dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len); 2921 if (dbkey.data == NULL) { 2922 goto loser; 2923 } 2924 PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY, 2925 SEC_DB_VERSION_KEY_LEN); 2926 2927 /* now write it to the database */ 2928 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 2929 if (rv != SECSuccess) { 2930 goto loser; 2931 } 2932 2933 PORT_FreeArena(tmparena, PR_FALSE); 2934 return (SECSuccess); 2935 2936 loser: 2937 if (tmparena) { 2938 PORT_FreeArena(tmparena, PR_FALSE); 2939 } 2940 return (SECFailure); 2941 } 2942 2943 /* 2944 * cert is no longer a perm cert, but will remain a temp cert 2945 */ 2946 static SECStatus 2947 RemovePermSubjectNode(NSSLOWCERTCertificate *cert) 2948 { 2949 certDBEntrySubject *entry; 2950 unsigned int i; 2951 SECStatus rv; 2952 2953 entry = ReadDBSubjectEntry(cert->dbhandle, &cert->derSubject); 2954 if (entry == NULL) { 2955 return (SECFailure); 2956 } 2957 2958 PORT_Assert(entry->ncerts); 2959 rv = SECFailure; 2960 2961 if (entry->ncerts > 1) { 2962 for (i = 0; i < entry->ncerts; i++) { 2963 if (SECITEM_CompareItem(&entry->certKeys[i], &cert->certKey) == 2964 SECEqual) { 2965 /* copy rest of list forward one entry */ 2966 for (i = i + 1; i < entry->ncerts; i++) { 2967 entry->certKeys[i - 1] = entry->certKeys[i]; 2968 entry->keyIDs[i - 1] = entry->keyIDs[i]; 2969 } 2970 entry->ncerts--; 2971 DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject); 2972 rv = WriteDBSubjectEntry(cert->dbhandle, entry); 2973 break; 2974 } 2975 } 2976 } else { 2977 /* no entries left, delete the perm entry in the DB */ 2978 if (entry->emailAddrs) { 2979 /* if the subject had an email record, then delete it too */ 2980 for (i = 0; i < entry->nemailAddrs; i++) { 2981 DeleteDBSMimeEntry(cert->dbhandle, entry->emailAddrs[i]); 2982 } 2983 } 2984 if (entry->nickname) { 2985 DeleteDBNicknameEntry(cert->dbhandle, entry->nickname); 2986 } 2987 2988 DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject); 2989 } 2990 DestroyDBEntry((certDBEntry *)entry); 2991 2992 return (rv); 2993 } 2994 2995 /* 2996 * add a cert to the perm subject list 2997 */ 2998 static SECStatus 2999 AddPermSubjectNode(certDBEntrySubject *entry, NSSLOWCERTCertificate *cert, 3000 char *nickname) 3001 { 3002 SECItem *newCertKeys, *newKeyIDs; 3003 unsigned int i, new_i; 3004 SECStatus rv; 3005 unsigned int ncerts; 3006 3007 PORT_Assert(entry); 3008 ncerts = entry->ncerts; 3009 3010 if (nickname && entry->nickname) { 3011 /* nicknames must be the same */ 3012 PORT_Assert(PORT_Strcmp(nickname, entry->nickname) == 0); 3013 } 3014 3015 if ((entry->nickname == NULL) && (nickname != NULL)) { 3016 /* copy nickname into the entry */ 3017 entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname); 3018 if (entry->nickname == NULL) { 3019 return (SECFailure); 3020 } 3021 } 3022 3023 /* a DB entry already exists, so add this cert */ 3024 newCertKeys = PORT_ArenaZNewArray(entry->common.arena, SECItem, ncerts + 1); 3025 newKeyIDs = PORT_ArenaZNewArray(entry->common.arena, SECItem, ncerts + 1); 3026 3027 if ((newCertKeys == NULL) || (newKeyIDs == NULL)) { 3028 return (SECFailure); 3029 } 3030 3031 /* Step 1: copy certs older than "cert" into new entry. */ 3032 for (i = 0, new_i = 0; i < ncerts; i++) { 3033 NSSLOWCERTCertificate *cmpcert; 3034 PRBool isNewer; 3035 cmpcert = nsslowcert_FindCertByKey(cert->dbhandle, 3036 &entry->certKeys[i]); 3037 /* The entry has been corrupted, remove it from the list */ 3038 if (!cmpcert) { 3039 continue; 3040 } 3041 3042 isNewer = nsslowcert_IsNewer(cert, cmpcert); 3043 nsslowcert_DestroyCertificate(cmpcert); 3044 if (isNewer) 3045 break; 3046 /* copy this cert entry */ 3047 newCertKeys[new_i] = entry->certKeys[i]; 3048 newKeyIDs[new_i] = entry->keyIDs[i]; 3049 new_i++; 3050 } 3051 3052 /* Step 2: Add "cert" to the entry. */ 3053 rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[new_i], 3054 &cert->certKey); 3055 if (rv != SECSuccess) { 3056 return (SECFailure); 3057 } 3058 rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[new_i], 3059 &cert->subjectKeyID); 3060 if (rv != SECSuccess) { 3061 return (SECFailure); 3062 } 3063 new_i++; 3064 3065 /* Step 3: copy remaining certs (if any) from old entry to new. */ 3066 for (; i < ncerts; i++, new_i++) { 3067 newCertKeys[new_i] = entry->certKeys[i]; 3068 newKeyIDs[new_i] = entry->keyIDs[i]; 3069 } 3070 3071 /* update certKeys and keyIDs */ 3072 entry->certKeys = newCertKeys; 3073 entry->keyIDs = newKeyIDs; 3074 3075 /* set new count value */ 3076 entry->ncerts = new_i; 3077 3078 DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject); 3079 rv = WriteDBSubjectEntry(cert->dbhandle, entry); 3080 return (rv); 3081 } 3082 3083 SECStatus 3084 nsslowcert_TraversePermCertsForSubject(NSSLOWCERTCertDBHandle *handle, 3085 SECItem *derSubject, 3086 NSSLOWCERTCertCallback cb, void *cbarg) 3087 { 3088 certDBEntrySubject *entry; 3089 unsigned int i; 3090 NSSLOWCERTCertificate *cert; 3091 SECStatus rv = SECSuccess; 3092 3093 entry = ReadDBSubjectEntry(handle, derSubject); 3094 3095 if (entry == NULL) { 3096 return (SECFailure); 3097 } 3098 3099 for (i = 0; i < entry->ncerts; i++) { 3100 cert = nsslowcert_FindCertByKey(handle, &entry->certKeys[i]); 3101 if (!cert) { 3102 continue; 3103 } 3104 rv = (*cb)(cert, cbarg); 3105 nsslowcert_DestroyCertificate(cert); 3106 if (rv == SECFailure) { 3107 break; 3108 } 3109 } 3110 3111 DestroyDBEntry((certDBEntry *)entry); 3112 3113 return (rv); 3114 } 3115 3116 int 3117 nsslowcert_NumPermCertsForSubject(NSSLOWCERTCertDBHandle *handle, 3118 SECItem *derSubject) 3119 { 3120 certDBEntrySubject *entry; 3121 int ret; 3122 3123 entry = ReadDBSubjectEntry(handle, derSubject); 3124 3125 if (entry == NULL) { 3126 return (SECFailure); 3127 } 3128 3129 ret = entry->ncerts; 3130 3131 DestroyDBEntry((certDBEntry *)entry); 3132 3133 return (ret); 3134 } 3135 3136 SECStatus 3137 nsslowcert_TraversePermCertsForNickname(NSSLOWCERTCertDBHandle *handle, 3138 char *nickname, NSSLOWCERTCertCallback cb, void *cbarg) 3139 { 3140 certDBEntryNickname *nnentry = NULL; 3141 certDBEntrySMime *smentry = NULL; 3142 SECStatus rv; 3143 SECItem *derSubject = NULL; 3144 3145 nnentry = ReadDBNicknameEntry(handle, nickname); 3146 if (nnentry) { 3147 derSubject = &nnentry->subjectName; 3148 } else { 3149 smentry = nsslowcert_ReadDBSMimeEntry(handle, nickname); 3150 if (smentry) { 3151 derSubject = &smentry->subjectName; 3152 } 3153 } 3154 3155 if (derSubject) { 3156 rv = nsslowcert_TraversePermCertsForSubject(handle, derSubject, 3157 cb, cbarg); 3158 } else { 3159 rv = SECFailure; 3160 } 3161 3162 if (nnentry) { 3163 DestroyDBEntry((certDBEntry *)nnentry); 3164 } 3165 if (smentry) { 3166 DestroyDBEntry((certDBEntry *)smentry); 3167 } 3168 3169 return (rv); 3170 } 3171 3172 int 3173 nsslowcert_NumPermCertsForNickname(NSSLOWCERTCertDBHandle *handle, 3174 char *nickname) 3175 { 3176 certDBEntryNickname *entry; 3177 int ret; 3178 3179 entry = ReadDBNicknameEntry(handle, nickname); 3180 3181 if (entry) { 3182 ret = nsslowcert_NumPermCertsForSubject(handle, &entry->subjectName); 3183 DestroyDBEntry((certDBEntry *)entry); 3184 } else { 3185 ret = 0; 3186 } 3187 return (ret); 3188 } 3189 3190 /* 3191 * add a nickname to a cert that doesn't have one 3192 */ 3193 static SECStatus 3194 AddNicknameToPermCert(NSSLOWCERTCertDBHandle *dbhandle, 3195 NSSLOWCERTCertificate *cert, char *nickname) 3196 { 3197 certDBEntryCert *entry; 3198 int rv; 3199 3200 entry = cert->dbEntry; 3201 PORT_Assert(entry != NULL); 3202 if (entry == NULL) { 3203 goto loser; 3204 } 3205 3206 pkcs11_freeNickname(entry->nickname, entry->nicknameSpace); 3207 entry->nickname = NULL; 3208 entry->nickname = pkcs11_copyNickname(nickname, entry->nicknameSpace, 3209 sizeof(entry->nicknameSpace)); 3210 3211 rv = WriteDBCertEntry(dbhandle, entry); 3212 if (rv) { 3213 goto loser; 3214 } 3215 3216 pkcs11_freeNickname(cert->nickname, cert->nicknameSpace); 3217 cert->nickname = NULL; 3218 cert->nickname = pkcs11_copyNickname(nickname, cert->nicknameSpace, 3219 sizeof(cert->nicknameSpace)); 3220 3221 return (SECSuccess); 3222 3223 loser: 3224 return (SECFailure); 3225 } 3226 3227 /* 3228 * add a nickname to a cert that is already in the perm database, but doesn't 3229 * have one yet (it is probably an e-mail cert). 3230 */ 3231 SECStatus 3232 nsslowcert_AddPermNickname(NSSLOWCERTCertDBHandle *dbhandle, 3233 NSSLOWCERTCertificate *cert, char *nickname) 3234 { 3235 SECStatus rv = SECFailure; 3236 certDBEntrySubject *entry = NULL; 3237 certDBEntryNickname *nicknameEntry = NULL; 3238 3239 nsslowcert_LockDB(dbhandle); 3240 3241 entry = ReadDBSubjectEntry(dbhandle, &cert->derSubject); 3242 if (entry == NULL) 3243 goto loser; 3244 3245 if (entry->nickname == NULL) { 3246 3247 /* no nickname for subject */ 3248 rv = AddNicknameToSubject(dbhandle, cert, nickname); 3249 if (rv != SECSuccess) { 3250 goto loser; 3251 } 3252 rv = AddNicknameToPermCert(dbhandle, cert, nickname); 3253 if (rv != SECSuccess) { 3254 goto loser; 3255 } 3256 nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0); 3257 if (nicknameEntry == NULL) { 3258 goto loser; 3259 } 3260 3261 rv = WriteDBNicknameEntry(dbhandle, nicknameEntry); 3262 if (rv != SECSuccess) { 3263 goto loser; 3264 } 3265 } else { 3266 /* subject already has a nickname */ 3267 rv = AddNicknameToPermCert(dbhandle, cert, entry->nickname); 3268 if (rv != SECSuccess) { 3269 goto loser; 3270 } 3271 /* make sure nickname entry exists. If the database was corrupted, 3272 * we may have lost the nickname entry. Add it back now */ 3273 nicknameEntry = ReadDBNicknameEntry(dbhandle, entry->nickname); 3274 if (nicknameEntry == NULL) { 3275 nicknameEntry = NewDBNicknameEntry(entry->nickname, 3276 &cert->derSubject, 0); 3277 if (nicknameEntry == NULL) { 3278 goto loser; 3279 } 3280 3281 rv = WriteDBNicknameEntry(dbhandle, nicknameEntry); 3282 if (rv != SECSuccess) { 3283 goto loser; 3284 } 3285 } 3286 } 3287 rv = SECSuccess; 3288 3289 loser: 3290 if (entry) { 3291 DestroyDBEntry((certDBEntry *)entry); 3292 } 3293 if (nicknameEntry) { 3294 DestroyDBEntry((certDBEntry *)nicknameEntry); 3295 } 3296 nsslowcert_UnlockDB(dbhandle); 3297 return (rv); 3298 } 3299 3300 static certDBEntryCert * 3301 AddCertToPermDB(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTCertificate *cert, 3302 char *nickname, NSSLOWCERTCertTrust *trust) 3303 { 3304 certDBEntryCert *certEntry = NULL; 3305 certDBEntryNickname *nicknameEntry = NULL; 3306 certDBEntrySubject *subjectEntry = NULL; 3307 int state = 0; 3308 SECStatus rv; 3309 PRBool donnentry = PR_FALSE; 3310 3311 if (nickname) { 3312 donnentry = PR_TRUE; 3313 } 3314 3315 subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject); 3316 3317 if (subjectEntry && subjectEntry->nickname) { 3318 donnentry = PR_FALSE; 3319 nickname = subjectEntry->nickname; 3320 } 3321 3322 certEntry = NewDBCertEntry(&cert->derCert, nickname, trust, 0); 3323 if (certEntry == NULL) { 3324 goto loser; 3325 } 3326 3327 if (donnentry) { 3328 nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0); 3329 if (nicknameEntry == NULL) { 3330 goto loser; 3331 } 3332 } 3333 3334 rv = WriteDBCertEntry(handle, certEntry); 3335 if (rv != SECSuccess) { 3336 goto loser; 3337 } 3338 state = 1; 3339 3340 if (nicknameEntry) { 3341 rv = WriteDBNicknameEntry(handle, nicknameEntry); 3342 if (rv != SECSuccess) { 3343 goto loser; 3344 } 3345 } 3346 3347 state = 2; 3348 3349 /* "Change" handles if necessary */ 3350 cert->dbhandle = handle; 3351 3352 /* add to or create new subject entry */ 3353 if (subjectEntry) { 3354 /* REWRITE BASED ON SUBJECT ENTRY */ 3355 rv = AddPermSubjectNode(subjectEntry, cert, nickname); 3356 if (rv != SECSuccess) { 3357 goto loser; 3358 } 3359 } else { 3360 /* make a new subject entry - this case is only used when updating 3361 * an old version of the database. This is OK because the oldnickname 3362 * db format didn't allow multiple certs with the same subject. 3363 */ 3364 /* where does subjectKeyID and certKey come from? */ 3365 subjectEntry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey, 3366 &cert->subjectKeyID, nickname, 3367 NULL, 0); 3368 if (subjectEntry == NULL) { 3369 goto loser; 3370 } 3371 rv = WriteDBSubjectEntry(handle, subjectEntry); 3372 if (rv != SECSuccess) { 3373 goto loser; 3374 } 3375 } 3376 3377 state = 3; 3378 3379 if (nicknameEntry) { 3380 DestroyDBEntry((certDBEntry *)nicknameEntry); 3381 } 3382 3383 if (subjectEntry) { 3384 DestroyDBEntry((certDBEntry *)subjectEntry); 3385 } 3386 3387 return (certEntry); 3388 3389 loser: 3390 /* don't leave partial entry in the database */ 3391 if (state > 0) { 3392 DeleteDBCertEntry(handle, &cert->certKey); 3393 } 3394 if ((state > 1) && donnentry) { 3395 DeleteDBNicknameEntry(handle, nickname); 3396 } 3397 if (certEntry) { 3398 DestroyDBEntry((certDBEntry *)certEntry); 3399 } 3400 if (nicknameEntry) { 3401 DestroyDBEntry((certDBEntry *)nicknameEntry); 3402 } 3403 if (subjectEntry) { 3404 DestroyDBEntry((certDBEntry *)subjectEntry); 3405 } 3406 3407 return (NULL); 3408 } 3409 3410 /* forward declaration */ 3411 static SECStatus 3412 UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb); 3413 3414 /* 3415 * version 8 uses the same schema as version 7. The only differences are 3416 * 1) version 8 db uses the blob shim to store data entries > 32k. 3417 * 2) version 8 db sets the db block size to 32k. 3418 * both of these are dealt with by the handle. 3419 */ 3420 3421 static SECStatus 3422 UpdateV8DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 3423 { 3424 return UpdateV7DB(handle, updatedb); 3425 } 3426 3427 /* 3428 * we could just blindly sequence through reading key data pairs and writing 3429 * them back out, but some cert.db's have gotten quite large and may have some 3430 * subtle corruption problems, so instead we cycle through the certs and 3431 * CRL's and S/MIME profiles and rebuild our subject lists from those records. 3432 */ 3433 static SECStatus 3434 UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 3435 { 3436 DBT key, data; 3437 int ret; 3438 NSSLOWCERTCertificate *cert; 3439 PRBool isKRL = PR_FALSE; 3440 certDBEntryType entryType; 3441 SECItem dbEntry, dbKey; 3442 certDBEntryRevocation crlEntry; 3443 certDBEntryCert certEntry; 3444 certDBEntrySMime smimeEntry; 3445 SECStatus rv; 3446 3447 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST); 3448 3449 if (ret) { 3450 return (SECFailure); 3451 } 3452 3453 do { 3454 unsigned char *dataBuf = (unsigned char *)data.data; 3455 unsigned char *keyBuf = (unsigned char *)key.data; 3456 dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN]; 3457 dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN; 3458 entryType = (certDBEntryType)keyBuf[0]; 3459 dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN]; 3460 dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN; 3461 if ((dbEntry.len <= 0) || (dbKey.len <= 0)) { 3462 continue; 3463 } 3464 3465 switch (entryType) { 3466 /* these entries will get regenerated as we read the 3467 * rest of the data from the database */ 3468 case certDBEntryTypeVersion: 3469 case certDBEntryTypeSubject: 3470 case certDBEntryTypeContentVersion: 3471 case certDBEntryTypeNickname: 3472 /* smime profiles need entries created after the certs have 3473 * been imported, loop over them in a second run */ 3474 case certDBEntryTypeSMimeProfile: 3475 break; 3476 3477 case certDBEntryTypeCert: 3478 /* decode Entry */ 3479 certEntry.common.version = (unsigned int)dataBuf[0]; 3480 certEntry.common.type = entryType; 3481 certEntry.common.flags = (unsigned int)dataBuf[2]; 3482 rv = DecodeDBCertEntry(&certEntry, &dbEntry); 3483 if (rv != SECSuccess) { 3484 break; 3485 } 3486 /* should we check for existing duplicates? */ 3487 cert = nsslowcert_DecodeDERCertificate(&certEntry.derCert, 3488 certEntry.nickname); 3489 if (cert) { 3490 nsslowcert_UpdatePermCert(handle, cert, certEntry.nickname, 3491 &certEntry.trust); 3492 nsslowcert_DestroyCertificate(cert); 3493 } 3494 /* free any data the decode may have allocated. */ 3495 pkcs11_freeStaticData(certEntry.derCert.data, 3496 certEntry.derCertSpace); 3497 pkcs11_freeNickname(certEntry.nickname, certEntry.nicknameSpace); 3498 break; 3499 3500 case certDBEntryTypeKeyRevocation: 3501 isKRL = PR_TRUE; 3502 /* fall through */ 3503 case certDBEntryTypeRevocation: 3504 crlEntry.common.version = (unsigned int)dataBuf[0]; 3505 crlEntry.common.type = entryType; 3506 crlEntry.common.flags = (unsigned int)dataBuf[2]; 3507 crlEntry.common.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 3508 if (crlEntry.common.arena == NULL) { 3509 break; 3510 } 3511 rv = DecodeDBCrlEntry(&crlEntry, &dbEntry); 3512 if (rv != SECSuccess) { 3513 break; 3514 } 3515 nsslowcert_UpdateCrl(handle, &crlEntry.derCrl, &dbKey, 3516 crlEntry.url, isKRL); 3517 /* free data allocated by the decode */ 3518 PORT_FreeArena(crlEntry.common.arena, PR_FALSE); 3519 crlEntry.common.arena = NULL; 3520 break; 3521 3522 default: 3523 break; 3524 } 3525 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0); 3526 3527 /* now loop again updating just the SMimeProfile. */ 3528 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST); 3529 3530 if (ret) { 3531 return (SECFailure); 3532 } 3533 3534 do { 3535 unsigned char *dataBuf = (unsigned char *)data.data; 3536 unsigned char *keyBuf = (unsigned char *)key.data; 3537 dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN]; 3538 dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN; 3539 entryType = (certDBEntryType)keyBuf[0]; 3540 if (entryType != certDBEntryTypeSMimeProfile) { 3541 continue; 3542 } 3543 dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN]; 3544 dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN; 3545 if ((dbEntry.len <= 0) || (dbKey.len <= 0)) { 3546 continue; 3547 } 3548 smimeEntry.common.version = (unsigned int)dataBuf[0]; 3549 smimeEntry.common.type = entryType; 3550 smimeEntry.common.flags = (unsigned int)dataBuf[2]; 3551 smimeEntry.common.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 3552 /* decode entry */ 3553 rv = DecodeDBSMimeEntry(&smimeEntry, &dbEntry, (char *)dbKey.data); 3554 if (rv == SECSuccess) { 3555 nsslowcert_UpdateSMimeProfile(handle, smimeEntry.emailAddr, 3556 &smimeEntry.subjectName, &smimeEntry.smimeOptions, 3557 &smimeEntry.optionsDate); 3558 } 3559 PORT_FreeArena(smimeEntry.common.arena, PR_FALSE); 3560 smimeEntry.common.arena = NULL; 3561 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0); 3562 3563 (*updatedb->close)(updatedb); 3564 3565 /* a database update is a good time to go back and verify the integrity of 3566 * the keys and certs */ 3567 handle->dbVerify = PR_TRUE; 3568 return (SECSuccess); 3569 } 3570 3571 /* 3572 * NOTE - Version 6 DB did not go out to the real world in a release, 3573 * so we can remove this function in a later release. 3574 */ 3575 static SECStatus 3576 UpdateV6DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 3577 { 3578 int ret; 3579 DBT key, data; 3580 unsigned char *buf, *tmpbuf = NULL; 3581 certDBEntryType type; 3582 certDBEntryNickname *nnEntry = NULL; 3583 certDBEntrySubject *subjectEntry = NULL; 3584 certDBEntrySMime *emailEntry = NULL; 3585 char *nickname; 3586 char *emailAddr; 3587 3588 /* 3589 * Sequence through the old database and copy all of the entries 3590 * to the new database. Subject name entries will have the new 3591 * fields inserted into them (with zero length). 3592 */ 3593 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST); 3594 if (ret) { 3595 return (SECFailure); 3596 } 3597 3598 do { 3599 buf = (unsigned char *)data.data; 3600 3601 if (data.size >= 3) { 3602 if (buf[0] == 6) { /* version number */ 3603 type = (certDBEntryType)buf[1]; 3604 if (type == certDBEntryTypeSubject) { 3605 /* expando subjecto entrieo */ 3606 tmpbuf = (unsigned char *)PORT_Alloc(data.size + 4); 3607 if (tmpbuf) { 3608 /* copy header stuff */ 3609 PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN + 2); 3610 /* insert 4 more bytes of zero'd header */ 3611 PORT_Memset(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 2], 3612 0, 4); 3613 /* copy rest of the data */ 3614 PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6], 3615 &buf[SEC_DB_ENTRY_HEADER_LEN + 2], 3616 data.size - (SEC_DB_ENTRY_HEADER_LEN + 2)); 3617 3618 data.data = (void *)tmpbuf; 3619 data.size += 4; 3620 buf = tmpbuf; 3621 } 3622 } else if (type == certDBEntryTypeCert) { 3623 /* expando certo entrieo */ 3624 tmpbuf = (unsigned char *)PORT_Alloc(data.size + 3); 3625 if (tmpbuf) { 3626 /* copy header stuff */ 3627 PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN); 3628 3629 /* copy trust flage, setting msb's to 0 */ 3630 tmpbuf[SEC_DB_ENTRY_HEADER_LEN] = 0; 3631 tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 1] = 3632 buf[SEC_DB_ENTRY_HEADER_LEN]; 3633 tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 2] = 0; 3634 tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 3] = 3635 buf[SEC_DB_ENTRY_HEADER_LEN + 1]; 3636 tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 4] = 0; 3637 tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 5] = 3638 buf[SEC_DB_ENTRY_HEADER_LEN + 2]; 3639 3640 /* copy rest of the data */ 3641 PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6], 3642 &buf[SEC_DB_ENTRY_HEADER_LEN + 3], 3643 data.size - (SEC_DB_ENTRY_HEADER_LEN + 3)); 3644 3645 data.data = (void *)tmpbuf; 3646 data.size += 3; 3647 buf = tmpbuf; 3648 } 3649 } 3650 3651 /* update the record version number */ 3652 buf[0] = CERT_DB_FILE_VERSION; 3653 3654 /* copy to the new database */ 3655 ret = certdb_Put(handle->permCertDB, &key, &data, 0); 3656 if (tmpbuf) { 3657 PORT_Free(tmpbuf); 3658 tmpbuf = NULL; 3659 } 3660 if (ret) { 3661 return SECFailure; 3662 } 3663 } 3664 } 3665 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0); 3666 3667 ret = certdb_Sync(handle->permCertDB, 0); 3668 if (ret) { 3669 return SECFailure; 3670 } 3671 3672 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST); 3673 if (ret) { 3674 return (SECFailure); 3675 } 3676 3677 do { 3678 buf = (unsigned char *)data.data; 3679 3680 if (data.size >= 3) { 3681 if (buf[0] == CERT_DB_FILE_VERSION) { /* version number */ 3682 type = (certDBEntryType)buf[1]; 3683 if (type == certDBEntryTypeNickname) { 3684 nickname = &((char *)key.data)[1]; 3685 3686 /* get the matching nickname entry in the new DB */ 3687 nnEntry = ReadDBNicknameEntry(handle, nickname); 3688 if (nnEntry == NULL) { 3689 goto endloop; 3690 } 3691 3692 /* find the subject entry pointed to by nickname */ 3693 subjectEntry = ReadDBSubjectEntry(handle, 3694 &nnEntry->subjectName); 3695 if (subjectEntry == NULL) { 3696 goto endloop; 3697 } 3698 3699 subjectEntry->nickname = 3700 (char *)PORT_ArenaAlloc(subjectEntry->common.arena, 3701 key.size - 1); 3702 if (subjectEntry->nickname) { 3703 PORT_Memcpy(subjectEntry->nickname, nickname, 3704 key.size - 1); 3705 (void)WriteDBSubjectEntry(handle, subjectEntry); 3706 } 3707 } else if (type == certDBEntryTypeSMimeProfile) { 3708 emailAddr = &((char *)key.data)[1]; 3709 3710 /* get the matching smime entry in the new DB */ 3711 emailEntry = nsslowcert_ReadDBSMimeEntry(handle, emailAddr); 3712 if (emailEntry == NULL) { 3713 goto endloop; 3714 } 3715 3716 /* find the subject entry pointed to by nickname */ 3717 subjectEntry = ReadDBSubjectEntry(handle, 3718 &emailEntry->subjectName); 3719 if (subjectEntry == NULL) { 3720 goto endloop; 3721 } 3722 3723 subjectEntry->emailAddrs = (char **) 3724 PORT_ArenaAlloc(subjectEntry->common.arena, 3725 sizeof(char *)); 3726 if (subjectEntry->emailAddrs) { 3727 subjectEntry->emailAddrs[0] = 3728 (char *)PORT_ArenaAlloc(subjectEntry->common.arena, 3729 key.size - 1); 3730 if (subjectEntry->emailAddrs[0]) { 3731 PORT_Memcpy(subjectEntry->emailAddrs[0], emailAddr, 3732 key.size - 1); 3733 subjectEntry->nemailAddrs = 1; 3734 (void)WriteDBSubjectEntry(handle, subjectEntry); 3735 } 3736 } 3737 } 3738 3739 endloop: 3740 if (subjectEntry) { 3741 DestroyDBEntry((certDBEntry *)subjectEntry); 3742 subjectEntry = NULL; 3743 } 3744 if (nnEntry) { 3745 DestroyDBEntry((certDBEntry *)nnEntry); 3746 nnEntry = NULL; 3747 } 3748 if (emailEntry) { 3749 DestroyDBEntry((certDBEntry *)emailEntry); 3750 emailEntry = NULL; 3751 } 3752 } 3753 } 3754 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0); 3755 3756 ret = certdb_Sync(handle->permCertDB, 0); 3757 if (ret) { 3758 return SECFailure; 3759 } 3760 3761 (*updatedb->close)(updatedb); 3762 return (SECSuccess); 3763 } 3764 3765 static SECStatus 3766 updateV5Callback(NSSLOWCERTCertificate *cert, SECItem *k, void *pdata) 3767 { 3768 NSSLOWCERTCertDBHandle *handle; 3769 certDBEntryCert *entry; 3770 NSSLOWCERTCertTrust *trust; 3771 3772 handle = (NSSLOWCERTCertDBHandle *)pdata; 3773 trust = &cert->dbEntry->trust; 3774 3775 /* SSL user certs can be used for email if they have an email addr */ 3776 if (cert->emailAddr && (trust->sslFlags & CERTDB_USER) && 3777 (trust->emailFlags == 0)) { 3778 trust->emailFlags = CERTDB_USER; 3779 } 3780 /* servers didn't set the user flags on the server cert.. */ 3781 if (PORT_Strcmp(cert->dbEntry->nickname, "Server-Cert") == 0) { 3782 trust->sslFlags |= CERTDB_USER; 3783 } 3784 3785 entry = AddCertToPermDB(handle, cert, cert->dbEntry->nickname, 3786 &cert->dbEntry->trust); 3787 if (entry) { 3788 DestroyDBEntry((certDBEntry *)entry); 3789 } 3790 3791 return (SECSuccess); 3792 } 3793 3794 static SECStatus 3795 UpdateV5DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 3796 { 3797 NSSLOWCERTCertDBHandle updatehandle; 3798 3799 updatehandle.permCertDB = updatedb; 3800 updatehandle.dbMon = PZ_NewMonitor(nssILockCertDB); 3801 updatehandle.dbVerify = 0; 3802 updatehandle.ref = 1; /* prevent premature close */ 3803 3804 (void)nsslowcert_TraversePermCerts(&updatehandle, updateV5Callback, 3805 (void *)handle); 3806 3807 PZ_DestroyMonitor(updatehandle.dbMon); 3808 3809 (*updatedb->close)(updatedb); 3810 return (SECSuccess); 3811 } 3812 3813 static PRBool 3814 isV4DB(DB *db) 3815 { 3816 DBT key, data; 3817 int ret; 3818 3819 key.data = "Version"; 3820 key.size = 7; 3821 3822 ret = (*db->get)(db, &key, &data, 0); 3823 if (ret) { 3824 return PR_FALSE; 3825 } 3826 3827 if ((data.size == 1) && (*(unsigned char *)data.data <= 4)) { 3828 return PR_TRUE; 3829 } 3830 3831 return PR_FALSE; 3832 } 3833 3834 static SECStatus 3835 UpdateV4DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 3836 { 3837 DBT key, data; 3838 certDBEntryCert *entry, *entry2; 3839 int ret; 3840 NSSLOWCERTCertificate *cert; 3841 3842 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST); 3843 3844 if (ret) { 3845 return (SECFailure); 3846 } 3847 3848 do { 3849 if (data.size != 1) { /* skip version number */ 3850 3851 /* decode the old DB entry */ 3852 entry = (certDBEntryCert *) 3853 DecodeV4DBCertEntry((unsigned char *)data.data, data.size); 3854 3855 if (entry) { 3856 cert = nsslowcert_DecodeDERCertificate(&entry->derCert, 3857 entry->nickname); 3858 3859 if (cert != NULL) { 3860 /* add to new database */ 3861 entry2 = AddCertToPermDB(handle, cert, entry->nickname, 3862 &entry->trust); 3863 3864 nsslowcert_DestroyCertificate(cert); 3865 if (entry2) { 3866 DestroyDBEntry((certDBEntry *)entry2); 3867 } 3868 } 3869 DestroyDBEntry((certDBEntry *)entry); 3870 } 3871 } 3872 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0); 3873 3874 (*updatedb->close)(updatedb); 3875 return (SECSuccess); 3876 } 3877 3878 /* 3879 * return true if a database key conflict exists 3880 */ 3881 PRBool 3882 nsslowcert_CertDBKeyConflict(SECItem *derCert, NSSLOWCERTCertDBHandle *handle) 3883 { 3884 SECStatus rv; 3885 DBT tmpdata; 3886 DBT namekey; 3887 int ret; 3888 SECItem keyitem; 3889 PLArenaPool *arena = NULL; 3890 SECItem derKey; 3891 3892 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 3893 if (arena == NULL) { 3894 goto loser; 3895 } 3896 3897 /* get the db key of the cert */ 3898 rv = nsslowcert_KeyFromDERCert(arena, derCert, &derKey); 3899 if (rv != SECSuccess) { 3900 goto loser; 3901 } 3902 3903 rv = EncodeDBCertKey(&derKey, arena, &keyitem); 3904 if (rv != SECSuccess) { 3905 goto loser; 3906 } 3907 3908 namekey.data = keyitem.data; 3909 namekey.size = keyitem.len; 3910 3911 ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0); 3912 if (ret == 0) { 3913 goto loser; 3914 } 3915 3916 PORT_FreeArena(arena, PR_FALSE); 3917 3918 return (PR_FALSE); 3919 loser: 3920 if (arena) { 3921 PORT_FreeArena(arena, PR_FALSE); 3922 } 3923 3924 return (PR_TRUE); 3925 } 3926 3927 /* 3928 * return true if a nickname conflict exists 3929 * NOTE: caller must have already made sure that this exact cert 3930 * doesn't exist in the DB 3931 */ 3932 static PRBool 3933 nsslowcert_CertNicknameConflict(char *nickname, SECItem *derSubject, 3934 NSSLOWCERTCertDBHandle *handle) 3935 { 3936 PRBool rv; 3937 certDBEntryNickname *entry; 3938 3939 if (nickname == NULL) { 3940 return (PR_FALSE); 3941 } 3942 3943 entry = ReadDBNicknameEntry(handle, nickname); 3944 3945 if (entry == NULL) { 3946 /* no entry for this nickname, so no conflict */ 3947 return (PR_FALSE); 3948 } 3949 3950 rv = PR_TRUE; 3951 if (SECITEM_CompareItem(derSubject, &entry->subjectName) == SECEqual) { 3952 /* if subject names are the same, then no conflict */ 3953 rv = PR_FALSE; 3954 } 3955 3956 DestroyDBEntry((certDBEntry *)entry); 3957 return (rv); 3958 } 3959 3960 #ifdef DBM_USING_NSPR 3961 #define NO_RDONLY PR_RDONLY 3962 #define NO_RDWR PR_RDWR 3963 #define NO_CREATE (PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE) 3964 #else 3965 #define NO_RDONLY O_RDONLY 3966 #define NO_RDWR O_RDWR 3967 #define NO_CREATE (O_RDWR | O_CREAT | O_TRUNC) 3968 #endif 3969 3970 /* 3971 * open an old database that needs to be updated 3972 */ 3973 static DB * 3974 nsslowcert_openolddb(NSSLOWCERTDBNameFunc namecb, void *cbarg, int version) 3975 { 3976 char *tmpname; 3977 DB *updatedb = NULL; 3978 3979 tmpname = (*namecb)(cbarg, version); /* get v6 db name */ 3980 if (tmpname) { 3981 updatedb = dbopen(tmpname, NO_RDONLY, 0600, DB_HASH, 0); 3982 PORT_Free(tmpname); 3983 } 3984 return updatedb; 3985 } 3986 3987 static SECStatus 3988 openNewCertDB(const char *appName, const char *prefix, const char *certdbname, 3989 NSSLOWCERTCertDBHandle *handle, NSSLOWCERTDBNameFunc namecb, void *cbarg) 3990 { 3991 SECStatus rv; 3992 certDBEntryVersion *versionEntry = NULL; 3993 DB *updatedb = NULL; 3994 int status = RDB_FAIL; 3995 3996 if (appName) { 3997 handle->permCertDB = rdbopen(appName, prefix, "cert", NO_CREATE, &status); 3998 } else { 3999 handle->permCertDB = dbsopen(certdbname, NO_CREATE, 0600, DB_HASH, 0); 4000 } 4001 4002 /* if create fails then we lose */ 4003 if (handle->permCertDB == 0) { 4004 return status == RDB_RETRY ? SECWouldBlock : SECFailure; 4005 } 4006 4007 /* Verify version number; */ 4008 versionEntry = NewDBVersionEntry(0); 4009 if (versionEntry == NULL) { 4010 rv = SECFailure; 4011 goto loser; 4012 } 4013 4014 rv = WriteDBVersionEntry(handle, versionEntry); 4015 4016 DestroyDBEntry((certDBEntry *)versionEntry); 4017 4018 if (rv != SECSuccess) { 4019 goto loser; 4020 } 4021 4022 /* rv must already be Success here because of previous if statement */ 4023 /* try to upgrade old db here */ 4024 if (appName && 4025 (updatedb = dbsopen(certdbname, NO_RDONLY, 0600, DB_HASH, 0)) != NULL) { 4026 rv = UpdateV8DB(handle, updatedb); 4027 } else if ((updatedb = nsslowcert_openolddb(namecb, cbarg, 7)) != NULL) { 4028 rv = UpdateV7DB(handle, updatedb); 4029 } else if ((updatedb = nsslowcert_openolddb(namecb, cbarg, 6)) != NULL) { 4030 rv = UpdateV6DB(handle, updatedb); 4031 } else if ((updatedb = nsslowcert_openolddb(namecb, cbarg, 5)) != NULL) { 4032 rv = UpdateV5DB(handle, updatedb); 4033 } else if ((updatedb = nsslowcert_openolddb(namecb, cbarg, 4)) != NULL) { 4034 /* NES has v5 format db's with v4 db names! */ 4035 if (isV4DB(updatedb)) { 4036 rv = UpdateV4DB(handle, updatedb); 4037 } else { 4038 rv = UpdateV5DB(handle, updatedb); 4039 } 4040 } 4041 4042 loser: 4043 db_InitComplete(handle->permCertDB); 4044 return rv; 4045 } 4046 4047 static int 4048 nsslowcert_GetVersionNumber(NSSLOWCERTCertDBHandle *handle) 4049 { 4050 certDBEntryVersion *versionEntry = NULL; 4051 int version = 0; 4052 4053 versionEntry = ReadDBVersionEntry(handle); 4054 if (versionEntry == NULL) { 4055 return 0; 4056 } 4057 version = versionEntry->common.version; 4058 DestroyDBEntry((certDBEntry *)versionEntry); 4059 return version; 4060 } 4061 4062 /* 4063 * Open the certificate database and index databases. Create them if 4064 * they are not there or bad. 4065 */ 4066 static SECStatus 4067 nsslowcert_OpenPermCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly, 4068 const char *appName, const char *prefix, 4069 NSSLOWCERTDBNameFunc namecb, void *cbarg) 4070 { 4071 SECStatus rv; 4072 int openflags; 4073 char *certdbname; 4074 int version = 0; 4075 4076 certdbname = (*namecb)(cbarg, CERT_DB_FILE_VERSION); 4077 if (certdbname == NULL) { 4078 return (SECFailure); 4079 } 4080 4081 openflags = readOnly ? NO_RDONLY : NO_RDWR; 4082 4083 /* 4084 * first open the permanent file based database. 4085 */ 4086 if (appName) { 4087 handle->permCertDB = rdbopen(appName, prefix, "cert", openflags, NULL); 4088 } else { 4089 handle->permCertDB = dbsopen(certdbname, openflags, 0600, DB_HASH, 0); 4090 } 4091 4092 /* check for correct version number */ 4093 if (handle->permCertDB) { 4094 version = nsslowcert_GetVersionNumber(handle); 4095 if ((version != CERT_DB_FILE_VERSION) && 4096 !(appName && version == CERT_DB_V7_FILE_VERSION)) { 4097 goto loser; 4098 } 4099 } else if (readOnly) { 4100 /* don't create if readonly */ 4101 /* Try openning a version 7 database */ 4102 handle->permCertDB = nsslowcert_openolddb(namecb, cbarg, 7); 4103 if (!handle->permCertDB) { 4104 goto loser; 4105 } 4106 if (nsslowcert_GetVersionNumber(handle) != 7) { 4107 goto loser; 4108 } 4109 } else { 4110 /* if first open fails, try to create a new DB */ 4111 rv = openNewCertDB(appName, prefix, certdbname, handle, namecb, cbarg); 4112 if (rv == SECWouldBlock) { 4113 /* only the rdb version can fail with wouldblock */ 4114 handle->permCertDB = 4115 rdbopen(appName, prefix, "cert", openflags, NULL); 4116 4117 /* check for correct version number */ 4118 if (!handle->permCertDB) { 4119 goto loser; 4120 } 4121 version = nsslowcert_GetVersionNumber(handle); 4122 if ((version != CERT_DB_FILE_VERSION) && 4123 !(appName && version == CERT_DB_V7_FILE_VERSION)) { 4124 goto loser; 4125 } 4126 } else if (rv != SECSuccess) { 4127 goto loser; 4128 } 4129 } 4130 4131 PORT_Free(certdbname); 4132 4133 return (SECSuccess); 4134 4135 loser: 4136 4137 PORT_SetError(SEC_ERROR_BAD_DATABASE); 4138 4139 if (handle->permCertDB) { 4140 certdb_Close(handle->permCertDB); 4141 handle->permCertDB = 0; 4142 } 4143 4144 PORT_Free(certdbname); 4145 4146 return (SECFailure); 4147 } 4148 4149 /* 4150 * delete all DB records associated with a particular certificate 4151 */ 4152 static SECStatus 4153 DeletePermCert(NSSLOWCERTCertificate *cert) 4154 { 4155 SECStatus rv; 4156 SECStatus ret; 4157 4158 ret = SECSuccess; 4159 4160 rv = DeleteDBCertEntry(cert->dbhandle, &cert->certKey); 4161 if (rv != SECSuccess) { 4162 ret = SECFailure; 4163 } 4164 4165 rv = RemovePermSubjectNode(cert); 4166 4167 return (ret); 4168 } 4169 4170 /* 4171 * Delete a certificate from the permanent database. 4172 */ 4173 SECStatus 4174 nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert) 4175 { 4176 SECStatus rv; 4177 4178 nsslowcert_LockDB(cert->dbhandle); 4179 4180 /* delete the records from the permanent database */ 4181 rv = DeletePermCert(cert); 4182 4183 /* get rid of dbcert and stuff pointing to it */ 4184 DestroyDBEntry((certDBEntry *)cert->dbEntry); 4185 cert->dbEntry = NULL; 4186 cert->trust = NULL; 4187 4188 nsslowcert_UnlockDB(cert->dbhandle); 4189 return (rv); 4190 } 4191 4192 /* 4193 * Traverse all of the entries in the database of a particular type 4194 * call the given function for each one. 4195 */ 4196 SECStatus 4197 nsslowcert_TraverseDBEntries(NSSLOWCERTCertDBHandle *handle, 4198 certDBEntryType type, 4199 SECStatus (*callback)(SECItem *data, SECItem *key, 4200 certDBEntryType type, void *pdata), 4201 void *udata) 4202 { 4203 DBT data; 4204 DBT key; 4205 SECStatus rv = SECSuccess; 4206 int ret; 4207 SECItem dataitem; 4208 SECItem keyitem; 4209 unsigned char *buf; 4210 unsigned char *keybuf; 4211 4212 ret = certdb_Seq(handle->permCertDB, &key, &data, R_FIRST); 4213 if (ret) { 4214 return (SECFailure); 4215 } 4216 /* here, ret is zero and rv is SECSuccess. 4217 * Below here, ret is a count of successful calls to the callback function. 4218 */ 4219 do { 4220 buf = (unsigned char *)data.data; 4221 4222 if (buf[1] == (unsigned char)type) { 4223 dataitem.len = data.size; 4224 dataitem.data = buf; 4225 dataitem.type = siBuffer; 4226 keyitem.len = key.size - SEC_DB_KEY_HEADER_LEN; 4227 keybuf = (unsigned char *)key.data; 4228 keyitem.data = &keybuf[SEC_DB_KEY_HEADER_LEN]; 4229 keyitem.type = siBuffer; 4230 /* type should equal keybuf[0]. */ 4231 4232 rv = (*callback)(&dataitem, &keyitem, type, udata); 4233 if (rv == SECSuccess) { 4234 ++ret; 4235 } 4236 } 4237 } while (certdb_Seq(handle->permCertDB, &key, &data, R_NEXT) == 0); 4238 /* If any callbacks succeeded, or no calls to callbacks were made, 4239 * then report success. Otherwise, report failure. 4240 */ 4241 return (ret ? SECSuccess : rv); 4242 } 4243 /* 4244 * Decode a certificate and enter it into the temporary certificate database. 4245 * Deal with nicknames correctly 4246 * 4247 * This is the private entry point. 4248 */ 4249 static NSSLOWCERTCertificate * 4250 DecodeACert(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry) 4251 { 4252 NSSLOWCERTCertificate *cert = NULL; 4253 4254 cert = nsslowcert_DecodeDERCertificate(&entry->derCert, entry->nickname); 4255 4256 if (cert == NULL) { 4257 goto loser; 4258 } 4259 4260 cert->dbhandle = handle; 4261 cert->dbEntry = entry; 4262 cert->trust = &entry->trust; 4263 4264 return (cert); 4265 4266 loser: 4267 return (0); 4268 } 4269 4270 static NSSLOWCERTTrust * 4271 CreateTrust(void) 4272 { 4273 NSSLOWCERTTrust *trust = NULL; 4274 4275 nsslowcert_LockFreeList(); 4276 trust = trustListHead; 4277 if (trust) { 4278 trustListCount--; 4279 trustListHead = trust->next; 4280 trust->next = NULL; 4281 } 4282 PORT_Assert(trustListCount >= 0); 4283 nsslowcert_UnlockFreeList(); 4284 if (trust) { 4285 return trust; 4286 } 4287 4288 return PORT_ZNew(NSSLOWCERTTrust); 4289 } 4290 4291 static void 4292 DestroyTrustFreeList(void) 4293 { 4294 NSSLOWCERTTrust *trust; 4295 4296 nsslowcert_LockFreeList(); 4297 while (NULL != (trust = trustListHead)) { 4298 trustListCount--; 4299 trustListHead = trust->next; 4300 PORT_Free(trust); 4301 } 4302 PORT_Assert(!trustListCount); 4303 trustListCount = 0; 4304 nsslowcert_UnlockFreeList(); 4305 } 4306 4307 static NSSLOWCERTTrust * 4308 DecodeTrustEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry, 4309 const SECItem *dbKey) 4310 { 4311 NSSLOWCERTTrust *trust = CreateTrust(); 4312 if (trust == NULL) { 4313 return trust; 4314 } 4315 trust->dbhandle = handle; 4316 trust->dbEntry = entry; 4317 trust->dbKey.data = pkcs11_copyStaticData(dbKey->data, dbKey->len, 4318 trust->dbKeySpace, sizeof(trust->dbKeySpace)); 4319 if (!trust->dbKey.data) { 4320 PORT_Free(trust); 4321 return NULL; 4322 } 4323 trust->dbKey.len = dbKey->len; 4324 4325 trust->trust = &entry->trust; 4326 trust->derCert = &entry->derCert; 4327 4328 return (trust); 4329 } 4330 4331 typedef struct { 4332 PermCertCallback certfunc; 4333 NSSLOWCERTCertDBHandle *handle; 4334 void *data; 4335 } PermCertCallbackState; 4336 4337 /* 4338 * traversal callback to decode certs and call callers callback 4339 */ 4340 static SECStatus 4341 certcallback(SECItem *dbdata, SECItem *dbkey, certDBEntryType type, void *data) 4342 { 4343 PermCertCallbackState *mystate; 4344 SECStatus rv; 4345 certDBEntryCert *entry; 4346 SECItem entryitem; 4347 NSSLOWCERTCertificate *cert; 4348 PLArenaPool *arena = NULL; 4349 4350 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 4351 if (arena == NULL) { 4352 goto loser; 4353 } 4354 4355 entry = (certDBEntryCert *)PORT_ArenaAlloc(arena, sizeof(certDBEntryCert)); 4356 if (!entry) { 4357 PORT_SetError(SEC_ERROR_NO_MEMORY); 4358 goto loser; 4359 } 4360 mystate = (PermCertCallbackState *)data; 4361 entry->common.version = (unsigned int)dbdata->data[0]; 4362 entry->common.type = (certDBEntryType)dbdata->data[1]; 4363 entry->common.flags = (unsigned int)dbdata->data[2]; 4364 entry->common.arena = arena; 4365 4366 entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN; 4367 entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN]; 4368 4369 rv = DecodeDBCertEntry(entry, &entryitem); 4370 if (rv != SECSuccess) { 4371 goto loser; 4372 } 4373 entry->derCert.type = siBuffer; 4374 4375 /* note: Entry is 'inheritted'. */ 4376 cert = DecodeACert(mystate->handle, entry); 4377 4378 rv = (*mystate->certfunc)(cert, dbkey, mystate->data); 4379 4380 /* arena stored in entry destroyed by nsslowcert_DestroyCertificate */ 4381 nsslowcert_DestroyCertificateNoLocking(cert); 4382 4383 return (rv); 4384 4385 loser: 4386 if (arena) { 4387 PORT_FreeArena(arena, PR_FALSE); 4388 } 4389 return (SECFailure); 4390 } 4391 4392 /* 4393 * Traverse all of the certificates in the permanent database and 4394 * call the given function for each one; expect the caller to have lock. 4395 */ 4396 static SECStatus 4397 TraversePermCertsNoLocking(NSSLOWCERTCertDBHandle *handle, 4398 SECStatus (*certfunc)(NSSLOWCERTCertificate *cert, 4399 SECItem *k, 4400 void *pdata), 4401 void *udata) 4402 { 4403 SECStatus rv; 4404 PermCertCallbackState mystate; 4405 4406 mystate.certfunc = certfunc; 4407 mystate.handle = handle; 4408 mystate.data = udata; 4409 rv = nsslowcert_TraverseDBEntries(handle, certDBEntryTypeCert, certcallback, 4410 (void *)&mystate); 4411 4412 return (rv); 4413 } 4414 4415 /* 4416 * Traverse all of the certificates in the permanent database and 4417 * call the given function for each one. 4418 */ 4419 SECStatus 4420 nsslowcert_TraversePermCerts(NSSLOWCERTCertDBHandle *handle, 4421 SECStatus (*certfunc)(NSSLOWCERTCertificate *cert, SECItem *k, 4422 void *pdata), 4423 void *udata) 4424 { 4425 SECStatus rv; 4426 4427 nsslowcert_LockDB(handle); 4428 rv = TraversePermCertsNoLocking(handle, certfunc, udata); 4429 nsslowcert_UnlockDB(handle); 4430 4431 return (rv); 4432 } 4433 4434 /* 4435 * Close the database 4436 */ 4437 void 4438 nsslowcert_ClosePermCertDB(NSSLOWCERTCertDBHandle *handle) 4439 { 4440 if (handle) { 4441 if (handle->permCertDB) { 4442 certdb_Close(handle->permCertDB); 4443 handle->permCertDB = NULL; 4444 } 4445 if (handle->dbMon) { 4446 PZ_DestroyMonitor(handle->dbMon); 4447 handle->dbMon = NULL; 4448 } 4449 PORT_Free(handle); 4450 } 4451 return; 4452 } 4453 4454 /* 4455 * Get the trust attributes from a certificate 4456 */ 4457 SECStatus 4458 nsslowcert_GetCertTrust(NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust) 4459 { 4460 SECStatus rv; 4461 4462 nsslowcert_LockCertTrust(cert); 4463 4464 if (cert->trust == NULL) { 4465 rv = SECFailure; 4466 } else { 4467 *trust = *cert->trust; 4468 rv = SECSuccess; 4469 } 4470 4471 nsslowcert_UnlockCertTrust(cert); 4472 return (rv); 4473 } 4474 4475 /* 4476 * Change the trust attributes of a certificate and make them permanent 4477 * in the database. 4478 */ 4479 SECStatus 4480 nsslowcert_ChangeCertTrust(NSSLOWCERTCertDBHandle *handle, 4481 NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust) 4482 { 4483 certDBEntryCert *entry; 4484 int rv; 4485 SECStatus ret; 4486 4487 nsslowcert_LockDB(handle); 4488 nsslowcert_LockCertTrust(cert); 4489 /* only set the trust on permanent certs */ 4490 if (cert->trust == NULL) { 4491 ret = SECFailure; 4492 goto done; 4493 } 4494 4495 *cert->trust = *trust; 4496 if (cert->dbEntry == NULL) { 4497 ret = SECSuccess; /* not in permanent database */ 4498 goto done; 4499 } 4500 4501 entry = cert->dbEntry; 4502 entry->trust = *trust; 4503 4504 rv = WriteDBCertEntry(handle, entry); 4505 if (rv) { 4506 ret = SECFailure; 4507 goto done; 4508 } 4509 4510 ret = SECSuccess; 4511 4512 done: 4513 nsslowcert_UnlockCertTrust(cert); 4514 nsslowcert_UnlockDB(handle); 4515 return (ret); 4516 } 4517 4518 static SECStatus 4519 nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle, 4520 NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust) 4521 { 4522 char *oldnn; 4523 certDBEntryCert *entry; 4524 PRBool conflict; 4525 SECStatus ret; 4526 4527 PORT_Assert(!cert->dbEntry); 4528 4529 /* don't add a conflicting nickname */ 4530 conflict = nsslowcert_CertNicknameConflict(nickname, &cert->derSubject, 4531 dbhandle); 4532 if (conflict) { 4533 ret = SECFailure; 4534 goto done; 4535 } 4536 4537 /* save old nickname so that we can delete it */ 4538 oldnn = cert->nickname; 4539 4540 entry = AddCertToPermDB(dbhandle, cert, nickname, trust); 4541 4542 if (entry == NULL) { 4543 ret = SECFailure; 4544 goto done; 4545 } 4546 4547 pkcs11_freeNickname(oldnn, cert->nicknameSpace); 4548 4549 cert->nickname = (entry->nickname) ? pkcs11_copyNickname(entry->nickname, 4550 cert->nicknameSpace, sizeof(cert->nicknameSpace)) 4551 : NULL; 4552 cert->trust = &entry->trust; 4553 cert->dbEntry = entry; 4554 4555 ret = SECSuccess; 4556 done: 4557 return (ret); 4558 } 4559 4560 SECStatus 4561 nsslowcert_AddPermCert(NSSLOWCERTCertDBHandle *dbhandle, 4562 NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust) 4563 { 4564 SECStatus ret; 4565 4566 nsslowcert_LockDB(dbhandle); 4567 4568 ret = nsslowcert_UpdatePermCert(dbhandle, cert, nickname, trust); 4569 4570 nsslowcert_UnlockDB(dbhandle); 4571 return (ret); 4572 } 4573 4574 /* 4575 * Open the certificate database and index databases. Create them if 4576 * they are not there or bad. 4577 */ 4578 SECStatus 4579 nsslowcert_OpenCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly, 4580 const char *appName, const char *prefix, 4581 NSSLOWCERTDBNameFunc namecb, void *cbarg, PRBool openVolatile) 4582 { 4583 int rv; 4584 4585 certdb_InitDBLock(handle); 4586 4587 handle->dbMon = PZ_NewMonitor(nssILockCertDB); 4588 PORT_Assert(handle->dbMon != NULL); 4589 handle->dbVerify = PR_FALSE; 4590 4591 rv = nsslowcert_OpenPermCertDB(handle, readOnly, appName, prefix, 4592 namecb, cbarg); 4593 if (rv) { 4594 goto loser; 4595 } 4596 4597 return (SECSuccess); 4598 4599 loser: 4600 if (handle->dbMon) { 4601 PZ_DestroyMonitor(handle->dbMon); 4602 handle->dbMon = NULL; 4603 } 4604 PORT_SetError(SEC_ERROR_BAD_DATABASE); 4605 return (SECFailure); 4606 } 4607 4608 PRBool 4609 nsslowcert_needDBVerify(NSSLOWCERTCertDBHandle *handle) 4610 { 4611 if (!handle) 4612 return PR_FALSE; 4613 return handle->dbVerify; 4614 } 4615 4616 void 4617 nsslowcert_setDBVerify(NSSLOWCERTCertDBHandle *handle, PRBool value) 4618 { 4619 handle->dbVerify = value; 4620 } 4621 4622 /* 4623 * Lookup a certificate in the databases. 4624 */ 4625 static NSSLOWCERTCertificate * 4626 FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb) 4627 { 4628 NSSLOWCERTCertificate *cert = NULL; 4629 certDBEntryCert *entry; 4630 PRBool locked = PR_FALSE; 4631 4632 if (lockdb) { 4633 locked = PR_TRUE; 4634 nsslowcert_LockDB(handle); 4635 } 4636 4637 /* find in perm database */ 4638 entry = ReadDBCertEntry(handle, certKey); 4639 4640 if (entry == NULL) { 4641 goto loser; 4642 } 4643 4644 /* inherit entry */ 4645 cert = DecodeACert(handle, entry); 4646 4647 loser: 4648 if (cert == NULL) { 4649 if (entry) { 4650 DestroyDBEntry((certDBEntry *)entry); 4651 } 4652 } 4653 4654 if (locked) { 4655 nsslowcert_UnlockDB(handle); 4656 } 4657 4658 return (cert); 4659 } 4660 4661 /* 4662 * Lookup a certificate in the databases. 4663 */ 4664 static NSSLOWCERTTrust * 4665 FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb) 4666 { 4667 NSSLOWCERTTrust *trust = NULL; 4668 certDBEntryCert *entry; 4669 PRBool locked = PR_FALSE; 4670 4671 if (lockdb) { 4672 locked = PR_TRUE; 4673 nsslowcert_LockDB(handle); 4674 } 4675 4676 /* find in perm database */ 4677 entry = ReadDBCertEntry(handle, certKey); 4678 4679 if (entry == NULL) { 4680 goto loser; 4681 } 4682 4683 if (!nsslowcert_hasTrust(&entry->trust)) { 4684 goto loser; 4685 } 4686 4687 /* inherit entry */ 4688 trust = DecodeTrustEntry(handle, entry, certKey); 4689 4690 loser: 4691 if (trust == NULL) { 4692 if (entry) { 4693 DestroyDBEntry((certDBEntry *)entry); 4694 } 4695 } 4696 4697 if (locked) { 4698 nsslowcert_UnlockDB(handle); 4699 } 4700 4701 return (trust); 4702 } 4703 4704 /* 4705 * Lookup a certificate in the databases without locking 4706 */ 4707 NSSLOWCERTCertificate * 4708 nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) 4709 { 4710 return (FindCertByKey(handle, certKey, PR_FALSE)); 4711 } 4712 4713 /* 4714 * Lookup a trust object in the databases without locking 4715 */ 4716 NSSLOWCERTTrust * 4717 nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) 4718 { 4719 return (FindTrustByKey(handle, certKey, PR_FALSE)); 4720 } 4721 4722 /* 4723 * Generate a key from an issuerAndSerialNumber, and find the 4724 * associated cert in the database. 4725 */ 4726 NSSLOWCERTCertificate * 4727 nsslowcert_FindCertByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTIssuerAndSN *issuerAndSN) 4728 { 4729 SECItem certKey; 4730 SECItem *sn = &issuerAndSN->serialNumber; 4731 SECItem *issuer = &issuerAndSN->derIssuer; 4732 NSSLOWCERTCertificate *cert; 4733 int data_len = sn->len; 4734 int index = 0; 4735 4736 /* automatically detect DER encoded serial numbers and remove the der 4737 * encoding since the database expects unencoded data. 4738 * if it's DER encoded, there must be at least 3 bytes, tag, len, data */ 4739 if ((sn->len >= 3) && (sn->data[0] == 0x2)) { 4740 /* remove the der encoding of the serial number before generating the 4741 * key.. */ 4742 int data_left = sn->len - 2; 4743 data_len = sn->data[1]; 4744 index = 2; 4745 4746 /* extended length ? (not very likely for a serial number) */ 4747 if (data_len & 0x80) { 4748 int len_count = data_len & 0x7f; 4749 4750 data_len = 0; 4751 data_left -= len_count; 4752 if (data_left > 0) { 4753 while (len_count--) { 4754 data_len = (data_len << 8) | sn->data[index++]; 4755 } 4756 } 4757 } 4758 /* XXX leaving any leading zeros on the serial number for backwards 4759 * compatibility 4760 */ 4761 /* not a valid der, must be just an unlucky serial number value */ 4762 if (data_len != data_left) { 4763 data_len = sn->len; 4764 index = 0; 4765 } 4766 } 4767 4768 certKey.type = 0; 4769 certKey.data = (unsigned char *)PORT_Alloc(sn->len + issuer->len); 4770 certKey.len = data_len + issuer->len; 4771 4772 if (certKey.data == NULL) { 4773 return (0); 4774 } 4775 4776 /* first try the serial number as hand-decoded above*/ 4777 /* copy the serialNumber */ 4778 PORT_Memcpy(certKey.data, &sn->data[index], data_len); 4779 4780 /* copy the issuer */ 4781 PORT_Memcpy(&certKey.data[data_len], issuer->data, issuer->len); 4782 4783 cert = nsslowcert_FindCertByKey(handle, &certKey); 4784 if (cert) { 4785 PORT_Free(certKey.data); 4786 return (cert); 4787 } 4788 4789 /* didn't find it, try by der encoded serial number */ 4790 /* copy the serialNumber */ 4791 PORT_Memcpy(certKey.data, sn->data, sn->len); 4792 4793 /* copy the issuer */ 4794 PORT_Memcpy(&certKey.data[sn->len], issuer->data, issuer->len); 4795 certKey.len = sn->len + issuer->len; 4796 4797 cert = nsslowcert_FindCertByKey(handle, &certKey); 4798 4799 PORT_Free(certKey.data); 4800 4801 return (cert); 4802 } 4803 4804 /* 4805 * Generate a key from an issuerAndSerialNumber, and find the 4806 * associated cert in the database. 4807 */ 4808 NSSLOWCERTTrust * 4809 nsslowcert_FindTrustByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, 4810 NSSLOWCERTIssuerAndSN *issuerAndSN) 4811 { 4812 SECItem certKey; 4813 SECItem *sn = &issuerAndSN->serialNumber; 4814 SECItem *issuer = &issuerAndSN->derIssuer; 4815 NSSLOWCERTTrust *trust; 4816 unsigned char keyBuf[512]; 4817 int data_len = sn->len; 4818 int index = 0; 4819 int len; 4820 4821 /* automatically detect DER encoded serial numbers and remove the der 4822 * encoding since the database expects unencoded data. 4823 * if it's DER encoded, there must be at least 3 bytes, tag, len, data */ 4824 if ((sn->len >= 3) && (sn->data[0] == 0x2)) { 4825 /* remove the der encoding of the serial number before generating the 4826 * key.. */ 4827 int data_left = sn->len - 2; 4828 data_len = sn->data[1]; 4829 index = 2; 4830 4831 /* extended length ? (not very likely for a serial number) */ 4832 if (data_len & 0x80) { 4833 int len_count = data_len & 0x7f; 4834 4835 data_len = 0; 4836 data_left -= len_count; 4837 if (data_left > 0) { 4838 while (len_count--) { 4839 data_len = (data_len << 8) | sn->data[index++]; 4840 } 4841 } 4842 } 4843 /* XXX leaving any leading zeros on the serial number for backwards 4844 * compatibility 4845 */ 4846 /* not a valid der, must be just an unlucky serial number value */ 4847 if (data_len != data_left) { 4848 data_len = sn->len; 4849 index = 0; 4850 } 4851 } 4852 4853 certKey.type = 0; 4854 certKey.len = data_len + issuer->len; 4855 len = sn->len + issuer->len; 4856 if (len > sizeof(keyBuf)) { 4857 certKey.data = (unsigned char *)PORT_Alloc(len); 4858 } else { 4859 certKey.data = keyBuf; 4860 } 4861 4862 if (certKey.data == NULL) { 4863 return (0); 4864 } 4865 4866 /* first try the serial number as hand-decoded above*/ 4867 /* copy the serialNumber */ 4868 PORT_Memcpy(certKey.data, &sn->data[index], data_len); 4869 4870 /* copy the issuer */ 4871 PORT_Memcpy(&certKey.data[data_len], issuer->data, issuer->len); 4872 4873 trust = nsslowcert_FindTrustByKey(handle, &certKey); 4874 if (trust) { 4875 pkcs11_freeStaticData(certKey.data, keyBuf); 4876 return (trust); 4877 } 4878 4879 if (index == 0) { 4880 pkcs11_freeStaticData(certKey.data, keyBuf); 4881 return NULL; 4882 } 4883 4884 /* didn't find it, try by der encoded serial number */ 4885 /* copy the serialNumber */ 4886 PORT_Memcpy(certKey.data, sn->data, sn->len); 4887 4888 /* copy the issuer */ 4889 PORT_Memcpy(&certKey.data[sn->len], issuer->data, issuer->len); 4890 certKey.len = sn->len + issuer->len; 4891 4892 trust = nsslowcert_FindTrustByKey(handle, &certKey); 4893 4894 pkcs11_freeStaticData(certKey.data, keyBuf); 4895 4896 return (trust); 4897 } 4898 4899 /* 4900 * look for the given DER certificate in the database 4901 */ 4902 NSSLOWCERTCertificate * 4903 nsslowcert_FindCertByDERCert(NSSLOWCERTCertDBHandle *handle, SECItem *derCert) 4904 { 4905 PLArenaPool *arena; 4906 SECItem certKey; 4907 SECStatus rv; 4908 NSSLOWCERTCertificate *cert = NULL; 4909 4910 /* create a scratch arena */ 4911 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 4912 if (arena == NULL) { 4913 return (NULL); 4914 } 4915 4916 /* extract the database key from the cert */ 4917 rv = nsslowcert_KeyFromDERCert(arena, derCert, &certKey); 4918 if (rv != SECSuccess) { 4919 goto loser; 4920 } 4921 4922 /* find the certificate */ 4923 cert = nsslowcert_FindCertByKey(handle, &certKey); 4924 4925 loser: 4926 PORT_FreeArena(arena, PR_FALSE); 4927 return (cert); 4928 } 4929 4930 static void 4931 DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb) 4932 { 4933 int refCount; 4934 NSSLOWCERTCertDBHandle *handle; 4935 4936 if (cert) { 4937 4938 handle = cert->dbhandle; 4939 4940 /* 4941 * handle may be NULL, for example if the cert was created with 4942 * nsslowcert_DecodeDERCertificate. 4943 */ 4944 if (lockdb && handle) { 4945 nsslowcert_LockDB(handle); 4946 } 4947 4948 nsslowcert_LockCertRefCount(cert); 4949 PORT_Assert(cert->referenceCount > 0); 4950 refCount = --cert->referenceCount; 4951 nsslowcert_UnlockCertRefCount(cert); 4952 4953 if (refCount == 0) { 4954 certDBEntryCert *entry = cert->dbEntry; 4955 4956 if (entry) { 4957 DestroyDBEntry((certDBEntry *)entry); 4958 } 4959 4960 pkcs11_freeNickname(cert->nickname, cert->nicknameSpace); 4961 pkcs11_freeNickname(cert->emailAddr, cert->emailAddrSpace); 4962 pkcs11_freeStaticData(cert->certKey.data, cert->certKeySpace); 4963 cert->certKey.data = NULL; 4964 cert->nickname = NULL; 4965 4966 /* zero cert before freeing. Any stale references to this cert 4967 * after this point will probably cause an exception. */ 4968 PORT_Memset(cert, 0, sizeof *cert); 4969 4970 /* use reflock to protect the free list */ 4971 nsslowcert_LockFreeList(); 4972 if (certListCount > MAX_CERT_LIST_COUNT) { 4973 PORT_Free(cert); 4974 } else { 4975 certListCount++; 4976 cert->next = certListHead; 4977 certListHead = cert; 4978 } 4979 nsslowcert_UnlockFreeList(); 4980 cert = NULL; 4981 } 4982 if (lockdb && handle) { 4983 nsslowcert_UnlockDB(handle); 4984 } 4985 } 4986 4987 return; 4988 } 4989 4990 NSSLOWCERTCertificate * 4991 nsslowcert_CreateCert(void) 4992 { 4993 NSSLOWCERTCertificate *cert; 4994 nsslowcert_LockFreeList(); 4995 cert = certListHead; 4996 if (cert) { 4997 certListHead = cert->next; 4998 certListCount--; 4999 } 5000 PORT_Assert(certListCount >= 0); 5001 nsslowcert_UnlockFreeList(); 5002 if (cert) { 5003 return cert; 5004 } 5005 return PORT_ZNew(NSSLOWCERTCertificate); 5006 } 5007 5008 static void 5009 DestroyCertFreeList(void) 5010 { 5011 NSSLOWCERTCertificate *cert; 5012 5013 nsslowcert_LockFreeList(); 5014 while (NULL != (cert = certListHead)) { 5015 certListCount--; 5016 certListHead = cert->next; 5017 PORT_Free(cert); 5018 } 5019 PORT_Assert(!certListCount); 5020 certListCount = 0; 5021 nsslowcert_UnlockFreeList(); 5022 } 5023 5024 void 5025 nsslowcert_DestroyTrust(NSSLOWCERTTrust *trust) 5026 { 5027 certDBEntryCert *entry = trust->dbEntry; 5028 5029 if (entry) { 5030 DestroyDBEntry((certDBEntry *)entry); 5031 } 5032 pkcs11_freeStaticData(trust->dbKey.data, trust->dbKeySpace); 5033 PORT_Memset(trust, 0, sizeof(*trust)); 5034 5035 nsslowcert_LockFreeList(); 5036 if (trustListCount > MAX_TRUST_LIST_COUNT) { 5037 PORT_Free(trust); 5038 } else { 5039 trustListCount++; 5040 trust->next = trustListHead; 5041 trustListHead = trust; 5042 } 5043 nsslowcert_UnlockFreeList(); 5044 5045 return; 5046 } 5047 5048 void 5049 nsslowcert_DestroyCertificate(NSSLOWCERTCertificate *cert) 5050 { 5051 DestroyCertificate(cert, PR_TRUE); 5052 return; 5053 } 5054 5055 static void 5056 nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert) 5057 { 5058 DestroyCertificate(cert, PR_FALSE); 5059 return; 5060 } 5061 5062 /* 5063 * Lookup a CRL in the databases. We mirror the same fast caching data base 5064 * caching stuff used by certificates....? 5065 */ 5066 certDBEntryRevocation * 5067 nsslowcert_FindCrlByKey(NSSLOWCERTCertDBHandle *handle, 5068 SECItem *crlKey, PRBool isKRL) 5069 { 5070 SECItem keyitem; 5071 SECStatus rv; 5072 PLArenaPool *arena = NULL; 5073 certDBEntryRevocation *entry = NULL; 5074 certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation 5075 : certDBEntryTypeRevocation; 5076 5077 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 5078 if (arena == NULL) { 5079 goto loser; 5080 } 5081 5082 rv = EncodeDBGenericKey(crlKey, arena, &keyitem, crlType); 5083 if (rv != SECSuccess) { 5084 goto loser; 5085 } 5086 5087 /* find in perm database */ 5088 entry = ReadDBCrlEntry(handle, crlKey, crlType); 5089 5090 if (entry == NULL) { 5091 goto loser; 5092 } 5093 5094 loser: 5095 if (arena) { 5096 PORT_FreeArena(arena, PR_FALSE); 5097 } 5098 5099 return entry; 5100 } 5101 5102 /* 5103 * replace the existing URL in the data base with a new one 5104 */ 5105 static SECStatus 5106 nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 5107 SECItem *crlKey, char *url, PRBool isKRL) 5108 { 5109 SECStatus rv = SECFailure; 5110 certDBEntryRevocation *entry = NULL; 5111 certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation 5112 : certDBEntryTypeRevocation; 5113 DeleteDBCrlEntry(handle, crlKey, crlType); 5114 5115 /* Write the new entry into the data base */ 5116 entry = NewDBCrlEntry(derCrl, url, crlType, 0); 5117 if (entry == NULL) 5118 goto done; 5119 5120 rv = WriteDBCrlEntry(handle, entry, crlKey); 5121 if (rv != SECSuccess) 5122 goto done; 5123 5124 done: 5125 if (entry) { 5126 DestroyDBEntry((certDBEntry *)entry); 5127 } 5128 return rv; 5129 } 5130 5131 SECStatus 5132 nsslowcert_AddCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 5133 SECItem *crlKey, char *url, PRBool isKRL) 5134 { 5135 SECStatus rv; 5136 5137 rv = nsslowcert_UpdateCrl(handle, derCrl, crlKey, url, isKRL); 5138 5139 return rv; 5140 } 5141 5142 SECStatus 5143 nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle, const SECItem *derName, 5144 PRBool isKRL) 5145 { 5146 SECStatus rv; 5147 certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation 5148 : certDBEntryTypeRevocation; 5149 5150 rv = DeleteDBCrlEntry(handle, derName, crlType); 5151 if (rv != SECSuccess) 5152 goto done; 5153 5154 done: 5155 return rv; 5156 } 5157 5158 PRBool 5159 nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust) 5160 { 5161 if (trust == NULL) { 5162 return PR_FALSE; 5163 } 5164 /* if we only have CERTDB__USER and CERTDB_TRUSTED_UNKNOWN bits, then 5165 * we don't have a trust record. */ 5166 return !(((trust->sslFlags & ~(CERTDB_USER | CERTDB_TRUSTED_UNKNOWN)) == 0) && 5167 ((trust->emailFlags & ~(CERTDB_USER | CERTDB_TRUSTED_UNKNOWN)) == 0) && 5168 ((trust->objectSigningFlags & ~(CERTDB_USER | CERTDB_TRUSTED_UNKNOWN)) == 0)); 5169 } 5170 5171 /* 5172 * This function has the logic that decides if another person's cert and 5173 * email profile from an S/MIME message should be saved. It can deal with 5174 * the case when there is no profile. 5175 */ 5176 static SECStatus 5177 nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, 5178 char *emailAddr, SECItem *derSubject, SECItem *emailProfile, 5179 SECItem *profileTime) 5180 { 5181 certDBEntrySMime *entry = NULL; 5182 SECStatus rv = SECFailure; 5183 ; 5184 5185 /* find our existing entry */ 5186 entry = nsslowcert_ReadDBSMimeEntry(dbhandle, emailAddr); 5187 5188 if (entry) { 5189 /* keep our old db entry consistant for old applications. */ 5190 if (!SECITEM_ItemsAreEqual(derSubject, &entry->subjectName)) { 5191 nsslowcert_UpdateSubjectEmailAddr(dbhandle, &entry->subjectName, 5192 emailAddr, nsslowcert_remove); 5193 } 5194 DestroyDBEntry((certDBEntry *)entry); 5195 entry = NULL; 5196 } 5197 5198 /* now save the entry */ 5199 entry = NewDBSMimeEntry(emailAddr, derSubject, emailProfile, 5200 profileTime, 0); 5201 if (entry == NULL) { 5202 rv = SECFailure; 5203 goto loser; 5204 } 5205 5206 nsslowcert_LockDB(dbhandle); 5207 5208 rv = DeleteDBSMimeEntry(dbhandle, emailAddr); 5209 /* if delete fails, try to write new entry anyway... */ 5210 5211 /* link subject entry back here */ 5212 rv = nsslowcert_UpdateSubjectEmailAddr(dbhandle, derSubject, emailAddr, 5213 nsslowcert_add); 5214 if (rv != SECSuccess) { 5215 nsslowcert_UnlockDB(dbhandle); 5216 goto loser; 5217 } 5218 5219 rv = WriteDBSMimeEntry(dbhandle, entry); 5220 if (rv != SECSuccess) { 5221 nsslowcert_UnlockDB(dbhandle); 5222 goto loser; 5223 } 5224 5225 nsslowcert_UnlockDB(dbhandle); 5226 5227 rv = SECSuccess; 5228 5229 loser: 5230 if (entry) { 5231 DestroyDBEntry((certDBEntry *)entry); 5232 } 5233 return (rv); 5234 } 5235 5236 SECStatus 5237 nsslowcert_SaveSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, char *emailAddr, 5238 SECItem *derSubject, SECItem *emailProfile, SECItem *profileTime) 5239 { 5240 SECStatus rv = SECFailure; 5241 ; 5242 5243 rv = nsslowcert_UpdateSMimeProfile(dbhandle, emailAddr, 5244 derSubject, emailProfile, profileTime); 5245 5246 return (rv); 5247 } 5248 5249 void 5250 nsslowcert_DestroyFreeLists(void) 5251 { 5252 if (freeListLock == NULL) { 5253 return; 5254 } 5255 DestroyCertEntryFreeList(); 5256 DestroyTrustFreeList(); 5257 DestroyCertFreeList(); 5258 SKIP_AFTER_FORK(PZ_DestroyLock(freeListLock)); 5259 freeListLock = NULL; 5260 } 5261 5262 void 5263 nsslowcert_DestroyGlobalLocks(void) 5264 { 5265 if (dbLock) { 5266 SKIP_AFTER_FORK(PZ_DestroyLock(dbLock)); 5267 dbLock = NULL; 5268 } 5269 if (certRefCountLock) { 5270 SKIP_AFTER_FORK(PZ_DestroyLock(certRefCountLock)); 5271 certRefCountLock = NULL; 5272 } 5273 if (certTrustLock) { 5274 SKIP_AFTER_FORK(PZ_DestroyLock(certTrustLock)); 5275 certTrustLock = NULL; 5276 } 5277 } 5278 5279 certDBEntry * 5280 nsslowcert_DecodeAnyDBEntry(SECItem *dbData, const SECItem *dbKey, 5281 certDBEntryType entryType, void *pdata) 5282 { 5283 PLArenaPool *arena = NULL; 5284 certDBEntry *entry; 5285 SECStatus rv; 5286 SECItem dbEntry; 5287 5288 if ((dbData->len < SEC_DB_ENTRY_HEADER_LEN) || (dbKey->len == 0)) { 5289 PORT_SetError(SEC_ERROR_INVALID_ARGS); 5290 goto loser; 5291 } 5292 dbEntry.data = &dbData->data[SEC_DB_ENTRY_HEADER_LEN]; 5293 dbEntry.len = dbData->len - SEC_DB_ENTRY_HEADER_LEN; 5294 5295 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 5296 if (arena == NULL) { 5297 goto loser; 5298 } 5299 entry = PORT_ArenaZNew(arena, certDBEntry); 5300 if (!entry) 5301 goto loser; 5302 5303 entry->common.version = (unsigned int)dbData->data[0]; 5304 entry->common.flags = (unsigned int)dbData->data[2]; 5305 entry->common.type = entryType; 5306 entry->common.arena = arena; 5307 5308 switch (entryType) { 5309 case certDBEntryTypeContentVersion: /* This type appears to be unused */ 5310 case certDBEntryTypeVersion: /* This type has only the common hdr */ 5311 rv = SECSuccess; 5312 break; 5313 5314 case certDBEntryTypeSubject: 5315 rv = DecodeDBSubjectEntry(&entry->subject, &dbEntry, dbKey); 5316 break; 5317 5318 case certDBEntryTypeNickname: 5319 rv = DecodeDBNicknameEntry(&entry->nickname, &dbEntry, 5320 (char *)dbKey->data); 5321 break; 5322 5323 /* smime profiles need entries created after the certs have 5324 * been imported, loop over them in a second run */ 5325 case certDBEntryTypeSMimeProfile: 5326 rv = DecodeDBSMimeEntry(&entry->smime, &dbEntry, (char *)dbKey->data); 5327 break; 5328 5329 case certDBEntryTypeCert: 5330 rv = DecodeDBCertEntry(&entry->cert, &dbEntry); 5331 break; 5332 5333 case certDBEntryTypeKeyRevocation: 5334 case certDBEntryTypeRevocation: 5335 rv = DecodeDBCrlEntry(&entry->revocation, &dbEntry); 5336 break; 5337 5338 default: 5339 PORT_SetError(SEC_ERROR_INVALID_ARGS); 5340 rv = SECFailure; 5341 } 5342 5343 if (rv == SECSuccess) 5344 return entry; 5345 5346 loser: 5347 if (arena) 5348 PORT_FreeArena(arena, PR_FALSE); 5349 return NULL; 5350 }