PageRenderTime 120ms CodeModel.GetById 16ms app.highlight 87ms RepoModel.GetById 2ms app.codeStats 1ms

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

http://github.com/zpao/v8monkey
C | 5388 lines | 3939 code | 871 blank | 578 comment | 914 complexity | cb1cf42a254592733b815c8c285e0205 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   4 * The contents of this file are subject to the Mozilla Public License Version
   5 * 1.1 (the "License"); you may not use this file except in compliance with
   6 * the License. You may obtain a copy of the License at
   7 * http://www.mozilla.org/MPL/
   8 *
   9 * Software distributed under the License is distributed on an "AS IS" basis,
  10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11 * for the specific language governing rights and limitations under the
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  16 * The Initial Developer of the Original Code is
  17 * Netscape Communications Corporation.
  18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19 * the Initial Developer. All Rights Reserved.
  20 *
  21 * Contributor(s):
  22 *
  23 * Alternatively, the contents of this file may be used under the terms of
  24 * either the GNU General Public License Version 2 or later (the "GPL"), or
  25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26 * in which case the provisions of the GPL or the LGPL are applicable instead
  27 * of those above. If you wish to allow use of your version of this file only
  28 * under the terms of either the GPL or the LGPL, and not to allow others to
  29 * use your version of this file under the terms of the MPL, indicate your
  30 * decision by deleting the provisions above and replace them with the notice
  31 * and other provisions required by the GPL or the LGPL. If you do not delete
  32 * the provisions above, a recipient may use your version of this file under
  33 * the terms of any one of the MPL, the GPL or the LGPL.
  34 *
  35 * ***** END LICENSE BLOCK ***** */
  36
  37/*
  38 * Permanent Certificate database handling code 
  39 *
  40 * $Id: pcertdb.c,v 1.12 2010/07/20 01:26:04 wtc%google.com Exp $
  41 */
  42#include "lowkeyti.h"
  43#include "pcert.h"
  44#include "mcom_db.h"
  45#include "pcert.h"
  46#include "secitem.h"
  47#include "secder.h"
  48
  49#include "secerr.h"
  50#include "lgdb.h"
  51
  52/* forward declaration */
  53NSSLOWCERTCertificate *
  54nsslowcert_FindCertByDERCertNoLocking(NSSLOWCERTCertDBHandle *handle, SECItem *derCert);
  55static SECStatus
  56nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, 
  57	char *emailAddr, SECItem *derSubject, SECItem *emailProfile, 
  58							SECItem *profileTime);
  59static SECStatus
  60nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
  61    NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust);
  62static SECStatus
  63nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 
  64			SECItem *crlKey, char *url, PRBool isKRL);
  65
  66static NSSLOWCERTCertificate *certListHead = NULL;
  67static NSSLOWCERTTrust *trustListHead = NULL;
  68static certDBEntryCert *entryListHead = NULL;
  69static int certListCount = 0;
  70static int trustListCount = 0;
  71static int entryListCount = 0;
  72#define MAX_CERT_LIST_COUNT 10
  73#define MAX_TRUST_LIST_COUNT 10
  74#define MAX_ENTRY_LIST_COUNT 10
  75
  76/*
  77 * the following functions are wrappers for the db library that implement
  78 * a global lock to make the database thread safe.
  79 */
  80static PZLock *dbLock = NULL;
  81static PZLock *certRefCountLock = NULL;
  82static PZLock *certTrustLock = NULL;
  83static PZLock *freeListLock = NULL;
  84
  85void
  86certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle)
  87{
  88    if (dbLock == NULL) {
  89	dbLock = PZ_NewLock(nssILockCertDB);
  90	PORT_Assert(dbLock != NULL);
  91    }
  92}
  93
  94SECStatus
  95nsslowcert_InitLocks(void)
  96{
  97    if (freeListLock == NULL) {
  98	freeListLock = PZ_NewLock(nssILockRefLock);
  99	if (freeListLock == NULL) {
 100	    return SECFailure;
 101	}
 102    }
 103    if (certRefCountLock == NULL) {
 104	certRefCountLock = PZ_NewLock(nssILockRefLock);
 105	if (certRefCountLock == NULL) {
 106	    return SECFailure;
 107	}
 108    }
 109    if (certTrustLock == NULL ) {
 110	certTrustLock = PZ_NewLock(nssILockCertDB);
 111	if (certTrustLock == NULL) {
 112	    return SECFailure;
 113	}
 114    }
 115    
 116    return SECSuccess;
 117}
 118
 119/*
 120 * Acquire the global lock on the cert database.
 121 * This lock is currently used for the following operations:
 122 *	adding or deleting a cert to either the temp or perm databases
 123 *	converting a temp to perm or perm to temp
 124 *	changing (maybe just adding!?) the trust of a cert
 125 *      chaning the DB status checking Configuration
 126 */
 127static void
 128nsslowcert_LockDB(NSSLOWCERTCertDBHandle *handle)
 129{
 130    PZ_EnterMonitor(handle->dbMon);
 131    return;
 132}
 133
 134/*
 135 * Free the global cert database lock.
 136 */
 137static void
 138nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle)
 139{
 140    PRStatus prstat;
 141    
 142    prstat = PZ_ExitMonitor(handle->dbMon);
 143    
 144    PORT_Assert(prstat == PR_SUCCESS);
 145    
 146    return;
 147}
 148
 149
 150/*
 151 * Acquire the cert reference count lock
 152 * There is currently one global lock for all certs, but I'm putting a cert
 153 * arg here so that it will be easy to make it per-cert in the future if
 154 * that turns out to be necessary.
 155 */
 156static void
 157nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert)
 158{
 159    PORT_Assert(certRefCountLock != NULL);
 160    
 161    PZ_Lock(certRefCountLock);
 162    return;
 163}
 164
 165/*
 166 * Free the cert reference count lock
 167 */
 168static void
 169nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert)
 170{
 171    PRStatus prstat;
 172
 173    PORT_Assert(certRefCountLock != NULL);
 174    
 175    prstat = PZ_Unlock(certRefCountLock);
 176    
 177    PORT_Assert(prstat == PR_SUCCESS);
 178
 179    return;
 180}
 181
 182/*
 183 * Acquire the cert trust lock
 184 * There is currently one global lock for all certs, but I'm putting a cert
 185 * arg here so that it will be easy to make it per-cert in the future if
 186 * that turns out to be necessary.
 187 */
 188static void
 189nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert)
 190{
 191    PORT_Assert(certTrustLock != NULL);
 192
 193    PZ_Lock(certTrustLock);
 194    return;
 195}
 196
 197/*
 198 * Free the cert trust lock
 199 */
 200static void
 201nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert)
 202{
 203    PRStatus prstat;
 204
 205    PORT_Assert(certTrustLock != NULL);
 206    
 207    prstat = PZ_Unlock(certTrustLock);
 208    
 209    PORT_Assert(prstat == PR_SUCCESS);
 210
 211    return;
 212}
 213
 214
 215/*
 216 * Acquire the cert reference count lock
 217 * There is currently one global lock for all certs, but I'm putting a cert
 218 * arg here so that it will be easy to make it per-cert in the future if
 219 * that turns out to be necessary.
 220 */
 221static void
 222nsslowcert_LockFreeList(void)
 223{
 224    PORT_Assert(freeListLock != NULL);
 225    
 226    SKIP_AFTER_FORK(PZ_Lock(freeListLock));
 227    return;
 228}
 229
 230/*
 231 * Free the cert reference count lock
 232 */
 233static void
 234nsslowcert_UnlockFreeList(void)
 235{
 236    PRStatus prstat = PR_SUCCESS;
 237
 238    PORT_Assert(freeListLock != NULL);
 239    
 240    SKIP_AFTER_FORK(prstat = PZ_Unlock(freeListLock));
 241    
 242    PORT_Assert(prstat == PR_SUCCESS);
 243
 244    return;
 245}
 246
 247NSSLOWCERTCertificate *
 248nsslowcert_DupCertificate(NSSLOWCERTCertificate *c)
 249{
 250    if (c) {
 251	nsslowcert_LockCertRefCount(c);
 252	++c->referenceCount;
 253	nsslowcert_UnlockCertRefCount(c);
 254    }
 255    return c;
 256}
 257
 258static int
 259certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags)
 260{
 261    PRStatus prstat;
 262    int ret;
 263    
 264    PORT_Assert(dbLock != NULL);
 265    PZ_Lock(dbLock);
 266
 267    ret = (* db->get)(db, key, data, flags);
 268
 269    prstat = PZ_Unlock(dbLock);
 270
 271    return(ret);
 272}
 273
 274static int
 275certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags)
 276{
 277    PRStatus prstat;
 278    int ret = 0;
 279
 280    PORT_Assert(dbLock != NULL);
 281    PZ_Lock(dbLock);
 282
 283    ret = (* db->put)(db, key, data, flags);
 284    
 285    prstat = PZ_Unlock(dbLock);
 286
 287    return(ret);
 288}
 289
 290static int
 291certdb_Sync(DB *db, unsigned int flags)
 292{
 293    PRStatus prstat;
 294    int ret;
 295
 296    PORT_Assert(dbLock != NULL);
 297    PZ_Lock(dbLock);
 298
 299    ret = (* db->sync)(db, flags);
 300    
 301    prstat = PZ_Unlock(dbLock);
 302
 303    return(ret);
 304}
 305
 306#define DB_NOT_FOUND -30991  /* from DBM 3.2 */
 307static int
 308certdb_Del(DB *db, DBT *key, unsigned int flags)
 309{
 310    PRStatus prstat;
 311    int ret;
 312
 313    PORT_Assert(dbLock != NULL);
 314    PZ_Lock(dbLock);
 315
 316    ret = (* db->del)(db, key, flags);
 317    
 318    prstat = PZ_Unlock(dbLock);
 319
 320    /* don't fail if the record is already deleted */
 321    if (ret == DB_NOT_FOUND) {
 322	ret = 0;
 323    }
 324
 325    return(ret);
 326}
 327
 328static int
 329certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags)
 330{
 331    PRStatus prstat;
 332    int ret;
 333    
 334    PORT_Assert(dbLock != NULL);
 335    PZ_Lock(dbLock);
 336    
 337    ret = (* db->seq)(db, key, data, flags);
 338
 339    prstat = PZ_Unlock(dbLock);
 340
 341    return(ret);
 342}
 343
 344static void
 345certdb_Close(DB *db)
 346{
 347    PRStatus prstat = PR_SUCCESS;
 348
 349    PORT_Assert(dbLock != NULL);
 350    SKIP_AFTER_FORK(PZ_Lock(dbLock));
 351
 352    (* db->close)(db);
 353    
 354    SKIP_AFTER_FORK(prstat = PZ_Unlock(dbLock));
 355
 356    return;
 357}
 358
 359void
 360pkcs11_freeNickname(char *nickname, char *space)
 361{
 362    if (nickname && nickname != space) {
 363	PORT_Free(nickname);
 364    }
 365}
 366
 367char *
 368pkcs11_copyNickname(char *nickname,char *space, int spaceLen)
 369{
 370    int len;
 371    char *copy = NULL;
 372
 373    len = PORT_Strlen(nickname)+1;
 374    if (len <= spaceLen) {
 375	copy = space;
 376	PORT_Memcpy(copy,nickname,len);
 377    } else {
 378	copy = PORT_Strdup(nickname);
 379    }
 380
 381    return copy;
 382}
 383
 384void
 385pkcs11_freeStaticData (unsigned char *data, unsigned char *space)
 386{
 387    if (data && data != space) {
 388	PORT_Free(data);
 389    }
 390}
 391
 392unsigned char *
 393pkcs11_allocStaticData(int len, unsigned char *space, int spaceLen)
 394{
 395    unsigned char *data = NULL;
 396
 397    if (len <= spaceLen) {
 398	data = space;
 399    } else {
 400	data = (unsigned char *) PORT_Alloc(len);
 401    }
 402
 403    return data;
 404}
 405
 406unsigned char *
 407pkcs11_copyStaticData(unsigned char *data, int len, 
 408					unsigned char *space, int spaceLen)
 409{
 410    unsigned char *copy = pkcs11_allocStaticData(len, space, spaceLen);
 411    if (copy) {
 412	PORT_Memcpy(copy,data,len);
 413    }
 414
 415    return copy;
 416}
 417
 418/*
 419 * destroy a database entry
 420 */
 421static void
 422DestroyDBEntry(certDBEntry *entry)
 423{
 424    PRArenaPool *arena = entry->common.arena;
 425
 426    /* must be one of our certDBEntry from the free list */
 427    if (arena == NULL) {
 428	certDBEntryCert *certEntry;
 429	if ( entry->common.type != certDBEntryTypeCert) {
 430	    return;
 431	}
 432	certEntry = (certDBEntryCert *)entry;
 433
 434	pkcs11_freeStaticData(certEntry->derCert.data, certEntry->derCertSpace);
 435	pkcs11_freeNickname(certEntry->nickname, certEntry->nicknameSpace);
 436
 437	nsslowcert_LockFreeList();
 438	if (entryListCount > MAX_ENTRY_LIST_COUNT) {
 439	    PORT_Free(certEntry);
 440	} else {
 441	    entryListCount++;
 442	    PORT_Memset(certEntry, 0, sizeof( *certEntry));
 443	    certEntry->next = entryListHead;
 444	    entryListHead = certEntry;
 445	}
 446	nsslowcert_UnlockFreeList();
 447	return;
 448    }
 449
 450
 451    /* Zero out the entry struct, so that any further attempts to use it
 452     * will cause an exception (e.g. null pointer reference). */
 453    PORT_Memset(&entry->common, 0, sizeof entry->common);
 454    PORT_FreeArena(arena, PR_FALSE);
 455
 456    return;
 457}
 458
 459/* forward references */
 460static void nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert);
 461
 462static SECStatus
 463DeleteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey)
 464{
 465    DBT key;
 466    int ret;
 467
 468    /* init the database key */
 469    key.data = dbkey->data;
 470    key.size = dbkey->len;
 471    
 472    dbkey->data[0] = (unsigned char)type;
 473
 474    /* delete entry from database */
 475    ret = certdb_Del(handle->permCertDB, &key, 0 );
 476    if ( ret != 0 ) {
 477	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 478	goto loser;
 479    }
 480
 481    ret = certdb_Sync(handle->permCertDB, 0);
 482    if ( ret ) {
 483	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 484	goto loser;
 485    }
 486
 487    return(SECSuccess);
 488    
 489loser:
 490    return(SECFailure);
 491}
 492
 493static SECStatus
 494ReadDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
 495	    SECItem *dbkey, SECItem *dbentry, PRArenaPool *arena)
 496{
 497    DBT data, key;
 498    int ret;
 499    unsigned char *buf;
 500    
 501    /* init the database key */
 502    key.data = dbkey->data;
 503    key.size = dbkey->len;
 504    
 505    dbkey->data[0] = (unsigned char)entry->type;
 506
 507    /* read entry from database */
 508    ret = certdb_Get(handle->permCertDB, &key, &data, 0 );
 509    if ( ret != 0 ) {
 510	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 511	goto loser;
 512    }
 513    
 514    /* validate the entry */
 515    if ( data.size < SEC_DB_ENTRY_HEADER_LEN ) {
 516	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 517	goto loser;
 518    }
 519    buf = (unsigned char *)data.data;
 520    /* version 7 has the same schema, we may be using a v7 db if we openned
 521     * the databases readonly. */
 522    if (!((buf[0] == (unsigned char)CERT_DB_FILE_VERSION) 
 523		|| (buf[0] == (unsigned char) CERT_DB_V7_FILE_VERSION))) {
 524	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 525	goto loser;
 526    }
 527    if ( buf[1] != (unsigned char)entry->type ) {
 528	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 529	goto loser;
 530    }
 531
 532    /* copy out header information */
 533    entry->version = (unsigned int)buf[0];
 534    entry->type = (certDBEntryType)buf[1];
 535    entry->flags = (unsigned int)buf[2];
 536    
 537    /* format body of entry for return to caller */
 538    dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN;
 539    if ( dbentry->len ) {
 540	if (arena) {
 541	    dbentry->data = (unsigned char *)
 542				PORT_ArenaAlloc(arena, dbentry->len);
 543	    if ( dbentry->data == NULL ) {
 544		PORT_SetError(SEC_ERROR_NO_MEMORY);
 545		goto loser;
 546	    }
 547    
 548	    PORT_Memcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN],
 549		  dbentry->len);
 550	} else {
 551	    dbentry->data = &buf[SEC_DB_ENTRY_HEADER_LEN];
 552	}
 553    } else {
 554	dbentry->data = NULL;
 555    }
 556    
 557    return(SECSuccess);
 558
 559loser:
 560    return(SECFailure);
 561}
 562
 563/**
 564 ** Implement low level database access
 565 **/
 566static SECStatus
 567WriteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
 568	     SECItem *dbkey, SECItem *dbentry)
 569{
 570    int ret;
 571    DBT data, key;
 572    unsigned char *buf;
 573    
 574    data.data = dbentry->data;
 575    data.size = dbentry->len;
 576    
 577    buf = (unsigned char*)data.data;
 578    
 579    buf[0] = (unsigned char)entry->version;
 580    buf[1] = (unsigned char)entry->type;
 581    buf[2] = (unsigned char)entry->flags;
 582    
 583    key.data = dbkey->data;
 584    key.size = dbkey->len;
 585    
 586    dbkey->data[0] = (unsigned char)entry->type;
 587
 588    /* put the record into the database now */
 589    ret = certdb_Put(handle->permCertDB, &key, &data, 0);
 590
 591    if ( ret != 0 ) {
 592	goto loser;
 593    }
 594
 595    ret = certdb_Sync( handle->permCertDB, 0 );
 596    
 597    if ( ret ) {
 598	goto loser;
 599    }
 600
 601    return(SECSuccess);
 602
 603loser:
 604    return(SECFailure);
 605}
 606
 607/*
 608 * encode a database cert record
 609 */
 610static SECStatus
 611EncodeDBCertEntry(certDBEntryCert *entry, PRArenaPool *arena, SECItem *dbitem)
 612{
 613    unsigned int nnlen;
 614    unsigned char *buf;
 615    char *nn;
 616    char zbuf = 0;
 617    
 618    if ( entry->nickname ) {
 619	nn = entry->nickname;
 620    } else {
 621	nn = &zbuf;
 622    }
 623    nnlen = PORT_Strlen(nn) + 1;
 624    
 625    /* allocate space for encoded database record, including space
 626     * for low level header
 627     */
 628    dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN +
 629	SEC_DB_ENTRY_HEADER_LEN;
 630    
 631    dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
 632    if ( dbitem->data == NULL) {
 633	PORT_SetError(SEC_ERROR_NO_MEMORY);
 634	goto loser;
 635    }
 636    
 637    /* fill in database record */
 638    buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
 639    
 640    buf[0] = (PRUint8)( entry->trust.sslFlags >> 8 );
 641    buf[1] = (PRUint8)( entry->trust.sslFlags      );
 642    buf[2] = (PRUint8)( entry->trust.emailFlags >> 8 );
 643    buf[3] = (PRUint8)( entry->trust.emailFlags      );
 644    buf[4] = (PRUint8)( entry->trust.objectSigningFlags >> 8 );
 645    buf[5] = (PRUint8)( entry->trust.objectSigningFlags      );
 646    buf[6] = (PRUint8)( entry->derCert.len >> 8 );
 647    buf[7] = (PRUint8)( entry->derCert.len      );
 648    buf[8] = (PRUint8)( nnlen >> 8 );
 649    buf[9] = (PRUint8)( nnlen      );
 650    
 651    PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data,
 652	      entry->derCert.len);
 653
 654    PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN + entry->derCert.len],
 655	      nn, nnlen);
 656
 657    return(SECSuccess);
 658
 659loser:
 660    return(SECFailure);
 661}
 662
 663/*
 664 * encode a database key for a cert record
 665 */
 666static SECStatus
 667EncodeDBCertKey(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey)
 668{
 669    unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN;
 670    if (len > NSS_MAX_LEGACY_DB_KEY_SIZE)
 671	goto loser;
 672    if (arena) {
 673	dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
 674    } else {
 675	if (dbkey->len < len) {
 676	    dbkey->data = (unsigned char *)PORT_Alloc(len);
 677	}
 678    }
 679    dbkey->len = len;
 680    if ( dbkey->data == NULL ) {
 681	goto loser;
 682    }
 683    PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
 684	      certKey->data, certKey->len);
 685    dbkey->data[0] = certDBEntryTypeCert;
 686
 687    return(SECSuccess);
 688loser:
 689    return(SECFailure);
 690}
 691
 692static SECStatus
 693EncodeDBGenericKey(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey, 
 694				certDBEntryType entryType)
 695{
 696    /*
 697     * we only allow _one_ KRL key!
 698     */
 699    if (entryType == certDBEntryTypeKeyRevocation) {
 700	dbkey->len = SEC_DB_KEY_HEADER_LEN;
 701 	dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
 702	if ( dbkey->data == NULL ) {
 703	    goto loser;
 704	}
 705        dbkey->data[0] = (unsigned char) entryType;
 706        return(SECSuccess);
 707    }
 708    
 709
 710    dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN;
 711    if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
 712	goto loser;
 713    dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
 714    if ( dbkey->data == NULL ) {
 715	goto loser;
 716    }
 717    PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
 718	       certKey->data, certKey->len);
 719    dbkey->data[0] = (unsigned char) entryType;
 720
 721    return(SECSuccess);
 722loser:
 723    return(SECFailure);
 724}
 725
 726static SECStatus
 727DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry)
 728{
 729    unsigned int nnlen;
 730    unsigned int headerlen;
 731    int lenoff;
 732
 733    /* allow updates of old versions of the database */
 734    switch ( entry->common.version ) {
 735      case 5:
 736	headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
 737	lenoff = 3;
 738	break;
 739      case 6:
 740	/* should not get here */
 741	PORT_Assert(0);
 742	headerlen = DB_CERT_V6_ENTRY_HEADER_LEN;
 743	lenoff = 3;
 744	break;
 745      case 7:
 746      case 8:
 747	headerlen = DB_CERT_ENTRY_HEADER_LEN;
 748	lenoff = 6;
 749	break;
 750      default:
 751	/* better not get here */
 752	PORT_Assert(0);
 753	headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
 754	lenoff = 3;
 755	break;
 756    }
 757    
 758    /* is record long enough for header? */
 759    if ( dbentry->len < headerlen ) {
 760	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 761	goto loser;
 762    }
 763    
 764    /* is database entry correct length? */
 765    entry->derCert.len = ( ( dbentry->data[lenoff] << 8 ) |
 766			  dbentry->data[lenoff+1] );
 767    nnlen = ( ( dbentry->data[lenoff+2] << 8 ) | dbentry->data[lenoff+3] );
 768    lenoff = dbentry->len - ( entry->derCert.len + nnlen + headerlen );
 769    if ( lenoff ) {
 770	if ( lenoff < 0 || (lenoff & 0xffff) != 0 ) {
 771	    PORT_SetError(SEC_ERROR_BAD_DATABASE);
 772	    goto loser;
 773	}
 774	/* The cert size exceeded 64KB.  Reconstruct the correct length. */
 775	entry->derCert.len += lenoff;
 776    }
 777    
 778    /* copy the dercert */
 779    entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen],
 780	entry->derCert.len,entry->derCertSpace,sizeof(entry->derCertSpace));
 781    if ( entry->derCert.data == NULL ) {
 782	PORT_SetError(SEC_ERROR_NO_MEMORY);
 783	goto loser;
 784    }
 785
 786    /* copy the nickname */
 787    if ( nnlen > 1 ) {
 788	entry->nickname = (char *)pkcs11_copyStaticData(
 789			&dbentry->data[headerlen+entry->derCert.len], nnlen,
 790			(unsigned char *)entry->nicknameSpace, 
 791			sizeof(entry->nicknameSpace));
 792	if ( entry->nickname == NULL ) {
 793	    PORT_SetError(SEC_ERROR_NO_MEMORY);
 794	    goto loser;
 795	}
 796    } else {
 797	entry->nickname = NULL;
 798    }
 799    
 800    if ( entry->common.version < 7 ) {
 801	/* allow updates of v5 db */
 802	entry->trust.sslFlags = dbentry->data[0];
 803	entry->trust.emailFlags = dbentry->data[1];
 804	entry->trust.objectSigningFlags = dbentry->data[2];
 805    } else {
 806	entry->trust.sslFlags = ( dbentry->data[0] << 8 ) | dbentry->data[1];
 807	entry->trust.emailFlags = ( dbentry->data[2] << 8 ) | dbentry->data[3];
 808	entry->trust.objectSigningFlags =
 809	    ( dbentry->data[4] << 8 ) | dbentry->data[5];
 810    }
 811    
 812    return(SECSuccess);
 813loser:
 814    return(SECFailure);
 815}
 816
 817
 818/*
 819 * Create a new certDBEntryCert from existing data
 820 */
 821static certDBEntryCert *
 822NewDBCertEntry(SECItem *derCert, char *nickname,
 823	       NSSLOWCERTCertTrust *trust, int flags)
 824{
 825    certDBEntryCert *entry;
 826    PRArenaPool *arena = NULL;
 827    int nnlen;
 828    
 829    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
 830
 831    if ( !arena ) {
 832	goto loser;
 833    }
 834	
 835    entry = PORT_ArenaZNew(arena, certDBEntryCert);
 836    if ( entry == NULL ) {
 837	goto loser;
 838    }
 839    
 840    /* fill in the dbCert */
 841    entry->common.arena = arena;
 842    entry->common.type = certDBEntryTypeCert;
 843    entry->common.version = CERT_DB_FILE_VERSION;
 844    entry->common.flags = flags;
 845    
 846    if ( trust ) {
 847	entry->trust = *trust;
 848    }
 849
 850    entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, derCert->len);
 851    if ( !entry->derCert.data ) {
 852	goto loser;
 853    }
 854    entry->derCert.len = derCert->len;
 855    PORT_Memcpy(entry->derCert.data, derCert->data, derCert->len);
 856    
 857    nnlen = ( nickname ? strlen(nickname) + 1 : 0 );
 858    
 859    if ( nnlen ) {
 860	entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
 861	if ( !entry->nickname ) {
 862	    goto loser;
 863	}
 864	PORT_Memcpy(entry->nickname, nickname, nnlen);
 865	
 866    } else {
 867	entry->nickname = 0;
 868    }
 869
 870    return(entry);
 871
 872loser:
 873    
 874    /* allocation error, free arena and return */
 875    if ( arena ) {
 876	PORT_FreeArena(arena, PR_FALSE);
 877    }
 878    
 879    PORT_SetError(SEC_ERROR_NO_MEMORY);
 880    return(0);
 881}
 882
 883/*
 884 * Decode a version 4 DBCert from the byte stream database format
 885 * and construct a current database entry struct
 886 */
 887static certDBEntryCert *
 888DecodeV4DBCertEntry(unsigned char *buf, int len)
 889{
 890    certDBEntryCert *entry;
 891    int certlen;
 892    int nnlen;
 893    PRArenaPool *arena;
 894    
 895    /* make sure length is at least long enough for the header */
 896    if ( len < DBCERT_V4_HEADER_LEN ) {
 897	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 898	return(0);
 899    }
 900
 901    /* get other lengths */
 902    certlen = buf[3] << 8 | buf[4];
 903    nnlen = buf[5] << 8 | buf[6];
 904    
 905    /* make sure DB entry is the right size */
 906    if ( ( certlen + nnlen + DBCERT_V4_HEADER_LEN ) != len ) {
 907	PORT_SetError(SEC_ERROR_BAD_DATABASE);
 908	return(0);
 909    }
 910
 911    /* allocate arena */
 912    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
 913
 914    if ( !arena ) {
 915	PORT_SetError(SEC_ERROR_NO_MEMORY);
 916	return(0);
 917    }
 918	
 919    /* allocate structure and members */
 920    entry = (certDBEntryCert *)  PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
 921
 922    if ( !entry ) {
 923	goto loser;
 924    }
 925
 926    entry->common.arena = arena;
 927    entry->common.version = CERT_DB_FILE_VERSION;
 928    entry->common.type = certDBEntryTypeCert;
 929    entry->common.flags = 0;
 930    entry->trust.sslFlags = buf[0];
 931    entry->trust.emailFlags = buf[1];
 932    entry->trust.objectSigningFlags = buf[2];
 933
 934    entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen);
 935    if ( !entry->derCert.data ) {
 936	goto loser;
 937    }
 938    entry->derCert.len = certlen;
 939    PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen);
 940
 941    if ( nnlen ) {
 942        entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen);
 943        if ( !entry->nickname ) {
 944            goto loser;
 945        }
 946        PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen);
 947        
 948        if (PORT_Strcmp(entry->nickname, "Server-Cert") == 0) {
 949            entry->trust.sslFlags |= CERTDB_USER;
 950        }
 951    } else {
 952        entry->nickname = 0;
 953    }
 954
 955    return(entry);
 956    
 957loser:
 958    PORT_FreeArena(arena, PR_FALSE);
 959    PORT_SetError(SEC_ERROR_NO_MEMORY);
 960    return(0);
 961}
 962
 963/*
 964 * Encode a Certificate database entry into byte stream suitable for
 965 * the database
 966 */
 967static SECStatus
 968WriteDBCertEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry)
 969{
 970    SECItem dbitem, dbkey;
 971    PRArenaPool *tmparena = NULL;
 972    SECItem tmpitem;
 973    SECStatus rv;
 974    
 975    tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 976    if ( tmparena == NULL ) {
 977	goto loser;
 978    }
 979    
 980    rv = EncodeDBCertEntry(entry, tmparena, &dbitem);
 981    if ( rv != SECSuccess ) {
 982	goto loser;
 983    }
 984
 985    /* get the database key and format it */
 986    rv = nsslowcert_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem);
 987    if ( rv == SECFailure ) {
 988	goto loser;
 989    }
 990
 991    rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey);
 992    if ( rv == SECFailure ) {
 993	goto loser;
 994    }
 995    
 996    /* now write it to the database */
 997    rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
 998    if ( rv != SECSuccess ) {
 999	goto loser;
1000    }
1001    
1002    PORT_FreeArena(tmparena, PR_FALSE);
1003    return(SECSuccess);
1004
1005loser:
1006    if ( tmparena ) {
1007	PORT_FreeArena(tmparena, PR_FALSE);
1008    }
1009    return(SECFailure);
1010}
1011
1012
1013/*
1014 * delete a certificate entry
1015 */
1016static SECStatus
1017DeleteDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
1018{
1019    SECItem dbkey;
1020    SECStatus rv;
1021
1022    dbkey.data= NULL;
1023    dbkey.len = 0;
1024
1025    rv = EncodeDBCertKey(certKey, NULL, &dbkey);
1026    if ( rv != SECSuccess ) {
1027	goto loser;
1028    }
1029    
1030    rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey);
1031    if ( rv == SECFailure ) {
1032	goto loser;
1033    }
1034
1035    PORT_Free(dbkey.data);
1036
1037    return(SECSuccess);
1038
1039loser:
1040    if (dbkey.data) {
1041	PORT_Free(dbkey.data);
1042    }
1043    return(SECFailure);
1044}
1045
1046static certDBEntryCert *
1047CreateCertEntry(void)
1048{
1049    certDBEntryCert *entry;
1050
1051    nsslowcert_LockFreeList();
1052    entry = entryListHead;
1053    if (entry) {
1054	entryListCount--;
1055	entryListHead = entry->next;
1056    }
1057    PORT_Assert(entryListCount >= 0);
1058    nsslowcert_UnlockFreeList();
1059    if (entry) {
1060	return entry;
1061    }
1062
1063    return PORT_ZNew(certDBEntryCert);
1064}
1065
1066static void
1067DestroyCertEntryFreeList(void)
1068{
1069    certDBEntryCert *entry;
1070
1071    nsslowcert_LockFreeList();
1072    while (NULL != (entry = entryListHead)) {
1073	entryListCount--;
1074	entryListHead = entry->next;
1075	PORT_Free(entry);
1076    }
1077    PORT_Assert(!entryListCount);
1078    entryListCount = 0;
1079    nsslowcert_UnlockFreeList();
1080}
1081
1082/*
1083 * Read a certificate entry
1084 */
1085static certDBEntryCert *
1086ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
1087{
1088    certDBEntryCert *entry;
1089    SECItem dbkey;
1090    SECItem dbentry;
1091    SECStatus rv;
1092    unsigned char buf[512];
1093
1094    dbkey.data = buf;
1095    dbkey.len = sizeof(buf);
1096
1097    entry = CreateCertEntry();
1098    if ( entry == NULL ) {
1099	PORT_SetError(SEC_ERROR_NO_MEMORY);
1100	goto loser;
1101    }
1102    entry->common.arena = NULL;
1103    entry->common.type = certDBEntryTypeCert;
1104
1105    rv = EncodeDBCertKey(certKey, NULL, &dbkey);
1106    if ( rv != SECSuccess ) {
1107	goto loser;
1108    }
1109    
1110    rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
1111    if ( rv == SECFailure ) {
1112	goto loser;
1113    }
1114
1115    rv = DecodeDBCertEntry(entry, &dbentry);
1116    if ( rv != SECSuccess ) {
1117	goto loser;
1118    }
1119
1120    pkcs11_freeStaticData(dbkey.data,buf);    
1121    dbkey.data = NULL;
1122    return(entry);
1123    
1124loser:
1125    pkcs11_freeStaticData(dbkey.data,buf);    
1126    dbkey.data = NULL;
1127    if ( entry ) {
1128        DestroyDBEntry((certDBEntry *)entry);
1129    }
1130    
1131    return(NULL);
1132}
1133
1134/*
1135 * encode a database cert record
1136 */
1137static SECStatus
1138EncodeDBCrlEntry(certDBEntryRevocation *entry, PRArenaPool *arena, SECItem *dbitem)
1139{
1140    unsigned int nnlen = 0;
1141    unsigned char *buf;
1142  
1143    if (entry->url) {  
1144	nnlen = PORT_Strlen(entry->url) + 1;
1145    }
1146    
1147    /* allocate space for encoded database record, including space
1148     * for low level header
1149     */
1150    dbitem->len = entry->derCrl.len + nnlen 
1151		+ SEC_DB_ENTRY_HEADER_LEN + DB_CRL_ENTRY_HEADER_LEN;
1152    
1153    dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
1154    if ( dbitem->data == NULL) {
1155	PORT_SetError(SEC_ERROR_NO_MEMORY);
1156	goto loser;
1157    }
1158    
1159    /* fill in database record */
1160    buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
1161    
1162    buf[0] = (PRUint8)( entry->derCrl.len >> 8 );
1163    buf[1] = (PRUint8)( entry->derCrl.len      );
1164    buf[2] = (PRUint8)( nnlen >> 8 );
1165    buf[3] = (PRUint8)( nnlen      );
1166    
1167    PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data,
1168	      entry->derCrl.len);
1169
1170    if (nnlen != 0) {
1171	PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
1172	      entry->url, nnlen);
1173    }
1174
1175    return(SECSuccess);
1176
1177loser:
1178    return(SECFailure);
1179}
1180
1181static SECStatus
1182DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry)
1183{
1184    unsigned int urlLen;
1185    int lenDiff;
1186
1187    /* is record long enough for header? */
1188    if ( dbentry->len < DB_CRL_ENTRY_HEADER_LEN ) {
1189	PORT_SetError(SEC_ERROR_BAD_DATABASE);
1190	goto loser;
1191    }
1192    
1193    /* is database entry correct length? */
1194    entry->derCrl.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
1195    urlLen =            ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
1196    lenDiff = dbentry->len - 
1197			(entry->derCrl.len + urlLen + DB_CRL_ENTRY_HEADER_LEN);
1198    if (lenDiff) {
1199    	if (lenDiff < 0 || (lenDiff & 0xffff) != 0) {
1200	    PORT_SetError(SEC_ERROR_BAD_DATABASE);
1201	    goto loser;
1202	}    
1203	/* CRL entry is greater than 64 K. Hack to make this continue to work */
1204	entry->derCrl.len += lenDiff;
1205    }
1206    
1207    /* copy the der CRL */
1208    entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1209							 entry->derCrl.len);
1210    if ( entry->derCrl.data == NULL ) {
1211	PORT_SetError(SEC_ERROR_NO_MEMORY);
1212	goto loser;
1213    }
1214    PORT_Memcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN],
1215	      entry->derCrl.len);
1216
1217    /* copy the url */
1218    entry->url = NULL;
1219    if (urlLen != 0) {
1220	entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, urlLen);
1221	if ( entry->url == NULL ) {
1222	    PORT_SetError(SEC_ERROR_NO_MEMORY);
1223	    goto loser;
1224	}
1225	PORT_Memcpy(entry->url,
1226	      &dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
1227	      urlLen);
1228    }
1229    
1230    return(SECSuccess);
1231loser:
1232    return(SECFailure);
1233}
1234
1235/*
1236 * Create a new certDBEntryRevocation from existing data
1237 */
1238static certDBEntryRevocation *
1239NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags)
1240{
1241    certDBEntryRevocation *entry;
1242    PRArenaPool *arena = NULL;
1243    int nnlen;
1244    
1245    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
1246
1247    if ( !arena ) {
1248	goto loser;
1249    }
1250	
1251    entry = PORT_ArenaZNew(arena, certDBEntryRevocation);
1252    if ( entry == NULL ) {
1253	goto loser;
1254    }
1255    
1256    /* fill in the dbRevolcation */
1257    entry->common.arena = arena;
1258    entry->common.type = crlType;
1259    entry->common.version = CERT_DB_FILE_VERSION;
1260    entry->common.flags = flags;
1261    
1262
1263    entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len);
1264    if ( !entry->derCrl.data ) {
1265	goto loser;
1266    }
1267
1268    if (url) {
1269	nnlen = PORT_Strlen(url) + 1;
1270	entry->url  = (char *)PORT_ArenaAlloc(arena, nnlen);
1271	if ( !entry->url ) {
1272	    goto loser;
1273	}
1274	PORT_Memcpy(entry->url, url, nnlen);
1275    } else {
1276	entry->url = NULL;
1277    }
1278
1279	
1280    entry->derCrl.len = derCrl->len;
1281    PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len);
1282
1283    return(entry);
1284
1285loser:
1286    
1287    /* allocation error, free arena and return */
1288    if ( arena ) {
1289	PORT_FreeArena(arena, PR_FALSE);
1290    }
1291    
1292    PORT_SetError(SEC_ERROR_NO_MEMORY);
1293    return(0);
1294}
1295
1296
1297static SECStatus
1298WriteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry,
1299				SECItem *crlKey )
1300{
1301    SECItem dbkey;
1302    PRArenaPool *tmparena = NULL;
1303    SECItem encodedEntry;
1304    SECStatus rv;
1305    
1306    tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1307    if ( tmparena == NULL ) {
1308	goto loser;
1309    }
1310
1311    rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry);
1312    if ( rv == SECFailure ) {
1313	goto loser;
1314    }
1315
1316    rv = EncodeDBGenericKey(crlKey, tmparena, &dbkey, entry->common.type);
1317    if ( rv == SECFailure ) {
1318	goto loser;
1319    }
1320    
1321    /* now write it to the database */
1322    rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry);
1323    if ( rv != SECSuccess ) {
1324	goto loser;
1325    }
1326    
1327    PORT_FreeArena(tmparena, PR_FALSE);
1328    return(SECSuccess);
1329
1330loser:
1331    if ( tmparena ) {
1332	PORT_FreeArena(tmparena, PR_FALSE);
1333    }
1334    return(SECFailure);
1335}
1336/*
1337 * delete a crl entry
1338 */
1339static SECStatus
1340DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *crlKey, 
1341						certDBEntryType crlType)
1342{
1343    SECItem dbkey;
1344    PRArenaPool *arena = NULL;
1345    SECStatus rv;
1346    
1347    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1348    if ( arena == NULL ) {
1349	goto loser;
1350    }
1351
1352    rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType);
1353    if ( rv != SECSuccess ) {
1354	goto loser;
1355    }
1356    
1357    rv = DeleteDBEntry(handle, crlType, &dbkey);
1358    if ( rv == SECFailure ) {
1359	goto loser;
1360    }
1361
1362    PORT_FreeArena(arena, PR_FALSE);
1363    return(SECSuccess);
1364
1365loser:
1366    if ( arena ) {
1367	PORT_FreeArena(arena, PR_FALSE);
1368    }
1369    
1370    return(SECFailure);
1371}
1372
1373/*
1374 * Read a certificate entry
1375 */
1376static certDBEntryRevocation *
1377ReadDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey,
1378						certDBEntryType crlType)
1379{
1380    PRArenaPool *arena = NULL;
1381    PRArenaPool *tmparena = NULL;
1382    certDBEntryRevocation *entry;
1383    SECItem dbkey;
1384    SECItem dbentry;
1385    SECStatus rv;
1386    
1387    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1388    if ( arena == NULL ) {
1389	PORT_SetError(SEC_ERROR_NO_MEMORY);
1390	goto loser;
1391    }
1392
1393    tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1394    if ( tmparena == NULL ) {
1395	PORT_SetError(SEC_ERROR_NO_MEMORY);
1396	goto loser;
1397    }
1398    
1399    entry = (certDBEntryRevocation *)
1400			PORT_ArenaAlloc(arena, sizeof(certDBEntryRevocation));
1401    if ( entry == NULL ) {
1402	PORT_SetError(SEC_ERROR_NO_MEMORY);
1403	goto loser;
1404    }
1405    entry->common.arena = arena;
1406    entry->common.type = crlType;
1407
1408    rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType);
1409    if ( rv != SECSuccess ) {
1410	goto loser;
1411    }
1412    
1413    rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
1414    if ( rv == SECFailure ) {
1415	goto loser;
1416    }
1417
1418    rv = DecodeDBCrlEntry(entry, &dbentry);
1419    if ( rv != SECSuccess ) {
1420	goto loser;
1421    }
1422    
1423    PORT_FreeArena(tmparena, PR_FALSE);
1424    return(entry);
1425    
1426loser:
1427    if ( tmparena ) {
1428	PORT_FreeArena(tmparena, PR_FALSE);
1429    }
1430    if ( arena ) {
1431	PORT_FreeArena(arena, PR_FALSE);
1432    }
1433    
1434    return(NULL);
1435}
1436
1437void
1438nsslowcert_DestroyDBEntry(certDBEntry *entry)
1439{
1440    DestroyDBEntry(entry);
1441    return;
1442}
1443
1444/*
1445 * Encode a database nickname record
1446 */
1447static SECStatus
1448EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena,
1449		      SECItem *dbitem)
1450{
1451    unsigned char *buf;
1452    
1453    /* allocate space for encoded database record, including space
1454     * for low level header
1455     */
1456    dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN +
1457	SEC_DB_ENTRY_HEADER_LEN;
1458    dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
1459    if ( dbitem->data == NULL) {
1460	goto loser;
1461    }
1462    
1463    /* fill in database record */
1464    buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
1465    buf[0] = (PRUint8)( entry->subjectName.len >> 8 );
1466    buf[1] = (PRUint8)( entry->subjectName.len      );
1467    PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data,
1468	      entry->subjectName.len);
1469
1470    return(SECSuccess);
1471
1472loser:
1473    return(SECFailure);
1474}
1475
1476/*
1477 * Encode a database key for a nickname record
1478 */
1479static SECStatus
1480EncodeDBNicknameKey(char *nickname, PRArenaPool *arena,
1481		    SECItem *dbkey)
1482{
1483    unsigned int nnlen;
1484    
1485    nnlen = PORT_Strlen(nickname) + 1; /* includes null */
1486
1487    /* now get the database key and format it */
1488    dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN;
1489    if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
1490	goto loser;
1491    dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
1492    if ( dbkey->data == NULL ) {
1493	goto loser;
1494    }
1495    PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], nickname, nnlen);
1496    dbkey->data[0] = certDBEntryTypeNickname;
1497
1498    return(SECSuccess);
1499
1500loser:
1501    return(SECFailure);
1502}
1503
1504static SECStatus
1505DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry,
1506                      char *nickname)
1507{
1508    int lenDiff;
1509
1510    /* is record long enough for header? */
1511    if ( dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
1512	PORT_SetError(SEC_ERROR_BAD_DATABASE);
1513	goto loser;
1514    }
1515    
1516    /* is database entry correct length? */
1517    entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
1518    lenDiff = dbentry->len - 
1519	      (entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN);
1520    if (lenDiff) {
1521	if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) { 
1522	    PORT_SetError(SEC_ERROR_BAD_DATABASE);
1523	    goto loser;
1524	}
1525	/* The entry size exceeded 64KB.  Reconstruct the correct length. */
1526	entry->subjectName.len += lenDiff;
1527    }
1528
1529    /* copy the certkey */
1530    entry->subjectName.data =
1531	(unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1532					 entry->subjectName.len);
1533    if ( entry->subjectName.data == NULL ) {
1534	PORT_SetError(SEC_ERROR_NO_MEMORY);
1535	goto loser;
1536    }
1537    PORT_Memcpy(entry->subjectName.data,
1538	      &dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN],
1539	      entry->subjectName.len);
1540    entry->subjectName.type = siBuffer;
1541    
1542    entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena, 
1543                                              PORT_Strlen(nickname)+1);
1544    if ( entry->nickname ) {
1545	PORT_Strcpy(entry->nickname, nickname);
1546    }
1547    
1548    return(SECSuccess);
1549
1550loser:
1551    return(SECFailure);
1552}
1553
1554/*
1555 * create a new nickname entry
1556 */
1557static certDBEntryNickname *
1558NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags)
1559{
1560    PRArenaPool *arena = NULL;
1561    certDBEntryNickname *entry;
1562    int nnlen;
1563    SECStatus rv;
1564    
1565    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1566    if ( arena == NULL ) {
1567	PORT_SetError(SEC_ERROR_NO_MEMORY);
1568	goto loser;
1569    }
1570
1571    entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
1572						 sizeof(certDBEntryNickname));
1573    if ( entry == NULL ) {
1574	PORT_SetError(SEC_ERROR_NO_MEMORY);
1575	goto loser;
1576    }
1577
1578    /* init common fields */
1579    entry->common.arena = arena;
1580    entry->common.type = certDBEntryTypeNickname;
1581    entry->common.version = CERT_DB_FILE_VERSION;
1582    entry->common.flags = flags;
1583
1584    /* copy the nickname */
1585    nnlen = PORT_Strlen(nickname) + 1;
1586    
1587    entry->nickname = (char*)PORT_ArenaAlloc(arena, nnlen);
1588    if ( entry->nickname == NULL ) {
1589	goto loser;
1590    }
1591    
1592    PORT_Memcpy(entry->nickname, nickname, nnlen);
1593    
1594    rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
1595    if ( rv != SECSuccess ) {
1596	goto loser;
1597    }
1598    
1599    return(entry);
1600loser:
1601    if ( arena ) {
1602	PORT_FreeArena(arena, PR_FALSE);
1603    }
1604    
1605    return(NULL);
1606}
1607
1608/*
1609 * delete a nickname entry
1610 */
1611static SECStatus
1612DeleteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
1613{
1614    PRArenaPool *arena = NULL;
1615    SECStatus rv;
1616    SECItem dbkey;
1617    
1618    if ( nickname == NULL ) {
1619	return(SECSuccess);
1620    }
1621    
1622    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1623    if ( arena == NULL ) {
1624	goto loser;
1625    }
1626
1627    rv = EncodeDBNicknameKey(nickname, arena, &dbkey);
1628    if ( rv != SECSuccess ) {
1629	goto loser;
1630    }
1631
1632    rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey);
1633    if ( rv == SECFailure ) {
1634	goto loser;
1635    }
1636
1637    PORT_FreeArena(arena, PR_FALSE);
1638    return(SECSuccess);
1639
1640loser:
1641    if ( arena ) {
1642	PORT_FreeArena(arena, PR_FALSE);
1643    }
1644    
1645    return(SECFailure);
1646}
1647
1648/*
1649 * Read a nickname entry
1650 */
1651static certDBEntryNickname *
1652ReadDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
1653{
1654    PRArenaPool *arena = NULL;
1655    PRArenaPool *tmparena = NULL;
1656    certDBEntryNickname *entry;
1657    SECItem dbkey;
1658    SECItem dbentry;
1659    SECStatus rv;
1660    
1661    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1662    if ( arena == NULL ) {
1663	PORT_SetError(SEC_ERROR_NO_MEMORY);
1664	goto loser;
1665    }
1666
1667    tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1668    if ( tmparena == NULL ) {
1669	PORT_SetError(SEC_ERROR_NO_MEMORY);
1670	goto loser;
1671    }
1672    
1673    entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
1674						 sizeof(certDBEntryNickname));
1675    if ( entry == NULL ) {
1676	PORT_SetError(SEC_ERROR_NO_MEMORY);
1677	goto loser;
1678    }
1679    entry->common.arena = arena;
1680    entry->common.type = certDBEntryTypeNickname;
1681
1682    rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey);
1683    if ( rv != SECSuccess ) {
1684	goto loser;
1685    }
1686    
1687    rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
1688    if ( rv == SECFailure ) {
1689	goto loser;
1690    }
1691
1692    /* is record long enough for header? */
1693    if ( dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
1694	PORT_SetError(SEC_ERROR_BAD_DATABASE);
1695	goto loser;
1696    }
1697
1698    rv = DecodeDBNicknameEntry(entry, &dbentry, nickname);
1699    if ( rv != SECSuccess ) {
1700	goto loser;
1701    }
1702    
1703    PORT_FreeArena(tmparena, PR_FALSE);
1704    return(entry);
1705    
1706loser:
1707    if ( tmparena ) {
1708	PORT_FreeArena(tmparena, PR_FALSE);
1709    }
1710    if ( arena ) {
1711	PORT_FreeArena(arena, PR_FALSE);
1712    }
1713    
1714    return(NULL);
1715}
1716
1717/*
1718 * Encode a nickname entry into byte stream suitable for
1719 * the database
1720 */
1721static SECStatus
1722WriteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryNickname *entry)
1723{
1724    SECItem dbitem, dbkey;
1725    PRArenaPool *tmparena = NULL;
1726    SECStatus rv;
1727    
1728    tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1729    if ( tmparena == NULL ) {
1730	goto loser;
1731    }
1732    
1733    rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem);
1734    if ( rv != SECSuccess ) {
1735	goto loser;
1736    }
1737
1738    rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey);
1739    if ( rv != SECSuccess ) {
1740	goto loser;
1741    }
1742
1743    /* now write it to the database */
1744    rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
1745    if ( rv != SECSuccess ) {
1746	goto loser;
1747    }
1748    
1749    PORT_FreeArena(tmparena, PR_FALSE);
1750    return(SECSuccess);
1751
1752loser:
1753    if ( tmparena ) {
1754	PORT_FreeArena(tmparena, PR_FALSE);
1755    }
1756    return(SECFailure);
1757    
1758}
1759
1760static SECStatus
1761EncodeDBSMimeEntry(certDBEntrySMime *entry, PRArenaPool *arena,
1762		   SECItem *dbitem)
1763{
1764    unsigned char *buf;
1765    
1766    /* allocate space for encoded database record, including space
1767     * for low level header
1768     */
1769    dbitem->len = entry->subjectName.len + entry->smimeOptions.len +
1770	entry->optionsDate.len +
1771	DB_SMIME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN;
1772    
1773    dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
1774    if ( dbitem->data == NULL) {
1775	PORT_SetError(SEC_ERROR_NO_MEMORY);
1776	goto loser;
1777    }
1778    
1779    /* fill in database record */
1780    buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
1781    
1782    buf[0] = (PRUint8)( entry->subjectName.len >> 8 );
1783    buf[1] = (PRUint8)( entry->subjectName.len      );
1784    buf[2] = (PRUint8)( entry->smimeOptions.len >> 8 );
1785    buf[3] = (PRUint8)( entry->smimeOptions.len      );
1786    buf[4] = (PRUint8)( entry->optionsDate.len >> 8 );
1787    buf[5] = (PRUint8)( entry->optionsDate.len      );
1788
1789    /* if no smime options, then there should not be an options date either */
1790    PORT_Assert( ! ( ( entry->smimeOptions.len == 0 ) &&
1791		    ( entry->optionsDate.len != 0 ) ) );
1792    
1793    PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN], entry->subjectName.data,
1794	      entry->subjectName.len);
1795    if ( entry->smimeOptions.len ) {
1796	PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN+entry->subjectName.len],
1797		    entry->smimeOptions.data,
1798		    entry->smimeOptions.len);
1799	PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len +
1800			 entry->smimeOptions.len],
1801		    entry->optionsDate.data,
1802		    entry->optionsDate.len);
1803    }
1804
1805    return(SECSuccess);
1806
1807loser:
1808    return(SECFailure);
1809}
1810
1811/*
1812 * Encode a database key for a SMIME record
1813 */
1814static SECStatus
1815EncodeDBSMimeKey(char *emailAddr, PRArenaPool *arena,
1816		 SECItem *dbkey)
1817{
1818    unsigned int addrlen;
1819    
1820    addrlen = PORT_Strlen(emailAddr) + 1; /* includes null */
1821
1822    /* now get the database key and format it */
1823    dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN;
1824    if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
1825	goto loser;
1826    dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
1827    if ( dbkey->data == NULL ) {
1828	goto loser;
1829    }
1830    PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], emailAddr, addrlen);
1831    dbkey->data[0] = certDBEntryTypeSMimeProfile;
1832
1833    return(SECSuccess);
1834
1835loser:
1836    return(SECFailure);
1837}
1838
1839/*
1840 * Decode a database SMIME record
1841 */
1842static SECStatus
1843DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr)
1844{
1845    int lenDiff;
1846
1847    /* is record long enough for header? */
1848    if ( dbentry->len < DB_SMIME_ENTRY_HEADER_LEN ) {
1849	PORT_SetError(SEC_ERROR_BAD_DATABASE);
1850	goto loser;
1851    }
1852    
1853    /* is database entry correct length? */
1854    entry->subjectName.len  = (( dbentry->data[0] << 8 ) | dbentry->data[1] );
1855    entry->smimeOptions.len = (( dbentry->data[2] << 8 ) | dbentry->data[3] );
1856    entry->optionsDate.len  = (( dbentry->data[4] << 8 ) | dbentry->data[5] );
1857    lenDiff = dbentry->len - (entry->subjectName.len + 
1858                              entry->smimeOptions.len + 
1859			      entry->optionsDate.len + 
1860			      DB_SMIME_ENTRY_HEADER_LEN);
1861    if (lenDiff) {
1862	if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) { 
1863	    PORT_SetError(SEC_ERROR_BAD_DATABASE);
1864	    goto loser;
1865	}
1866	/* The entry size exceeded 64KB.  Reconstruct the correct length. */
1867	entry->subjectName.len += lenDiff;
1868    }
1869
1870    /* copy the subject name */
1871    entry->subjectName.data =
1872	(unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1873					 entry->subjectName.len);
1874    if ( entry->subjectName.data == NULL ) {
1875	PORT_SetError(SEC_ERROR_NO_MEMORY);
1876	goto loser;
1877    }
1878    PORT_Memcpy(entry->subjectName.data,
1879	      &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN],
1880	      entry->subjectName.len);
1881
1882    /* copy the smime options */
1883    if ( entry->smimeOptions.len ) {
1884	entry->smimeOptions.data =
1885	    (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1886					     entry->smimeOptions.len);
1887	if ( entry->smimeOptions.data == NULL ) {
1888	    PORT_SetError(SEC_ERROR_NO_MEMORY);
1889	    goto loser;
1890	}
1891	PORT_Memcpy(entry->smimeOptions.data,
1892		    &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
1893				   entry->subjectName.len],
1894		    entry->smimeOptions.len);
1895    }
1896    if ( entry->optionsDate.len ) {
1897	entry->optionsDate.data =
1898	    (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1899					     entry->optionsDate.len);
1900	if ( entry->optionsDate.data == NULL ) {
1901	    PORT_SetError(SEC_ERROR_NO_MEMORY);
1902	    goto loser;
1903	}
1904	PORT_Memcpy(entry->optionsDate.data,
1905		    &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
1906				   entry->subjectName.len +
1907				   entry->smimeOptions.len],
1908		    entry->optionsDate.len);
1909    }
1910
1911    /* both options and options date must either exist or not exist */
1912    if ( ( ( entry->optionsDate.len == 0 ) ||
1913	  ( entry->smimeOptions.len == 0 ) ) &&
1914	entry->smimeOptions.len != entry->optionsDate.len ) {
1915	PORT_SetError(SEC_ERROR_BAD_DATABASE);
1916	goto loser;
1917    }
1918
1919    entry->emailAddr = (char *)PORT_ArenaAlloc(entry->common.arena,
1920						PORT_Strlen(emailAddr)+1);
1921    if ( entry->emailAddr ) {
1922	PORT_Strcpy(entry->emailAddr, emailAddr);
1923    }
1924    
1925    return(SECSuccess);
1926
1927loser:
1928    return(SECFailure);
1929}
1930
1931/*
1932 * create a new SMIME entry
1933 */
1934static certDBEntrySMime *
1935NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions,
1936		SECItem *optionsDate, unsigned int flags)
1937{
1938    PRArenaPool *arena = NULL;
1939    certDBEntrySMime *entry;
1940    int addrlen;
1941    SECStatus rv;
1942    
1943    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1944    if ( arena == NULL ) {
1945	PORT_SetError(SEC_ERROR_NO_MEMORY);
1946	goto loser;
1947    }
1948
1949    entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
1950						sizeof(certDBEntrySMime));
1951    if ( entry == NULL ) {
1952	PORT_SetError(SEC_ERROR_NO_MEMORY);
1953	goto loser;
1954    }
1955
1956    /* init common fields */
1957    entry->common.arena = arena;
1958    entry->common.type = certDBEntryTypeSMimeProfile;
1959    entry->common.version = CERT_DB_FILE_VERSION;
1960    entry->common.flags = flags;
1961
1962    /* copy the email addr */
1963    addrlen = PORT_Strlen(emailAddr) + 1;
1964    
1965    entry->emailAddr = (char*)PORT_ArenaAlloc(arena, addrlen);
1966    if ( entry->emailAddr == NULL ) {
1967	goto loser;
1968    }
1969    
1970    PORT_Memcpy(entry->emailAddr, emailAddr, addrlen);
1971    
1972    /* copy the subject name */
1973    rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
1974    if ( rv != SECSuccess ) {
1975	goto loser;
1976    }
1977
1978    /* copy the smime options */
1979    if ( smimeOptions ) {
1980	rv = SECITEM_CopyItem(arena, &entry->smimeOptions, smimeOptions);
1981	if ( rv != SECSuccess ) {
1982	    goto loser;
1983	}
1984    } else {
1985	PORT_Assert(optionsDate == NULL);
1986	entry->smimeOptions.data = NULL;
1987	entry->smimeOptions.len = 0;
1988    }
1989
1990    /* copy the options date */
1991    if ( optionsDate ) {
1992	rv = SECITEM_CopyItem(arena, &entry->optionsDate, optionsDate);
1993	if ( rv != SECSuccess ) {
1994	    goto loser;
1995	}
1996    } else {
1997	PORT_Assert(smimeOptions == NULL);
1998	entry->optionsDate.data = NULL;
1999	entry->optionsDate.len = 0;
2000    }
2001    
2002    return(entry);
2003loser:
2004    if ( arena ) {
2005	PORT_FreeArena(arena, PR_FALSE);
2006    }
2007    
2008    return(NULL);
2009}
2010
2011/*
2012 * delete a SMIME entry
2013 */
2014static SECStatus
2015DeleteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
2016{
2017    PRArenaPool *arena = NULL;
2018    SECStatus rv;
2019    SECItem dbkey;
2020    
2021    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2022    if ( arena == NULL ) {
2023	goto loser;
2024    }
2025
2026    rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey);
2027    if ( rv != SECSuccess ) {
2028	goto loser;
2029    }
2030
2031    rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey);
2032    if ( rv == SECFailure ) {
2033	goto loser;
2034    }
2035
2036    PORT_FreeArena(arena, PR_FALSE);
2037    return(SECSuccess);
2038
2039loser:
2040    if ( arena ) {
2041	PORT_FreeArena(arena, PR_FALSE);
2042    }
2043    
2044    return(SECFailure);
2045}
2046
2047/*
2048 * Read a SMIME entry
2049 */
2050certDBEntrySMime *
2051nsslowcert_ReadDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
2052{
2053    PRArenaPool *arena = NULL;
2054    PRArenaPool *tmparena = NULL;
2055    certDBEntrySMime *entry;
2056    SECItem dbkey;
2057    SECItem dbentry;
2058    SECStatus rv;
2059    
2060    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2061    if ( arena == NULL ) {
2062	PORT_SetError(SEC_ERROR_NO_MEMORY);
2063	goto loser;
2064    }
2065
2066    tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2067    if ( tmparena == NULL ) {
2068	PORT_SetError(SEC_ERROR_NO_MEMORY);
2069	goto loser;
2070    }
2071    
2072    entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
2073						sizeof(certDBEntrySMime));
2074    if ( entry == NULL ) {
2075	PORT_SetError(SEC_ERROR_NO_MEMORY);
2076	goto loser;
2077    }
2078    entry->common.arena = arena;
2079    entry->common.type = certDBEntryTypeSMimeProfile;
2080
2081    rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey);
2082    if ( 

Large files files are truncated, but you can click here to view the full file