security/nss/lib/softoken/legacydb/pcertdb.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial