Back to index

lightning-sunbird  0.9+nobinonly
pcertdb.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * Permanent Certificate database handling code 
00039  *
00040  * $Id: pcertdb.c,v 1.53.2.10 2006/05/17 20:46:59 alexei.volkov.bugs%sun.com Exp $
00041  */
00042 #include "prtime.h"
00043 
00044 #include "lowkeyti.h"
00045 #include "pcert.h"
00046 #include "mcom_db.h"
00047 #include "pcert.h"
00048 #include "secitem.h"
00049 #include "secder.h"
00050 
00051 /* Call to SFTK_FreeSlot below */
00052 
00053 #include "secasn1.h"
00054 #include "secerr.h"
00055 #include "nssilock.h"
00056 #include "prmon.h"
00057 #include "nsslocks.h"
00058 #include "base64.h"
00059 #include "sechash.h"
00060 #include "plhash.h"
00061 
00062 #include "cdbhdl.h"
00063 #include "pkcs11i.h"
00064 
00065 /* forward declaration */
00066 NSSLOWCERTCertificate *
00067 nsslowcert_FindCertByDERCertNoLocking(NSSLOWCERTCertDBHandle *handle, SECItem *derCert);
00068 static SECStatus
00069 nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, 
00070        char *emailAddr, SECItem *derSubject, SECItem *emailProfile, 
00071                                                  SECItem *profileTime);
00072 static SECStatus
00073 nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
00074     NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust);
00075 static SECStatus
00076 nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 
00077                      SECItem *crlKey, char *url, PRBool isKRL);
00078 
00079 static NSSLOWCERTCertificate *certListHead = NULL;
00080 static NSSLOWCERTTrust *trustListHead = NULL;
00081 static certDBEntryCert *entryListHead = NULL;
00082 static int certListCount = 0;
00083 static int trustListCount = 0;
00084 static int entryListCount = 0;
00085 #define MAX_CERT_LIST_COUNT 10
00086 #define MAX_TRUST_LIST_COUNT 10
00087 #define MAX_ENTRY_LIST_COUNT 10
00088 
00089 /*
00090  * the following functions are wrappers for the db library that implement
00091  * a global lock to make the database thread safe.
00092  */
00093 static PZLock *dbLock = NULL;
00094 static PZLock *certRefCountLock = NULL;
00095 static PZLock *certTrustLock = NULL;
00096 static PZLock *freeListLock = NULL;
00097 
00098 void
00099 certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle)
00100 {
00101     if (dbLock == NULL) {
00102        nss_InitLock(&dbLock, nssILockCertDB);
00103        PORT_Assert(dbLock != NULL);
00104     }
00105 }
00106 
00107 SECStatus
00108 nsslowcert_InitLocks(void)
00109 {
00110     if (freeListLock == NULL) {
00111        nss_InitLock(&freeListLock, nssILockRefLock);
00112        if (freeListLock == NULL) {
00113            return SECFailure;
00114        }
00115     }
00116     if (certRefCountLock == NULL) {
00117        nss_InitLock(&certRefCountLock, nssILockRefLock);
00118        if (certRefCountLock == NULL) {
00119            return SECFailure;
00120        }
00121     }
00122     if (certTrustLock == NULL ) {
00123        nss_InitLock(&certTrustLock, nssILockCertDB);
00124        if (certTrustLock == NULL) {
00125            return SECFailure;
00126        }
00127     }
00128     
00129     return SECSuccess;
00130 }
00131 
00132 /*
00133  * Acquire the global lock on the cert database.
00134  * This lock is currently used for the following operations:
00135  *     adding or deleting a cert to either the temp or perm databases
00136  *     converting a temp to perm or perm to temp
00137  *     changing (maybe just adding!?) the trust of a cert
00138  *      chaning the DB status checking Configuration
00139  */
00140 static void
00141 nsslowcert_LockDB(NSSLOWCERTCertDBHandle *handle)
00142 {
00143     PZ_EnterMonitor(handle->dbMon);
00144     return;
00145 }
00146 
00147 /*
00148  * Free the global cert database lock.
00149  */
00150 static void
00151 nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle)
00152 {
00153     PRStatus prstat;
00154     
00155     prstat = PZ_ExitMonitor(handle->dbMon);
00156     
00157     PORT_Assert(prstat == PR_SUCCESS);
00158     
00159     return;
00160 }
00161 
00162 
00163 /*
00164  * Acquire the cert reference count lock
00165  * There is currently one global lock for all certs, but I'm putting a cert
00166  * arg here so that it will be easy to make it per-cert in the future if
00167  * that turns out to be necessary.
00168  */
00169 static void
00170 nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert)
00171 {
00172     PORT_Assert(certRefCountLock != NULL);
00173     
00174     PZ_Lock(certRefCountLock);
00175     return;
00176 }
00177 
00178 /*
00179  * Free the cert reference count lock
00180  */
00181 static void
00182 nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert)
00183 {
00184     PRStatus prstat;
00185 
00186     PORT_Assert(certRefCountLock != NULL);
00187     
00188     prstat = PZ_Unlock(certRefCountLock);
00189     
00190     PORT_Assert(prstat == PR_SUCCESS);
00191 
00192     return;
00193 }
00194 
00195 /*
00196  * Acquire the cert trust lock
00197  * There is currently one global lock for all certs, but I'm putting a cert
00198  * arg here so that it will be easy to make it per-cert in the future if
00199  * that turns out to be necessary.
00200  */
00201 void
00202 nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert)
00203 {
00204     PORT_Assert(certTrustLock != NULL);
00205 
00206     PZ_Lock(certTrustLock);
00207     return;
00208 }
00209 
00210 /*
00211  * Free the cert trust lock
00212  */
00213 void
00214 nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert)
00215 {
00216     PRStatus prstat;
00217 
00218     PORT_Assert(certTrustLock != NULL);
00219     
00220     prstat = PZ_Unlock(certTrustLock);
00221     
00222     PORT_Assert(prstat == PR_SUCCESS);
00223 
00224     return;
00225 }
00226 
00227 
00228 /*
00229  * Acquire the cert reference count lock
00230  * There is currently one global lock for all certs, but I'm putting a cert
00231  * arg here so that it will be easy to make it per-cert in the future if
00232  * that turns out to be necessary.
00233  */
00234 static void
00235 nsslowcert_LockFreeList(void)
00236 {
00237     PORT_Assert(freeListLock != NULL);
00238     
00239     PZ_Lock(freeListLock);
00240     return;
00241 }
00242 
00243 /*
00244  * Free the cert reference count lock
00245  */
00246 static void
00247 nsslowcert_UnlockFreeList(void)
00248 {
00249     PRStatus prstat;
00250 
00251     PORT_Assert(freeListLock != NULL);
00252     
00253     prstat = PZ_Unlock(freeListLock);
00254     
00255     PORT_Assert(prstat == PR_SUCCESS);
00256 
00257     return;
00258 }
00259 
00260 NSSLOWCERTCertificate *
00261 nsslowcert_DupCertificate(NSSLOWCERTCertificate *c)
00262 {
00263     if (c) {
00264        nsslowcert_LockCertRefCount(c);
00265        ++c->referenceCount;
00266        nsslowcert_UnlockCertRefCount(c);
00267     }
00268     return c;
00269 }
00270 
00271 static int
00272 certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags)
00273 {
00274     PRStatus prstat;
00275     int ret;
00276     
00277     PORT_Assert(dbLock != NULL);
00278     PZ_Lock(dbLock);
00279 
00280     ret = (* db->get)(db, key, data, flags);
00281 
00282     prstat = PZ_Unlock(dbLock);
00283 
00284     return(ret);
00285 }
00286 
00287 static int
00288 certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags)
00289 {
00290     PRStatus prstat;
00291     int ret = 0;
00292 
00293     PORT_Assert(dbLock != NULL);
00294     PZ_Lock(dbLock);
00295 
00296     ret = (* db->put)(db, key, data, flags);
00297     
00298     prstat = PZ_Unlock(dbLock);
00299 
00300     return(ret);
00301 }
00302 
00303 static int
00304 certdb_Sync(DB *db, unsigned int flags)
00305 {
00306     PRStatus prstat;
00307     int ret;
00308 
00309     PORT_Assert(dbLock != NULL);
00310     PZ_Lock(dbLock);
00311 
00312     ret = (* db->sync)(db, flags);
00313     
00314     prstat = PZ_Unlock(dbLock);
00315 
00316     return(ret);
00317 }
00318 
00319 #define DB_NOT_FOUND -30991  /* from DBM 3.2 */
00320 static int
00321 certdb_Del(DB *db, DBT *key, unsigned int flags)
00322 {
00323     PRStatus prstat;
00324     int ret;
00325 
00326     PORT_Assert(dbLock != NULL);
00327     PZ_Lock(dbLock);
00328 
00329     ret = (* db->del)(db, key, flags);
00330     
00331     prstat = PZ_Unlock(dbLock);
00332 
00333     /* don't fail if the record is already deleted */
00334     if (ret == DB_NOT_FOUND) {
00335        ret = 0;
00336     }
00337 
00338     return(ret);
00339 }
00340 
00341 static int
00342 certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags)
00343 {
00344     PRStatus prstat;
00345     int ret;
00346     
00347     PORT_Assert(dbLock != NULL);
00348     PZ_Lock(dbLock);
00349     
00350     ret = (* db->seq)(db, key, data, flags);
00351 
00352     prstat = PZ_Unlock(dbLock);
00353 
00354     return(ret);
00355 }
00356 
00357 static void
00358 certdb_Close(DB *db)
00359 {
00360     PRStatus prstat;
00361 
00362     PORT_Assert(dbLock != NULL);
00363     PZ_Lock(dbLock);
00364 
00365     (* db->close)(db);
00366     
00367     prstat = PZ_Unlock(dbLock);
00368 
00369     return;
00370 }
00371 
00372 void
00373 pkcs11_freeNickname(char *nickname, char *space)
00374 {
00375     if (nickname && nickname != space) {
00376        PORT_Free(nickname);
00377     }
00378 }
00379 
00380 char *
00381 pkcs11_copyNickname(char *nickname,char *space, int spaceLen)
00382 {
00383     int len;
00384     char *copy = NULL;
00385 
00386     len = PORT_Strlen(nickname)+1;
00387     if (len <= spaceLen) {
00388        copy = space;
00389        PORT_Memcpy(copy,nickname,len);
00390     } else {
00391        copy = PORT_Strdup(nickname);
00392     }
00393 
00394     return copy;
00395 }
00396 
00397 void
00398 pkcs11_freeStaticData (unsigned char *data, unsigned char *space)
00399 {
00400     if (data && data != space) {
00401        PORT_Free(data);
00402     }
00403 }
00404 
00405 unsigned char *
00406 pkcs11_allocStaticData(int len, unsigned char *space, int spaceLen)
00407 {
00408     unsigned char *data = NULL;
00409 
00410     if (len <= spaceLen) {
00411        data = space;
00412     } else {
00413        data = (unsigned char *) PORT_Alloc(len);
00414     }
00415 
00416     return data;
00417 }
00418 
00419 unsigned char *
00420 pkcs11_copyStaticData(unsigned char *data, int len, 
00421                                    unsigned char *space, int spaceLen)
00422 {
00423     unsigned char *copy = pkcs11_allocStaticData(len, space, spaceLen);
00424     if (copy) {
00425        PORT_Memcpy(copy,data,len);
00426     }
00427 
00428     return copy;
00429 }
00430 
00431 /*
00432  * destroy a database entry
00433  */
00434 static void
00435 DestroyDBEntry(certDBEntry *entry)
00436 {
00437     PRArenaPool *arena = entry->common.arena;
00438 
00439     /* must be one of our certDBEntry from the free list */
00440     if (arena == NULL) {
00441        certDBEntryCert *certEntry;
00442        if ( entry->common.type != certDBEntryTypeCert) {
00443            return;
00444        }
00445        certEntry = (certDBEntryCert *)entry;
00446 
00447        pkcs11_freeStaticData(certEntry->derCert.data, certEntry->derCertSpace);
00448        pkcs11_freeNickname(certEntry->nickname, certEntry->nicknameSpace);
00449 
00450        nsslowcert_LockFreeList();
00451        if (entryListCount > MAX_ENTRY_LIST_COUNT) {
00452            PORT_Free(certEntry);
00453        } else {
00454            entryListCount++;
00455            PORT_Memset(certEntry, 0, sizeof( *certEntry));
00456            certEntry->next = entryListHead;
00457            entryListHead = certEntry;
00458        }
00459        nsslowcert_UnlockFreeList();
00460        return;
00461     }
00462 
00463 
00464     /* Zero out the entry struct, so that any further attempts to use it
00465      * will cause an exception (e.g. null pointer reference). */
00466     PORT_Memset(&entry->common, 0, sizeof entry->common);
00467     PORT_FreeArena(arena, PR_FALSE);
00468 
00469     return;
00470 }
00471 
00472 /* forward references */
00473 static void nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert);
00474 
00475 static SECStatus
00476 DeleteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey)
00477 {
00478     DBT key;
00479     int ret;
00480 
00481     /* init the database key */
00482     key.data = dbkey->data;
00483     key.size = dbkey->len;
00484     
00485     dbkey->data[0] = (unsigned char)type;
00486 
00487     /* delete entry from database */
00488     ret = certdb_Del(handle->permCertDB, &key, 0 );
00489     if ( ret != 0 ) {
00490        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00491        goto loser;
00492     }
00493 
00494     ret = certdb_Sync(handle->permCertDB, 0);
00495     if ( ret ) {
00496        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00497        goto loser;
00498     }
00499 
00500     return(SECSuccess);
00501     
00502 loser:
00503     return(SECFailure);
00504 }
00505 
00506 static SECStatus
00507 ReadDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
00508            SECItem *dbkey, SECItem *dbentry, PRArenaPool *arena)
00509 {
00510     DBT data, key;
00511     int ret;
00512     unsigned char *buf;
00513     
00514     /* init the database key */
00515     key.data = dbkey->data;
00516     key.size = dbkey->len;
00517     
00518     dbkey->data[0] = (unsigned char)entry->type;
00519 
00520     /* read entry from database */
00521     ret = certdb_Get(handle->permCertDB, &key, &data, 0 );
00522     if ( ret != 0 ) {
00523        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00524        goto loser;
00525     }
00526     
00527     /* validate the entry */
00528     if ( data.size < SEC_DB_ENTRY_HEADER_LEN ) {
00529        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00530        goto loser;
00531     }
00532     buf = (unsigned char *)data.data;
00533     /* version 7 has the same schema, we may be using a v7 db if we openned
00534      * the databases readonly. */
00535     if (!((buf[0] == (unsigned char)CERT_DB_FILE_VERSION) 
00536               || (buf[0] == (unsigned char) CERT_DB_V7_FILE_VERSION))) {
00537        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00538        goto loser;
00539     }
00540     if ( buf[1] != (unsigned char)entry->type ) {
00541        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00542        goto loser;
00543     }
00544 
00545     /* copy out header information */
00546     entry->version = (unsigned int)buf[0];
00547     entry->type = (certDBEntryType)buf[1];
00548     entry->flags = (unsigned int)buf[2];
00549     
00550     /* format body of entry for return to caller */
00551     dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN;
00552     if ( dbentry->len ) {
00553        if (arena) {
00554            dbentry->data = (unsigned char *)
00555                             PORT_ArenaAlloc(arena, dbentry->len);
00556            if ( dbentry->data == NULL ) {
00557               PORT_SetError(SEC_ERROR_NO_MEMORY);
00558               goto loser;
00559            }
00560     
00561            PORT_Memcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN],
00562                 dbentry->len);
00563        } else {
00564            dbentry->data = &buf[SEC_DB_ENTRY_HEADER_LEN];
00565        }
00566     } else {
00567        dbentry->data = NULL;
00568     }
00569     
00570     return(SECSuccess);
00571 
00572 loser:
00573     return(SECFailure);
00574 }
00575 
00579 static SECStatus
00580 WriteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
00581             SECItem *dbkey, SECItem *dbentry)
00582 {
00583     int ret;
00584     DBT data, key;
00585     unsigned char *buf;
00586     
00587     data.data = dbentry->data;
00588     data.size = dbentry->len;
00589     
00590     buf = (unsigned char*)data.data;
00591     
00592     buf[0] = (unsigned char)entry->version;
00593     buf[1] = (unsigned char)entry->type;
00594     buf[2] = (unsigned char)entry->flags;
00595     
00596     key.data = dbkey->data;
00597     key.size = dbkey->len;
00598     
00599     dbkey->data[0] = (unsigned char)entry->type;
00600 
00601     /* put the record into the database now */
00602     ret = certdb_Put(handle->permCertDB, &key, &data, 0);
00603 
00604     if ( ret != 0 ) {
00605        goto loser;
00606     }
00607 
00608     ret = certdb_Sync( handle->permCertDB, 0 );
00609     
00610     if ( ret ) {
00611        goto loser;
00612     }
00613 
00614     return(SECSuccess);
00615 
00616 loser:
00617     return(SECFailure);
00618 }
00619 
00620 /*
00621  * encode a database cert record
00622  */
00623 static SECStatus
00624 EncodeDBCertEntry(certDBEntryCert *entry, PRArenaPool *arena, SECItem *dbitem)
00625 {
00626     unsigned int nnlen;
00627     unsigned char *buf;
00628     char *nn;
00629     char zbuf = 0;
00630     
00631     if ( entry->nickname ) {
00632        nn = entry->nickname;
00633     } else {
00634        nn = &zbuf;
00635     }
00636     nnlen = PORT_Strlen(nn) + 1;
00637     
00638     /* allocate space for encoded database record, including space
00639      * for low level header
00640      */
00641     dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN +
00642        SEC_DB_ENTRY_HEADER_LEN;
00643     
00644     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
00645     if ( dbitem->data == NULL) {
00646        PORT_SetError(SEC_ERROR_NO_MEMORY);
00647        goto loser;
00648     }
00649     
00650     /* fill in database record */
00651     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
00652     
00653     buf[0] = ( entry->trust.sslFlags >> 8 ) & 0xff;
00654     buf[1] = entry->trust.sslFlags & 0xff;
00655     buf[2] = ( entry->trust.emailFlags >> 8 ) & 0xff;
00656     buf[3] = entry->trust.emailFlags & 0xff;
00657     buf[4] = ( entry->trust.objectSigningFlags >> 8 ) & 0xff;
00658     buf[5] = entry->trust.objectSigningFlags & 0xff;
00659     buf[6] = ( entry->derCert.len >> 8 ) & 0xff;
00660     buf[7] = entry->derCert.len & 0xff;
00661     buf[8] = ( nnlen >> 8 ) & 0xff;
00662     buf[9] = nnlen & 0xff;
00663     
00664     PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data,
00665              entry->derCert.len);
00666 
00667     PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN + entry->derCert.len],
00668              nn, nnlen);
00669 
00670     return(SECSuccess);
00671 
00672 loser:
00673     return(SECFailure);
00674 }
00675 
00676 /*
00677  * encode a database key for a cert record
00678  */
00679 static SECStatus
00680 EncodeDBCertKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey)
00681 {
00682     unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN;
00683     if (arena) {
00684        dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
00685     } else {
00686        if (dbkey->len < len) {
00687            dbkey->data = (unsigned char *)PORT_Alloc(len);
00688        }
00689     }
00690     dbkey->len = len;
00691     if ( dbkey->data == NULL ) {
00692        goto loser;
00693     }
00694     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
00695              certKey->data, certKey->len);
00696     dbkey->data[0] = certDBEntryTypeCert;
00697 
00698     return(SECSuccess);
00699 loser:
00700     return(SECFailure);
00701 }
00702 
00703 static SECStatus
00704 EncodeDBGenericKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey, 
00705                             certDBEntryType entryType)
00706 {
00707     /*
00708      * we only allow _one_ KRL key!
00709      */
00710     if (entryType == certDBEntryTypeKeyRevocation) {
00711        dbkey->len = SEC_DB_KEY_HEADER_LEN;
00712        dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
00713        if ( dbkey->data == NULL ) {
00714            goto loser;
00715        }
00716         dbkey->data[0] = (unsigned char) entryType;
00717         return(SECSuccess);
00718     }
00719     
00720 
00721     dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN;
00722     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
00723     if ( dbkey->data == NULL ) {
00724        goto loser;
00725     }
00726     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
00727              certKey->data, certKey->len);
00728     dbkey->data[0] = (unsigned char) entryType;
00729 
00730     return(SECSuccess);
00731 loser:
00732     return(SECFailure);
00733 }
00734 
00735 static SECStatus
00736 DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry)
00737 {
00738     unsigned int nnlen;
00739     unsigned int headerlen;
00740     int lenoff;
00741 
00742     /* allow updates of old versions of the database */
00743     switch ( entry->common.version ) {
00744       case 5:
00745        headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
00746        lenoff = 3;
00747        break;
00748       case 6:
00749        /* should not get here */
00750        PORT_Assert(0);
00751        headerlen = DB_CERT_V6_ENTRY_HEADER_LEN;
00752        lenoff = 3;
00753        break;
00754       case 7:
00755       case 8:
00756        headerlen = DB_CERT_ENTRY_HEADER_LEN;
00757        lenoff = 6;
00758        break;
00759       default:
00760        /* better not get here */
00761        PORT_Assert(0);
00762        headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
00763        lenoff = 3;
00764        break;
00765     }
00766     
00767     /* is record long enough for header? */
00768     if ( dbentry->len < headerlen ) {
00769        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00770        goto loser;
00771     }
00772     
00773     /* is database entry correct length? */
00774     entry->derCert.len = ( ( dbentry->data[lenoff] << 8 ) |
00775                        dbentry->data[lenoff+1] );
00776     nnlen = ( ( dbentry->data[lenoff+2] << 8 ) | dbentry->data[lenoff+3] );
00777     if ( ( entry->derCert.len + nnlen + headerlen )
00778        != dbentry->len) {
00779        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00780        goto loser;
00781     }
00782     
00783     /* copy the dercert */
00784 
00785     entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen],
00786        entry->derCert.len,entry->derCertSpace,sizeof(entry->derCertSpace));
00787     if ( entry->derCert.data == NULL ) {
00788        PORT_SetError(SEC_ERROR_NO_MEMORY);
00789        goto loser;
00790     }
00791 
00792     /* copy the nickname */
00793     if ( nnlen > 1 ) {
00794        entry->nickname = (char *)pkcs11_copyStaticData(
00795                      &dbentry->data[headerlen+entry->derCert.len], nnlen,
00796                      (unsigned char *)entry->nicknameSpace, 
00797                      sizeof(entry->nicknameSpace));
00798        if ( entry->nickname == NULL ) {
00799            PORT_SetError(SEC_ERROR_NO_MEMORY);
00800            goto loser;
00801        }
00802     } else {
00803        entry->nickname = NULL;
00804     }
00805     
00806     if ( entry->common.version < 7 ) {
00807        /* allow updates of v5 db */
00808        entry->trust.sslFlags = dbentry->data[0];
00809        entry->trust.emailFlags = dbentry->data[1];
00810        entry->trust.objectSigningFlags = dbentry->data[2];
00811     } else {
00812        entry->trust.sslFlags = ( dbentry->data[0] << 8 ) | dbentry->data[1];
00813        entry->trust.emailFlags = ( dbentry->data[2] << 8 ) | dbentry->data[3];
00814        entry->trust.objectSigningFlags =
00815            ( dbentry->data[4] << 8 ) | dbentry->data[5];
00816     }
00817     
00818     return(SECSuccess);
00819 loser:
00820     return(SECFailure);
00821 }
00822 
00823 
00824 /*
00825  * Create a new certDBEntryCert from existing data
00826  */
00827 static certDBEntryCert *
00828 NewDBCertEntry(SECItem *derCert, char *nickname,
00829               NSSLOWCERTCertTrust *trust, int flags)
00830 {
00831     certDBEntryCert *entry;
00832     PRArenaPool *arena = NULL;
00833     int nnlen;
00834     
00835     arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
00836 
00837     if ( !arena ) {
00838        goto loser;
00839     }
00840        
00841     entry = PORT_ArenaZNew(arena, certDBEntryCert);
00842     if ( entry == NULL ) {
00843        goto loser;
00844     }
00845     
00846     /* fill in the dbCert */
00847     entry->common.arena = arena;
00848     entry->common.type = certDBEntryTypeCert;
00849     entry->common.version = CERT_DB_FILE_VERSION;
00850     entry->common.flags = flags;
00851     
00852     if ( trust ) {
00853        entry->trust = *trust;
00854     }
00855 
00856     entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, derCert->len);
00857     if ( !entry->derCert.data ) {
00858        goto loser;
00859     }
00860     entry->derCert.len = derCert->len;
00861     PORT_Memcpy(entry->derCert.data, derCert->data, derCert->len);
00862     
00863     nnlen = ( nickname ? strlen(nickname) + 1 : 0 );
00864     
00865     if ( nnlen ) {
00866        entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
00867        if ( !entry->nickname ) {
00868            goto loser;
00869        }
00870        PORT_Memcpy(entry->nickname, nickname, nnlen);
00871        
00872     } else {
00873        entry->nickname = 0;
00874     }
00875 
00876     return(entry);
00877 
00878 loser:
00879     
00880     /* allocation error, free arena and return */
00881     if ( arena ) {
00882        PORT_FreeArena(arena, PR_FALSE);
00883     }
00884     
00885     PORT_SetError(SEC_ERROR_NO_MEMORY);
00886     return(0);
00887 }
00888 
00889 /*
00890  * Decode a version 4 DBCert from the byte stream database format
00891  * and construct a current database entry struct
00892  */
00893 static certDBEntryCert *
00894 DecodeV4DBCertEntry(unsigned char *buf, int len)
00895 {
00896     certDBEntryCert *entry;
00897     int certlen;
00898     int nnlen;
00899     PRArenaPool *arena;
00900     
00901     /* make sure length is at least long enough for the header */
00902     if ( len < DBCERT_V4_HEADER_LEN ) {
00903        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00904        return(0);
00905     }
00906 
00907     /* get other lengths */
00908     certlen = buf[3] << 8 | buf[4];
00909     nnlen = buf[5] << 8 | buf[6];
00910     
00911     /* make sure DB entry is the right size */
00912     if ( ( certlen + nnlen + DBCERT_V4_HEADER_LEN ) != len ) {
00913        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00914        return(0);
00915     }
00916 
00917     /* allocate arena */
00918     arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
00919 
00920     if ( !arena ) {
00921        PORT_SetError(SEC_ERROR_NO_MEMORY);
00922        return(0);
00923     }
00924        
00925     /* allocate structure and members */
00926     entry = (certDBEntryCert *)  PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
00927 
00928     if ( !entry ) {
00929        goto loser;
00930     }
00931 
00932     entry->common.arena = arena;
00933     entry->common.version = CERT_DB_FILE_VERSION;
00934     entry->common.type = certDBEntryTypeCert;
00935     entry->common.flags = 0;
00936     entry->trust.sslFlags = buf[0];
00937     entry->trust.emailFlags = buf[1];
00938     entry->trust.objectSigningFlags = buf[2];
00939 
00940     entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen);
00941     if ( !entry->derCert.data ) {
00942        goto loser;
00943     }
00944     entry->derCert.len = certlen;
00945     PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen);
00946 
00947     if ( nnlen ) {
00948         entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen);
00949         if ( !entry->nickname ) {
00950             goto loser;
00951         }
00952         PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen);
00953         
00954         if (PORT_Strcmp(entry->nickname, "Server-Cert") == 0) {
00955             entry->trust.sslFlags |= CERTDB_USER;
00956         }
00957     } else {
00958         entry->nickname = 0;
00959     }
00960 
00961     return(entry);
00962     
00963 loser:
00964     PORT_FreeArena(arena, PR_FALSE);
00965     PORT_SetError(SEC_ERROR_NO_MEMORY);
00966     return(0);
00967 }
00968 
00969 /*
00970  * Encode a Certificate database entry into byte stream suitable for
00971  * the database
00972  */
00973 static SECStatus
00974 WriteDBCertEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry)
00975 {
00976     SECItem dbitem, dbkey;
00977     PRArenaPool *tmparena = NULL;
00978     SECItem tmpitem;
00979     SECStatus rv;
00980     
00981     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00982     if ( tmparena == NULL ) {
00983        goto loser;
00984     }
00985     
00986     rv = EncodeDBCertEntry(entry, tmparena, &dbitem);
00987     if ( rv != SECSuccess ) {
00988        goto loser;
00989     }
00990 
00991     /* get the database key and format it */
00992     rv = nsslowcert_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem);
00993     if ( rv == SECFailure ) {
00994        goto loser;
00995     }
00996 
00997     rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey);
00998     if ( rv == SECFailure ) {
00999        goto loser;
01000     }
01001     
01002     /* now write it to the database */
01003     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
01004     if ( rv != SECSuccess ) {
01005        goto loser;
01006     }
01007     
01008     PORT_FreeArena(tmparena, PR_FALSE);
01009     return(SECSuccess);
01010 
01011 loser:
01012     if ( tmparena ) {
01013        PORT_FreeArena(tmparena, PR_FALSE);
01014     }
01015     return(SECFailure);
01016 }
01017 
01018 
01019 /*
01020  * delete a certificate entry
01021  */
01022 static SECStatus
01023 DeleteDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
01024 {
01025     SECItem dbkey;
01026     SECStatus rv;
01027 
01028     dbkey.data= NULL;
01029     dbkey.len = 0;
01030 
01031     rv = EncodeDBCertKey(certKey, NULL, &dbkey);
01032     if ( rv != SECSuccess ) {
01033        goto loser;
01034     }
01035     
01036     rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey);
01037     if ( rv == SECFailure ) {
01038        goto loser;
01039     }
01040 
01041     if (dbkey.data) {
01042        PORT_Free(dbkey.data);
01043     }
01044     return(SECSuccess);
01045 
01046 loser:
01047     if (dbkey.data) {
01048        PORT_Free(dbkey.data);
01049     }
01050     return(SECFailure);
01051 }
01052 
01053 static certDBEntryCert *
01054 CreateCertEntry(void)
01055 {
01056     certDBEntryCert *entry;
01057 
01058     nsslowcert_LockFreeList();
01059     entry = entryListHead;
01060     if (entry) {
01061        entryListCount--;
01062        entryListHead = entry->next;
01063     }
01064     PORT_Assert(entryListCount >= 0);
01065     nsslowcert_UnlockFreeList();
01066     if (entry) {
01067        return entry;
01068     }
01069 
01070     return PORT_ZNew(certDBEntryCert);
01071 }
01072 
01073 static void
01074 DestroyCertEntryFreeList(void)
01075 {
01076     certDBEntryCert *entry;
01077 
01078     nsslowcert_LockFreeList();
01079     while (NULL != (entry = entryListHead)) {
01080        entryListCount--;
01081        entryListHead = entry->next;
01082        PORT_Free(entry);
01083     }
01084     PORT_Assert(!entryListCount);
01085     entryListCount = 0;
01086     nsslowcert_UnlockFreeList();
01087 }
01088 
01089 /*
01090  * Read a certificate entry
01091  */
01092 static certDBEntryCert *
01093 ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
01094 {
01095     certDBEntryCert *entry;
01096     SECItem dbkey;
01097     SECItem dbentry;
01098     SECStatus rv;
01099     unsigned char buf[512];
01100 
01101     dbkey.data = buf;
01102     dbkey.len = sizeof(buf);
01103 
01104     entry = CreateCertEntry();
01105     if ( entry == NULL ) {
01106        PORT_SetError(SEC_ERROR_NO_MEMORY);
01107        goto loser;
01108     }
01109     entry->common.arena = NULL;
01110     entry->common.type = certDBEntryTypeCert;
01111 
01112     rv = EncodeDBCertKey(certKey, NULL, &dbkey);
01113     if ( rv != SECSuccess ) {
01114        goto loser;
01115     }
01116     
01117     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
01118     if ( rv == SECFailure ) {
01119        goto loser;
01120     }
01121 
01122     rv = DecodeDBCertEntry(entry, &dbentry);
01123     if ( rv != SECSuccess ) {
01124        goto loser;
01125     }
01126 
01127     pkcs11_freeStaticData(dbkey.data,buf);    
01128     dbkey.data = NULL;
01129     return(entry);
01130     
01131 loser:
01132     pkcs11_freeStaticData(dbkey.data,buf);    
01133     dbkey.data = NULL;
01134     if ( entry ) {
01135         DestroyDBEntry((certDBEntry *)entry);
01136     }
01137     
01138     return(NULL);
01139 }
01140 
01141 /*
01142  * encode a database cert record
01143  */
01144 static SECStatus
01145 EncodeDBCrlEntry(certDBEntryRevocation *entry, PRArenaPool *arena, SECItem *dbitem)
01146 {
01147     unsigned int nnlen = 0;
01148     unsigned char *buf;
01149   
01150     if (entry->url) {  
01151        nnlen = PORT_Strlen(entry->url) + 1;
01152     }
01153     
01154     /* allocate space for encoded database record, including space
01155      * for low level header
01156      */
01157     dbitem->len = entry->derCrl.len + nnlen 
01158               + SEC_DB_ENTRY_HEADER_LEN + DB_CRL_ENTRY_HEADER_LEN;
01159     
01160     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
01161     if ( dbitem->data == NULL) {
01162        PORT_SetError(SEC_ERROR_NO_MEMORY);
01163        goto loser;
01164     }
01165     
01166     /* fill in database record */
01167     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
01168     
01169     buf[0] = ( entry->derCrl.len >> 8 ) & 0xff;
01170     buf[1] = entry->derCrl.len & 0xff;
01171     buf[2] = ( nnlen >> 8 ) & 0xff;
01172     buf[3] = nnlen & 0xff;
01173     
01174     PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data,
01175              entry->derCrl.len);
01176 
01177     if (nnlen != 0) {
01178        PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
01179              entry->url, nnlen);
01180     }
01181 
01182     return(SECSuccess);
01183 
01184 loser:
01185     return(SECFailure);
01186 }
01187 
01188 static SECStatus
01189 DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry)
01190 {
01191     unsigned int nnlen;
01192     
01193     /* is record long enough for header? */
01194     if ( dbentry->len < DB_CRL_ENTRY_HEADER_LEN ) {
01195        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01196        goto loser;
01197     }
01198     
01199     /* is database entry correct length? */
01200     entry->derCrl.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
01201     nnlen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
01202     if ( ( entry->derCrl.len + nnlen + DB_CRL_ENTRY_HEADER_LEN )
01203        != dbentry->len) {
01204       /* CRL entry is greater than 64 K. Hack to make this continue to work */
01205       if (dbentry->len >= (0xffff - DB_CRL_ENTRY_HEADER_LEN) - nnlen) {
01206           entry->derCrl.len = 
01207                       (dbentry->len - DB_CRL_ENTRY_HEADER_LEN) - nnlen;
01208       } else {
01209           PORT_SetError(SEC_ERROR_BAD_DATABASE);
01210           goto loser;
01211       }    
01212     }
01213     
01214     /* copy the dercert */
01215     entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
01216                                                   entry->derCrl.len);
01217     if ( entry->derCrl.data == NULL ) {
01218        PORT_SetError(SEC_ERROR_NO_MEMORY);
01219        goto loser;
01220     }
01221     PORT_Memcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN],
01222              entry->derCrl.len);
01223 
01224     /* copy the url */
01225     entry->url = NULL;
01226     if (nnlen != 0) {
01227        entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, nnlen);
01228        if ( entry->url == NULL ) {
01229            PORT_SetError(SEC_ERROR_NO_MEMORY);
01230            goto loser;
01231        }
01232        PORT_Memcpy(entry->url,
01233              &dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
01234              nnlen);
01235     }
01236     
01237     return(SECSuccess);
01238 loser:
01239     return(SECFailure);
01240 }
01241 
01242 /*
01243  * Create a new certDBEntryRevocation from existing data
01244  */
01245 static certDBEntryRevocation *
01246 NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags)
01247 {
01248     certDBEntryRevocation *entry;
01249     PRArenaPool *arena = NULL;
01250     int nnlen;
01251     
01252     arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
01253 
01254     if ( !arena ) {
01255        goto loser;
01256     }
01257        
01258     entry = PORT_ArenaZNew(arena, certDBEntryRevocation);
01259     if ( entry == NULL ) {
01260        goto loser;
01261     }
01262     
01263     /* fill in the dbRevolcation */
01264     entry->common.arena = arena;
01265     entry->common.type = crlType;
01266     entry->common.version = CERT_DB_FILE_VERSION;
01267     entry->common.flags = flags;
01268     
01269 
01270     entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len);
01271     if ( !entry->derCrl.data ) {
01272        goto loser;
01273     }
01274 
01275     if (url) {
01276        nnlen = PORT_Strlen(url) + 1;
01277        entry->url  = (char *)PORT_ArenaAlloc(arena, nnlen);
01278        if ( !entry->url ) {
01279            goto loser;
01280        }
01281        PORT_Memcpy(entry->url, url, nnlen);
01282     } else {
01283        entry->url = NULL;
01284     }
01285 
01286        
01287     entry->derCrl.len = derCrl->len;
01288     PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len);
01289 
01290     return(entry);
01291 
01292 loser:
01293     
01294     /* allocation error, free arena and return */
01295     if ( arena ) {
01296        PORT_FreeArena(arena, PR_FALSE);
01297     }
01298     
01299     PORT_SetError(SEC_ERROR_NO_MEMORY);
01300     return(0);
01301 }
01302 
01303 
01304 static SECStatus
01305 WriteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry,
01306                             SECItem *crlKey )
01307 {
01308     SECItem dbkey;
01309     PRArenaPool *tmparena = NULL;
01310     SECItem encodedEntry;
01311     SECStatus rv;
01312     
01313     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01314     if ( tmparena == NULL ) {
01315        goto loser;
01316     }
01317 
01318     rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry);
01319     if ( rv == SECFailure ) {
01320        goto loser;
01321     }
01322 
01323     rv = EncodeDBGenericKey(crlKey, tmparena, &dbkey, entry->common.type);
01324     if ( rv == SECFailure ) {
01325        goto loser;
01326     }
01327     
01328     /* now write it to the database */
01329     rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry);
01330     if ( rv != SECSuccess ) {
01331        goto loser;
01332     }
01333     
01334     PORT_FreeArena(tmparena, PR_FALSE);
01335     return(SECSuccess);
01336 
01337 loser:
01338     if ( tmparena ) {
01339        PORT_FreeArena(tmparena, PR_FALSE);
01340     }
01341     return(SECFailure);
01342 }
01343 /*
01344  * delete a crl entry
01345  */
01346 static SECStatus
01347 DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *crlKey, 
01348                                           certDBEntryType crlType)
01349 {
01350     SECItem dbkey;
01351     PRArenaPool *arena = NULL;
01352     SECStatus rv;
01353     
01354     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01355     if ( arena == NULL ) {
01356        goto loser;
01357     }
01358 
01359     rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType);
01360     if ( rv != SECSuccess ) {
01361        goto loser;
01362     }
01363     
01364     rv = DeleteDBEntry(handle, crlType, &dbkey);
01365     if ( rv == SECFailure ) {
01366        goto loser;
01367     }
01368 
01369     PORT_FreeArena(arena, PR_FALSE);
01370     return(SECSuccess);
01371 
01372 loser:
01373     if ( arena ) {
01374        PORT_FreeArena(arena, PR_FALSE);
01375     }
01376     
01377     return(SECFailure);
01378 }
01379 
01380 /*
01381  * Read a certificate entry
01382  */
01383 static certDBEntryRevocation *
01384 ReadDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey,
01385                                           certDBEntryType crlType)
01386 {
01387     PRArenaPool *arena = NULL;
01388     PRArenaPool *tmparena = NULL;
01389     certDBEntryRevocation *entry;
01390     SECItem dbkey;
01391     SECItem dbentry;
01392     SECStatus rv;
01393     
01394     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01395     if ( arena == NULL ) {
01396        PORT_SetError(SEC_ERROR_NO_MEMORY);
01397        goto loser;
01398     }
01399 
01400     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01401     if ( tmparena == NULL ) {
01402        PORT_SetError(SEC_ERROR_NO_MEMORY);
01403        goto loser;
01404     }
01405     
01406     entry = (certDBEntryRevocation *)
01407                      PORT_ArenaAlloc(arena, sizeof(certDBEntryRevocation));
01408     if ( entry == NULL ) {
01409        PORT_SetError(SEC_ERROR_NO_MEMORY);
01410        goto loser;
01411     }
01412     entry->common.arena = arena;
01413     entry->common.type = crlType;
01414 
01415     rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType);
01416     if ( rv != SECSuccess ) {
01417        goto loser;
01418     }
01419     
01420     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
01421     if ( rv == SECFailure ) {
01422        goto loser;
01423     }
01424 
01425     rv = DecodeDBCrlEntry(entry, &dbentry);
01426     if ( rv != SECSuccess ) {
01427        goto loser;
01428     }
01429     
01430     PORT_FreeArena(tmparena, PR_FALSE);
01431     return(entry);
01432     
01433 loser:
01434     if ( tmparena ) {
01435        PORT_FreeArena(tmparena, PR_FALSE);
01436     }
01437     if ( arena ) {
01438        PORT_FreeArena(arena, PR_FALSE);
01439     }
01440     
01441     return(NULL);
01442 }
01443 
01444 void
01445 nsslowcert_DestroyDBEntry(certDBEntry *entry)
01446 {
01447     DestroyDBEntry(entry);
01448     return;
01449 }
01450 
01451 /*
01452  * Encode a database nickname record
01453  */
01454 static SECStatus
01455 EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena,
01456                     SECItem *dbitem)
01457 {
01458     unsigned char *buf;
01459     
01460     /* allocate space for encoded database record, including space
01461      * for low level header
01462      */
01463     dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN +
01464        SEC_DB_ENTRY_HEADER_LEN;
01465     
01466     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
01467     if ( dbitem->data == NULL) {
01468        goto loser;
01469     }
01470     
01471     /* fill in database record */
01472     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
01473     
01474     buf[0] = ( entry->subjectName.len >> 8 ) & 0xff;
01475     buf[1] = entry->subjectName.len & 0xff;
01476     
01477     PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data,
01478              entry->subjectName.len);
01479 
01480     return(SECSuccess);
01481 
01482 loser:
01483     return(SECFailure);
01484 }
01485 
01486 /*
01487  * Encode a database key for a nickname record
01488  */
01489 static SECStatus
01490 EncodeDBNicknameKey(char *nickname, PRArenaPool *arena,
01491                   SECItem *dbkey)
01492 {
01493     unsigned int nnlen;
01494     
01495     nnlen = PORT_Strlen(nickname) + 1; /* includes null */
01496 
01497     /* now get the database key and format it */
01498     dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN;
01499     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
01500     if ( dbkey->data == NULL ) {
01501        goto loser;
01502     }
01503     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], nickname, nnlen);
01504     dbkey->data[0] = certDBEntryTypeNickname;
01505 
01506     return(SECSuccess);
01507 
01508 loser:
01509     return(SECFailure);
01510 }
01511 
01512 static SECStatus
01513 DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry,
01514                       char *nickname)
01515 {
01516     /* is record long enough for header? */
01517     if ( dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
01518        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01519        goto loser;
01520     }
01521     
01522     /* is database entry correct length? */
01523     entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
01524     if (( entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN ) !=
01525        dbentry->len ){
01526        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01527        goto loser;
01528     }
01529     
01530     /* copy the certkey */
01531     entry->subjectName.data =
01532        (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
01533                                     entry->subjectName.len);
01534     if ( entry->subjectName.data == NULL ) {
01535        PORT_SetError(SEC_ERROR_NO_MEMORY);
01536        goto loser;
01537     }
01538     PORT_Memcpy(entry->subjectName.data,
01539              &dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN],
01540              entry->subjectName.len);
01541     entry->subjectName.type = siBuffer;
01542     
01543     entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena, 
01544                                               PORT_Strlen(nickname)+1);
01545     if ( entry->nickname ) {
01546        PORT_Strcpy(entry->nickname, nickname);
01547     }
01548     
01549     return(SECSuccess);
01550 
01551 loser:
01552     return(SECFailure);
01553 }
01554 
01555 /*
01556  * create a new nickname entry
01557  */
01558 static certDBEntryNickname *
01559 NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags)
01560 {
01561     PRArenaPool *arena = NULL;
01562     certDBEntryNickname *entry;
01563     int nnlen;
01564     SECStatus rv;
01565     
01566     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01567     if ( arena == NULL ) {
01568        PORT_SetError(SEC_ERROR_NO_MEMORY);
01569        goto loser;
01570     }
01571 
01572     entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
01573                                            sizeof(certDBEntryNickname));
01574     if ( entry == NULL ) {
01575        PORT_SetError(SEC_ERROR_NO_MEMORY);
01576        goto loser;
01577     }
01578 
01579     /* init common fields */
01580     entry->common.arena = arena;
01581     entry->common.type = certDBEntryTypeNickname;
01582     entry->common.version = CERT_DB_FILE_VERSION;
01583     entry->common.flags = flags;
01584 
01585     /* copy the nickname */
01586     nnlen = PORT_Strlen(nickname) + 1;
01587     
01588     entry->nickname = (char*)PORT_ArenaAlloc(arena, nnlen);
01589     if ( entry->nickname == NULL ) {
01590        goto loser;
01591     }
01592     
01593     PORT_Memcpy(entry->nickname, nickname, nnlen);
01594     
01595     rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
01596     if ( rv != SECSuccess ) {
01597        goto loser;
01598     }
01599     
01600     return(entry);
01601 loser:
01602     if ( arena ) {
01603        PORT_FreeArena(arena, PR_FALSE);
01604     }
01605     
01606     return(NULL);
01607 }
01608 
01609 /*
01610  * delete a nickname entry
01611  */
01612 static SECStatus
01613 DeleteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
01614 {
01615     PRArenaPool *arena = NULL;
01616     SECStatus rv;
01617     SECItem dbkey;
01618     
01619     if ( nickname == NULL ) {
01620        return(SECSuccess);
01621     }
01622     
01623     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01624     if ( arena == NULL ) {
01625        goto loser;
01626     }
01627 
01628     rv = EncodeDBNicknameKey(nickname, arena, &dbkey);
01629     if ( rv != SECSuccess ) {
01630        goto loser;
01631     }
01632 
01633     rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey);
01634     if ( rv == SECFailure ) {
01635        goto loser;
01636     }
01637 
01638     PORT_FreeArena(arena, PR_FALSE);
01639     return(SECSuccess);
01640 
01641 loser:
01642     if ( arena ) {
01643        PORT_FreeArena(arena, PR_FALSE);
01644     }
01645     
01646     return(SECFailure);
01647 }
01648 
01649 /*
01650  * Read a nickname entry
01651  */
01652 static certDBEntryNickname *
01653 ReadDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
01654 {
01655     PRArenaPool *arena = NULL;
01656     PRArenaPool *tmparena = NULL;
01657     certDBEntryNickname *entry;
01658     SECItem dbkey;
01659     SECItem dbentry;
01660     SECStatus rv;
01661     
01662     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01663     if ( arena == NULL ) {
01664        PORT_SetError(SEC_ERROR_NO_MEMORY);
01665        goto loser;
01666     }
01667 
01668     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01669     if ( tmparena == NULL ) {
01670        PORT_SetError(SEC_ERROR_NO_MEMORY);
01671        goto loser;
01672     }
01673     
01674     entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
01675                                            sizeof(certDBEntryNickname));
01676     if ( entry == NULL ) {
01677        PORT_SetError(SEC_ERROR_NO_MEMORY);
01678        goto loser;
01679     }
01680     entry->common.arena = arena;
01681     entry->common.type = certDBEntryTypeNickname;
01682 
01683     rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey);
01684     if ( rv != SECSuccess ) {
01685        goto loser;
01686     }
01687     
01688     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
01689     if ( rv == SECFailure ) {
01690        goto loser;
01691     }
01692 
01693     /* is record long enough for header? */
01694     if ( dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
01695        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01696        goto loser;
01697     }
01698 
01699     rv = DecodeDBNicknameEntry(entry, &dbentry, nickname);
01700     if ( rv != SECSuccess ) {
01701        goto loser;
01702     }
01703     
01704     PORT_FreeArena(tmparena, PR_FALSE);
01705     return(entry);
01706     
01707 loser:
01708     if ( tmparena ) {
01709        PORT_FreeArena(tmparena, PR_FALSE);
01710     }
01711     if ( arena ) {
01712        PORT_FreeArena(arena, PR_FALSE);
01713     }
01714     
01715     return(NULL);
01716 }
01717 
01718 /*
01719  * Encode a nickname entry into byte stream suitable for
01720  * the database
01721  */
01722 static SECStatus
01723 WriteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryNickname *entry)
01724 {
01725     SECItem dbitem, dbkey;
01726     PRArenaPool *tmparena = NULL;
01727     SECStatus rv;
01728     
01729     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01730     if ( tmparena == NULL ) {
01731        goto loser;
01732     }
01733     
01734     rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem);
01735     if ( rv != SECSuccess ) {
01736        goto loser;
01737     }
01738 
01739     rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey);
01740     if ( rv != SECSuccess ) {
01741        goto loser;
01742     }
01743 
01744     /* now write it to the database */
01745     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
01746     if ( rv != SECSuccess ) {
01747        goto loser;
01748     }
01749     
01750     PORT_FreeArena(tmparena, PR_FALSE);
01751     return(SECSuccess);
01752 
01753 loser:
01754     if ( tmparena ) {
01755        PORT_FreeArena(tmparena, PR_FALSE);
01756     }
01757     return(SECFailure);
01758     
01759 }
01760 
01761 SECStatus
01762 EncodeDBSMimeEntry(certDBEntrySMime *entry, PRArenaPool *arena,
01763                  SECItem *dbitem)
01764 {
01765     unsigned char *buf;
01766     
01767     /* allocate space for encoded database record, including space
01768      * for low level header
01769      */
01770     dbitem->len = entry->subjectName.len + entry->smimeOptions.len +
01771        entry->optionsDate.len +
01772        DB_SMIME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN;
01773     
01774     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
01775     if ( dbitem->data == NULL) {
01776        PORT_SetError(SEC_ERROR_NO_MEMORY);
01777        goto loser;
01778     }
01779     
01780     /* fill in database record */
01781     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
01782     
01783     buf[0] = ( entry->subjectName.len >> 8 ) & 0xff;
01784     buf[1] = entry->subjectName.len & 0xff;
01785     buf[2] = ( entry->smimeOptions.len >> 8 ) & 0xff;
01786     buf[3] = entry->smimeOptions.len & 0xff;
01787     buf[4] = ( entry->optionsDate.len >> 8 ) & 0xff;
01788     buf[5] = entry->optionsDate.len & 0xff;
01789 
01790     /* if no smime options, then there should not be an options date either */
01791     PORT_Assert( ! ( ( entry->smimeOptions.len == 0 ) &&
01792                   ( entry->optionsDate.len != 0 ) ) );
01793     
01794     PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN], entry->subjectName.data,
01795              entry->subjectName.len);
01796     if ( entry->smimeOptions.len ) {
01797        PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN+entry->subjectName.len],
01798                   entry->smimeOptions.data,
01799                   entry->smimeOptions.len);
01800        PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len +
01801                       entry->smimeOptions.len],
01802                   entry->optionsDate.data,
01803                   entry->optionsDate.len);
01804     }
01805 
01806     return(SECSuccess);
01807 
01808 loser:
01809     return(SECFailure);
01810 }
01811 
01812 /*
01813  * Encode a database key for a SMIME record
01814  */
01815 static SECStatus
01816 EncodeDBSMimeKey(char *emailAddr, PRArenaPool *arena,
01817                SECItem *dbkey)
01818 {
01819     unsigned int addrlen;
01820     
01821     addrlen = PORT_Strlen(emailAddr) + 1; /* includes null */
01822 
01823     /* now get the database key and format it */
01824     dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN;
01825     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
01826     if ( dbkey->data == NULL ) {
01827        goto loser;
01828     }
01829     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], emailAddr, addrlen);
01830     dbkey->data[0] = certDBEntryTypeSMimeProfile;
01831 
01832     return(SECSuccess);
01833 
01834 loser:
01835     return(SECFailure);
01836 }
01837 
01838 /*
01839  * Decode a database SMIME record
01840  */
01841 static SECStatus
01842 DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr)
01843 {
01844     /* is record long enough for header? */
01845     if ( dbentry->len < DB_SMIME_ENTRY_HEADER_LEN ) {
01846        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01847        goto loser;
01848     }
01849     
01850     /* is database entry correct length? */
01851     entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
01852     entry->smimeOptions.len = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
01853     entry->optionsDate.len = ( ( dbentry->data[4] << 8 ) | dbentry->data[5] );
01854     if (( entry->subjectName.len + entry->smimeOptions.len +
01855         entry->optionsDate.len + DB_SMIME_ENTRY_HEADER_LEN ) != dbentry->len){
01856        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01857        goto loser;
01858     }
01859     
01860     /* copy the subject name */
01861     entry->subjectName.data =
01862        (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
01863                                     entry->subjectName.len);
01864     if ( entry->subjectName.data == NULL ) {
01865        PORT_SetError(SEC_ERROR_NO_MEMORY);
01866        goto loser;
01867     }
01868     PORT_Memcpy(entry->subjectName.data,
01869              &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN],
01870              entry->subjectName.len);
01871 
01872     /* copy the smime options */
01873     if ( entry->smimeOptions.len ) {
01874        entry->smimeOptions.data =
01875            (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
01876                                         entry->smimeOptions.len);
01877        if ( entry->smimeOptions.data == NULL ) {
01878            PORT_SetError(SEC_ERROR_NO_MEMORY);
01879            goto loser;
01880        }
01881        PORT_Memcpy(entry->smimeOptions.data,
01882                   &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
01883                                entry->subjectName.len],
01884                   entry->smimeOptions.len);
01885     }
01886     if ( entry->optionsDate.len ) {
01887        entry->optionsDate.data =
01888            (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
01889                                         entry->optionsDate.len);
01890        if ( entry->optionsDate.data == NULL ) {
01891            PORT_SetError(SEC_ERROR_NO_MEMORY);
01892            goto loser;
01893        }
01894        PORT_Memcpy(entry->optionsDate.data,
01895                   &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
01896                                entry->subjectName.len +
01897                                entry->smimeOptions.len],
01898                   entry->optionsDate.len);
01899     }
01900 
01901     /* both options and options date must either exist or not exist */
01902     if ( ( ( entry->optionsDate.len == 0 ) ||
01903          ( entry->smimeOptions.len == 0 ) ) &&
01904        entry->smimeOptions.len != entry->optionsDate.len ) {
01905        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01906        goto loser;
01907     }
01908 
01909     entry->emailAddr = (char *)PORT_ArenaAlloc(entry->common.arena,
01910                                           PORT_Strlen(emailAddr)+1);
01911     if ( entry->emailAddr ) {
01912        PORT_Strcpy(entry->emailAddr, emailAddr);
01913     }
01914     
01915     return(SECSuccess);
01916 
01917 loser:
01918     return(SECFailure);
01919 }
01920 
01921 /*
01922  * create a new SMIME entry
01923  */
01924 static certDBEntrySMime *
01925 NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions,
01926               SECItem *optionsDate, unsigned int flags)
01927 {
01928     PRArenaPool *arena = NULL;
01929     certDBEntrySMime *entry;
01930     int addrlen;
01931     SECStatus rv;
01932     
01933     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01934     if ( arena == NULL ) {
01935        PORT_SetError(SEC_ERROR_NO_MEMORY);
01936        goto loser;
01937     }
01938 
01939     entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
01940                                           sizeof(certDBEntrySMime));
01941     if ( entry == NULL ) {
01942        PORT_SetError(SEC_ERROR_NO_MEMORY);
01943        goto loser;
01944     }
01945 
01946     /* init common fields */
01947     entry->common.arena = arena;
01948     entry->common.type = certDBEntryTypeSMimeProfile;
01949     entry->common.version = CERT_DB_FILE_VERSION;
01950     entry->common.flags = flags;
01951 
01952     /* copy the email addr */
01953     addrlen = PORT_Strlen(emailAddr) + 1;
01954     
01955     entry->emailAddr = (char*)PORT_ArenaAlloc(arena, addrlen);
01956     if ( entry->emailAddr == NULL ) {
01957        goto loser;
01958     }
01959     
01960     PORT_Memcpy(entry->emailAddr, emailAddr, addrlen);
01961     
01962     /* copy the subject name */
01963     rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
01964     if ( rv != SECSuccess ) {
01965        goto loser;
01966     }
01967 
01968     /* copy the smime options */
01969     if ( smimeOptions ) {
01970        rv = SECITEM_CopyItem(arena, &entry->smimeOptions, smimeOptions);
01971        if ( rv != SECSuccess ) {
01972            goto loser;
01973        }
01974     } else {
01975        PORT_Assert(optionsDate == NULL);
01976        entry->smimeOptions.data = NULL;
01977        entry->smimeOptions.len = 0;
01978     }
01979 
01980     /* copy the options date */
01981     if ( optionsDate ) {
01982        rv = SECITEM_CopyItem(arena, &entry->optionsDate, optionsDate);
01983        if ( rv != SECSuccess ) {
01984            goto loser;
01985        }
01986     } else {
01987        PORT_Assert(smimeOptions == NULL);
01988        entry->optionsDate.data = NULL;
01989        entry->optionsDate.len = 0;
01990     }
01991     
01992     return(entry);
01993 loser:
01994     if ( arena ) {
01995        PORT_FreeArena(arena, PR_FALSE);
01996     }
01997     
01998     return(NULL);
01999 }
02000 
02001 /*
02002  * delete a SMIME entry
02003  */
02004 static SECStatus
02005 DeleteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
02006 {
02007     PRArenaPool *arena = NULL;
02008     SECStatus rv;
02009     SECItem dbkey;
02010     
02011     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02012     if ( arena == NULL ) {
02013        goto loser;
02014     }
02015 
02016     rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey);
02017     if ( rv != SECSuccess ) {
02018        goto loser;
02019     }
02020 
02021     rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey);
02022     if ( rv == SECFailure ) {
02023        goto loser;
02024     }
02025 
02026     PORT_FreeArena(arena, PR_FALSE);
02027     return(SECSuccess);
02028 
02029 loser:
02030     if ( arena ) {
02031        PORT_FreeArena(arena, PR_FALSE);
02032     }
02033     
02034     return(SECFailure);
02035 }
02036 
02037 /*
02038  * Read a SMIME entry
02039  */
02040 certDBEntrySMime *
02041 nsslowcert_ReadDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
02042 {
02043     PRArenaPool *arena = NULL;
02044     PRArenaPool *tmparena = NULL;
02045     certDBEntrySMime *entry;
02046     SECItem dbkey;
02047     SECItem dbentry;
02048     SECStatus rv;
02049     
02050     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02051     if ( arena == NULL ) {
02052        PORT_SetError(SEC_ERROR_NO_MEMORY);
02053        goto loser;
02054     }
02055 
02056     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02057     if ( tmparena == NULL ) {
02058        PORT_SetError(SEC_ERROR_NO_MEMORY);
02059        goto loser;
02060     }
02061     
02062     entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
02063                                           sizeof(certDBEntrySMime));
02064     if ( entry == NULL ) {
02065        PORT_SetError(SEC_ERROR_NO_MEMORY);
02066        goto loser;
02067     }
02068     entry->common.arena = arena;
02069     entry->common.type = certDBEntryTypeSMimeProfile;
02070 
02071     rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey);
02072     if ( rv != SECSuccess ) {
02073        goto loser;
02074     }
02075     
02076     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
02077     if ( rv == SECFailure ) {
02078        goto loser;
02079     }
02080 
02081     /* is record long enough for header? */
02082     if ( dbentry.len < DB_SMIME_ENTRY_HEADER_LEN ) {
02083        PORT_SetError(SEC_ERROR_BAD_DATABASE);
02084        goto loser;
02085     }
02086 
02087     rv = DecodeDBSMimeEntry(entry, &dbentry, emailAddr);
02088     if ( rv != SECSuccess ) {
02089        goto loser;
02090     }
02091     
02092     PORT_FreeArena(tmparena, PR_FALSE);
02093     return(entry);
02094     
02095 loser:
02096     if ( tmparena ) {
02097        PORT_FreeArena(tmparena, PR_FALSE);
02098     }
02099     if ( arena ) {
02100        PORT_FreeArena(arena, PR_FALSE);
02101     }
02102     
02103     return(NULL);
02104 }
02105 
02106 /*
02107  * Encode a SMIME entry into byte stream suitable for
02108  * the database
02109  */
02110 static SECStatus
02111 WriteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySMime *entry)
02112 {
02113     SECItem dbitem, dbkey;
02114     PRArenaPool *tmparena = NULL;
02115     SECStatus rv;
02116     
02117     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02118     if ( tmparena == NULL ) {
02119        goto loser;
02120     }
02121     
02122     rv = EncodeDBSMimeEntry(entry, tmparena, &dbitem);
02123     if ( rv != SECSuccess ) {
02124        goto loser;
02125     }
02126 
02127     rv = EncodeDBSMimeKey(entry->emailAddr, tmparena, &dbkey);
02128     if ( rv != SECSuccess ) {
02129        goto loser;
02130     }
02131 
02132     /* now write it to the database */
02133     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
02134     if ( rv != SECSuccess ) {
02135        goto loser;
02136     }
02137     
02138     PORT_FreeArena(tmparena, PR_FALSE);
02139     return(SECSuccess);
02140 
02141 loser:
02142     if ( tmparena ) {
02143        PORT_FreeArena(tmparena, PR_FALSE);
02144     }
02145     return(SECFailure);
02146     
02147 }
02148 
02149 /*
02150  * Encode a database subject record
02151  */
02152 static SECStatus
02153 EncodeDBSubjectEntry(certDBEntrySubject *entry, PRArenaPool *arena,
02154                    SECItem *dbitem)
02155 {
02156     unsigned char *buf;
02157     int len;
02158     unsigned int ncerts;
02159     unsigned int i;
02160     unsigned char *tmpbuf;
02161     unsigned int nnlen = 0;
02162     unsigned int eaddrslen = 0;
02163     int keyidoff;
02164     SECItem *certKeys;
02165     SECItem *keyIDs;
02166     
02167     if ( entry->nickname ) {
02168        nnlen = PORT_Strlen(entry->nickname) + 1;
02169     }
02170     if ( entry->emailAddrs ) {
02171        eaddrslen = 2;
02172        for (i=0; i < entry->nemailAddrs; i++) {
02173            eaddrslen += PORT_Strlen(entry->emailAddrs[i]) + 1 + 2;
02174        }
02175     }
02176 
02177     ncerts = entry->ncerts;
02178     
02179     /* compute the length of the entry */
02180     keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen ;
02181     len = keyidoff + 4 * ncerts + eaddrslen;
02182     for ( i = 0; i < ncerts; i++ ) {
02183        len += entry->certKeys[i].len;
02184        len += entry->keyIDs[i].len;
02185     }
02186     
02187     /* allocate space for encoded database record, including space
02188      * for low level header
02189      */
02190     dbitem->len = len + SEC_DB_ENTRY_HEADER_LEN;
02191     
02192     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
02193     if ( dbitem->data == NULL) {
02194        PORT_SetError(SEC_ERROR_NO_MEMORY);
02195        goto loser;
02196     }
02197     
02198     /* fill in database record */
02199     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
02200     
02201     buf[0] = ( ncerts >> 8 ) & 0xff;
02202     buf[1] = ncerts & 0xff;
02203     buf[2] = ( nnlen >> 8 ) & 0xff;
02204     buf[3] = nnlen & 0xff;
02205     /* v7 email field is NULL in v8 */
02206     buf[4] = 0;
02207     buf[5] = 0;
02208 
02209     PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN], entry->nickname, nnlen);
02210     
02211     for ( i = 0; i < ncerts; i++ ) {
02212 
02213        certKeys = entry->certKeys;
02214        keyIDs = entry->keyIDs;
02215 
02216        buf[keyidoff+i*2] = ( certKeys[i].len >> 8 ) & 0xff;
02217        buf[keyidoff+1+i*2] = certKeys[i].len & 0xff;
02218        buf[keyidoff+ncerts*2+i*2] = ( keyIDs[i].len >> 8 ) & 0xff;
02219        buf[keyidoff+1+ncerts*2+i*2] = keyIDs[i].len & 0xff;
02220     }
02221     
02222     /* temp pointer used to stuff certkeys and keyids into the buffer */
02223     tmpbuf = &buf[keyidoff+ncerts*4];
02224 
02225     for ( i = 0; i < ncerts; i++ ) {
02226        certKeys = entry->certKeys;
02227        PORT_Memcpy(tmpbuf, certKeys[i].data, certKeys[i].len);
02228        tmpbuf = tmpbuf + certKeys[i].len;
02229     }
02230     
02231     for ( i = 0; i < ncerts; i++ ) {
02232        keyIDs = entry->keyIDs;
02233        PORT_Memcpy(tmpbuf, keyIDs[i].data, keyIDs[i].len);
02234        tmpbuf = tmpbuf + keyIDs[i].len;
02235     }
02236 
02237     if (entry->emailAddrs) {
02238        tmpbuf[0] =  (entry->nemailAddrs >> 8) & 0xff;
02239        tmpbuf[1] =  entry->nemailAddrs  & 0xff;
02240        tmpbuf += 2;
02241        for (i=0; i < entry->nemailAddrs; i++) {
02242            int nameLen = PORT_Strlen(entry->emailAddrs[i]) + 1;
02243            tmpbuf[0] =  (nameLen >> 8) & 0xff;
02244            tmpbuf[1] =  nameLen & 0xff;
02245            tmpbuf += 2;
02246            PORT_Memcpy(tmpbuf,entry->emailAddrs[i],nameLen);
02247            tmpbuf +=nameLen;
02248        }
02249     }
02250 
02251     PORT_Assert(tmpbuf == &buf[len]);
02252     
02253     return(SECSuccess);
02254 
02255 loser:
02256     return(SECFailure);
02257 }
02258 
02259 /*
02260  * Encode a database key for a subject record
02261  */
02262 static SECStatus
02263 EncodeDBSubjectKey(SECItem *derSubject, PRArenaPool *arena,
02264                  SECItem *dbkey)
02265 {
02266     dbkey->len = derSubject->len + SEC_DB_KEY_HEADER_LEN;
02267     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
02268     if ( dbkey->data == NULL ) {
02269        goto loser;
02270     }
02271     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], derSubject->data,
02272              derSubject->len);
02273     dbkey->data[0] = certDBEntryTypeSubject;
02274 
02275     return(SECSuccess);
02276 
02277 loser:
02278     return(SECFailure);
02279 }
02280 
02281 static SECStatus
02282 DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry,
02283                    SECItem *derSubject)
02284 {
02285     unsigned int ncerts;
02286     PRArenaPool *arena;
02287     unsigned int len, itemlen;
02288     unsigned char *tmpbuf;
02289     unsigned char *end;
02290     unsigned int i;
02291     SECStatus rv;
02292     unsigned int keyidoff;
02293     unsigned int nnlen, eaddrlen;
02294     unsigned int stdlen;
02295     
02296     arena = entry->common.arena;
02297 
02298     rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject);
02299     if ( rv != SECSuccess ) {
02300        goto loser;
02301     }
02302 
02303     /* is record long enough for header? */
02304     if ( dbentry->len < DB_SUBJECT_ENTRY_HEADER_LEN ) {
02305        PORT_SetError(SEC_ERROR_BAD_DATABASE);
02306        goto loser;
02307     }
02308     
02309     entry->ncerts = ncerts = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
02310     nnlen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
02311     eaddrlen = ( ( dbentry->data[4] << 8 ) | dbentry->data[5] );
02312     stdlen = ncerts * 4 + DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen;
02313     if ( dbentry->len < stdlen) {
02314        PORT_SetError(SEC_ERROR_BAD_DATABASE);
02315        goto loser;
02316     }
02317     
02318     entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena,
02319                                            sizeof(SECItem) * ncerts);
02320     entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena,
02321                                           sizeof(SECItem) * ncerts);
02322 
02323     if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) {
02324        PORT_SetError(SEC_ERROR_NO_MEMORY);
02325        goto loser;
02326     }
02327 
02328     if ( nnlen > 1 ) { /* null terminator is stored */
02329        entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
02330        if ( entry->nickname == NULL ) {
02331            PORT_SetError(SEC_ERROR_NO_MEMORY);
02332            goto loser;
02333        }
02334        PORT_Memcpy(entry->nickname,
02335                   &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN],
02336                   nnlen);
02337     } else {
02338        entry->nickname = NULL;
02339     }
02340 
02341     /* if we have an old style email entry, there is only one */    
02342     entry->nemailAddrs = 0;
02343     if ( eaddrlen > 1 ) { /* null terminator is stored */
02344        entry->emailAddrs = (char **)PORT_ArenaAlloc(arena, sizeof(char *));
02345        if ( entry->emailAddrs == NULL ) {
02346            PORT_SetError(SEC_ERROR_NO_MEMORY);
02347            goto loser;
02348        }
02349        entry->emailAddrs[0] = (char *)PORT_ArenaAlloc(arena, eaddrlen);
02350        if ( entry->emailAddrs[0] == NULL ) {
02351            PORT_SetError(SEC_ERROR_NO_MEMORY);
02352            goto loser;
02353        }
02354        PORT_Memcpy(entry->emailAddrs[0],
02355                   &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN+nnlen],
02356                   eaddrlen);
02357         entry->nemailAddrs = 1;
02358     } else {
02359        entry->emailAddrs = NULL;
02360     }
02361     
02362     /* collect the lengths of the certKeys and keyIDs, and total the
02363      * overall length.
02364      */
02365     keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen;
02366     len = keyidoff + 4 * ncerts;
02367 
02368     tmpbuf = &dbentry->data[0];
02369     
02370     for ( i = 0; i < ncerts; i++ ) {
02371 
02372        itemlen = ( tmpbuf[keyidoff + 2*i] << 8 ) | tmpbuf[keyidoff + 1 + 2*i] ;
02373        len += itemlen;
02374        entry->certKeys[i].len = itemlen;
02375 
02376        itemlen = ( tmpbuf[keyidoff + 2*ncerts + 2*i] << 8 ) |
02377            tmpbuf[keyidoff + 1 + 2*ncerts + 2*i] ;
02378        len += itemlen;
02379        entry->keyIDs[i].len = itemlen;
02380     }
02381     
02382     /* is database entry correct length? */
02383     if ( len > dbentry->len ){
02384        PORT_SetError(SEC_ERROR_BAD_DATABASE);
02385        goto loser;
02386     }
02387     
02388     tmpbuf = &tmpbuf[keyidoff + 4*ncerts];
02389     for ( i = 0; i < ncerts; i++ ) {
02390        entry->certKeys[i].data =
02391            (unsigned char *)PORT_ArenaAlloc(arena, entry->certKeys[i].len);
02392        if ( entry->certKeys[i].data == NULL ) {
02393            PORT_SetError(SEC_ERROR_NO_MEMORY);
02394            goto loser;
02395        }
02396        PORT_Memcpy(entry->certKeys[i].data, tmpbuf, entry->certKeys[i].len);
02397        tmpbuf = &tmpbuf[entry->certKeys[i].len];
02398     }
02399 
02400     for ( i = 0; i < ncerts; i++ ) {
02401        entry->keyIDs[i].data =
02402            (unsigned char *)PORT_ArenaAlloc(arena, entry->keyIDs[i].len);
02403        if ( entry->keyIDs[i].data == NULL ) {
02404            PORT_SetError(SEC_ERROR_NO_MEMORY);
02405            goto loser;
02406        }
02407        PORT_Memcpy(entry->keyIDs[i].data, tmpbuf, entry->keyIDs[i].len);
02408        tmpbuf = &tmpbuf[entry->keyIDs[i].len];
02409     }
02410 
02411     end = &dbentry->data[dbentry->len];
02412     if ((eaddrlen == 0) && (tmpbuf+1 < end)) {
02413        /* read in the additional email addresses */
02414        entry->nemailAddrs = tmpbuf[0] << 8 | tmpbuf[1];
02415        tmpbuf += 2;
02416        entry->emailAddrs = (char **)
02417               PORT_ArenaAlloc(arena, entry->nemailAddrs * sizeof(char *));
02418        if (entry->emailAddrs == NULL) {
02419            PORT_SetError(SEC_ERROR_NO_MEMORY);
02420            goto loser;
02421        }
02422        for (i=0; i < entry->nemailAddrs; i++) {
02423            int nameLen;
02424            if (tmpbuf + 2 > end) {
02425               goto loser;
02426            }
02427 
02428            nameLen = tmpbuf[0] << 8 | tmpbuf[1];
02429            entry->emailAddrs[i] = PORT_ArenaAlloc(arena,nameLen);
02430            if (entry->emailAddrs == NULL) {
02431                PORT_SetError(SEC_ERROR_NO_MEMORY);
02432                goto loser;
02433            }
02434            if (tmpbuf + (nameLen+2) > end) {
02435               goto loser;
02436            }
02437            PORT_Memcpy(entry->emailAddrs[i],&tmpbuf[2],nameLen);
02438            tmpbuf += 2 + nameLen;
02439        }
02440     }
02441     
02442     
02443     return(SECSuccess);
02444 
02445 loser:
02446     return(SECFailure);
02447 }
02448 
02449 /*
02450  * create a new subject entry with a single cert
02451  */
02452 static certDBEntrySubject *
02453 NewDBSubjectEntry(SECItem *derSubject, SECItem *certKey,
02454                 SECItem *keyID, char *nickname, char *emailAddr,
02455                 unsigned int flags)
02456 {
02457     PRArenaPool *arena = NULL;
02458     certDBEntrySubject *entry;
02459     SECStatus rv;
02460     unsigned int nnlen;
02461     unsigned int eaddrlen;
02462     
02463     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02464     if ( arena == NULL ) {
02465        PORT_SetError(SEC_ERROR_NO_MEMORY);
02466        goto loser;
02467     }
02468 
02469     entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
02470                                             sizeof(certDBEntrySubject));
02471     if ( entry == NULL ) {
02472        PORT_SetError(SEC_ERROR_NO_MEMORY);
02473        goto loser;
02474     }
02475 
02476     /* init common fields */
02477     entry->common.arena = arena;
02478     entry->common.type = certDBEntryTypeSubject;
02479     entry->common.version = CERT_DB_FILE_VERSION;
02480     entry->common.flags = flags;
02481 
02482     /* copy the subject */
02483     rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject);
02484     if ( rv != SECSuccess ) {
02485        goto loser;
02486     }
02487     
02488     entry->ncerts = 1;
02489     entry->nemailAddrs = 0;
02490     /* copy nickname */
02491     if ( nickname && ( *nickname != '\0' ) ) {
02492        nnlen = PORT_Strlen(nickname) + 1;
02493        entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
02494        if ( entry->nickname == NULL ) {
02495            goto loser;
02496        }
02497                                             
02498        PORT_Memcpy(entry->nickname, nickname, nnlen);
02499     } else {
02500        entry->nickname = NULL;
02501     }
02502     
02503     /* copy email addr */
02504     if ( emailAddr && ( *emailAddr != '\0' ) ) {
02505        emailAddr = nsslowcert_FixupEmailAddr(emailAddr);
02506        if ( emailAddr == NULL ) {
02507            entry->emailAddrs = NULL;
02508            goto loser;
02509        }
02510        
02511        eaddrlen = PORT_Strlen(emailAddr) + 1;
02512        entry->emailAddrs = (char **)PORT_ArenaAlloc(arena, sizeof(char *));
02513        if ( entry->emailAddrs == NULL ) {
02514            PORT_Free(emailAddr);
02515            goto loser;
02516        }
02517        entry->emailAddrs[0] = PORT_ArenaStrdup(arena,emailAddr);
02518        if (entry->emailAddrs[0]) {
02519            entry->nemailAddrs = 1;
02520        } 
02521        
02522        PORT_Free(emailAddr);
02523     } else {
02524        entry->emailAddrs = NULL;
02525     }
02526     
02527     /* allocate space for certKeys and keyIDs */
02528     entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
02529     entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
02530     if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) {
02531        goto loser;
02532     }
02533 
02534     /* copy the certKey and keyID */
02535     rv = SECITEM_CopyItem(arena, &entry->certKeys[0], certKey);
02536     if ( rv != SECSuccess ) {
02537        goto loser;
02538     }
02539     rv = SECITEM_CopyItem(arena, &entry->keyIDs[0], keyID);
02540     if ( rv != SECSuccess ) {
02541        goto loser;
02542     }
02543     
02544     return(entry);
02545 loser:
02546     if ( arena ) {
02547        PORT_FreeArena(arena, PR_FALSE);
02548     }
02549     
02550     return(NULL);
02551 }
02552 
02553 /*
02554  * delete a subject entry
02555  */
02556 static SECStatus
02557 DeleteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject)
02558 {
02559     SECItem dbkey;
02560     PRArenaPool *arena = NULL;
02561     SECStatus rv;
02562     
02563     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02564     if ( arena == NULL ) {
02565        goto loser;
02566     }
02567     
02568     rv = EncodeDBSubjectKey(derSubject, arena, &dbkey);
02569     if ( rv != SECSuccess ) {
02570        goto loser;
02571     }
02572     
02573     rv = DeleteDBEntry(handle, certDBEntryTypeSubject, &dbkey);
02574     if ( rv == SECFailure ) {
02575        goto loser;
02576     }
02577 
02578     PORT_FreeArena(arena, PR_FALSE);
02579     return(SECSuccess);
02580 
02581 loser:
02582     if ( arena ) {
02583        PORT_FreeArena(arena, PR_FALSE);
02584     }
02585     
02586     return(SECFailure);
02587 }
02588 
02589 /*
02590  * Read the subject entry
02591  */
02592 static certDBEntrySubject *
02593 ReadDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject)
02594 {
02595     PRArenaPool *arena = NULL;
02596     PRArenaPool *tmparena = NULL;
02597     certDBEntrySubject *entry;
02598     SECItem dbkey;
02599     SECItem dbentry;
02600     SECStatus rv;
02601     
02602     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02603     if ( arena == NULL ) {
02604        PORT_SetError(SEC_ERROR_NO_MEMORY);
02605        goto loser;
02606     }
02607 
02608     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02609     if ( tmparena == NULL ) {
02610        PORT_SetError(SEC_ERROR_NO_MEMORY);
02611        goto loser;
02612     }
02613     
02614     entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
02615                                           sizeof(certDBEntrySubject));
02616     if ( entry == NULL ) {
02617        PORT_SetError(SEC_ERROR_NO_MEMORY);
02618        goto loser;
02619     }
02620     entry->common.arena = arena;
02621     entry->common.type = certDBEntryTypeSubject;
02622 
02623     rv = EncodeDBSubjectKey(derSubject, tmparena, &dbkey);
02624     if ( rv != SECSuccess ) {
02625        goto loser;
02626     }
02627     
02628     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
02629     if ( rv == SECFailure ) {
02630        goto loser;
02631     }
02632 
02633     rv = DecodeDBSubjectEntry(entry, &dbentry, derSubject);
02634     if ( rv == SECFailure ) {
02635        goto loser;
02636     }
02637     
02638     PORT_FreeArena(tmparena, PR_FALSE);
02639     return(entry);
02640     
02641 loser:
02642     if ( tmparena ) {
02643        PORT_FreeArena(tmparena, PR_FALSE);
02644     }
02645     if ( arena ) {
02646        PORT_FreeArena(arena, PR_FALSE);
02647     }
02648     
02649     return(NULL);
02650 }
02651 
02652 /*
02653  * Encode a subject name entry into byte stream suitable for
02654  * the database
02655  */
02656 static SECStatus
02657 WriteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySubject *entry)
02658 {
02659     SECItem dbitem, dbkey;
02660     PRArenaPool *tmparena = NULL;
02661     SECStatus rv;
02662     
02663     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02664     if ( tmparena == NULL ) {
02665        goto loser;
02666     }
02667     
02668     rv = EncodeDBSubjectEntry(entry, tmparena, &dbitem);
02669     if ( rv != SECSuccess ) {
02670        goto loser;
02671     }
02672     
02673     rv = EncodeDBSubjectKey(&entry->derSubject, tmparena, &dbkey);
02674     if ( rv != SECSuccess ) {
02675        goto loser;
02676     }
02677 
02678     /* now write it to the database */
02679     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
02680     if ( rv != SECSuccess ) {
02681        goto loser;
02682     }
02683     
02684     PORT_FreeArena(tmparena, PR_FALSE);
02685     return(SECSuccess);
02686 
02687 loser:
02688     if ( tmparena ) {
02689        PORT_FreeArena(tmparena, PR_FALSE);
02690     }
02691     return(SECFailure);
02692     
02693 }
02694 
02695 typedef enum { nsslowcert_remove, nsslowcert_add } nsslowcertUpdateType;
02696 
02697 static SECStatus
02698 nsslowcert_UpdateSubjectEmailAddr(NSSLOWCERTCertDBHandle *dbhandle, 
02699        SECItem *derSubject, char *emailAddr, nsslowcertUpdateType updateType)
02700 {
02701     certDBEntrySubject *entry = NULL;
02702     int index = -1, i;
02703     SECStatus rv;
02704    
02705     if (emailAddr) { 
02706        emailAddr = nsslowcert_FixupEmailAddr(emailAddr);
02707        if (emailAddr == NULL) {
02708            return SECFailure;
02709        }
02710     } else {
02711        return SECSuccess;
02712     }
02713 
02714     entry = ReadDBSubjectEntry(dbhandle,derSubject);    
02715     if (entry == NULL) {
02716        rv = SECFailure;
02717        goto done;
02718     } 
02719 
02720     for (i=0; i < (int)(entry->nemailAddrs); i++) {
02721         if (PORT_Strcmp(entry->emailAddrs[i],emailAddr) == 0) {
02722            index = i;
02723        }
02724     }
02725 
02726     if (updateType == nsslowcert_remove) {
02727        if (index == -1) {
02728            rv = SECSuccess;
02729            goto done;
02730        }
02731        entry->nemailAddrs--;
02732        for (i=index; i < (int)(entry->nemailAddrs); i++) {
02733           entry->emailAddrs[i] = entry->emailAddrs[i+1];
02734        }
02735     } else {
02736        char **newAddrs = NULL;
02737 
02738        if (index != -1) {
02739            rv = SECSuccess;
02740            goto done;
02741        }
02742        newAddrs = (char **)PORT_ArenaAlloc(entry->common.arena,
02743               (entry->nemailAddrs+1)* sizeof(char *));
02744        if (!newAddrs) {
02745            rv = SECFailure;
02746            goto done;
02747        }
02748        for (i=0; i < (int)(entry->nemailAddrs); i++) {
02749           newAddrs[i] = entry->emailAddrs[i];
02750        }
02751        newAddrs[entry->nemailAddrs] = 
02752                      PORT_ArenaStrdup(entry->common.arena,emailAddr);
02753        if (!newAddrs[entry->nemailAddrs]) {
02754           rv = SECFailure;
02755           goto done;
02756        }
02757        entry->emailAddrs = newAddrs;
02758        entry->nemailAddrs++;
02759     }
02760        
02761     /* delete the subject entry */
02762     DeleteDBSubjectEntry(dbhandle, derSubject);
02763 
02764     /* write the new one */
02765     rv = WriteDBSubjectEntry(dbhandle, entry);
02766 
02767   done:
02768     if (entry) DestroyDBEntry((certDBEntry *)entry);
02769     if (emailAddr) PORT_Free(emailAddr);
02770     return rv;
02771 }
02772 
02773 /*
02774  * writes a nickname to an existing subject entry that does not currently
02775  * have one
02776  */
02777 static SECStatus
02778 AddNicknameToSubject(NSSLOWCERTCertDBHandle *dbhandle,
02779                      NSSLOWCERTCertificate *cert, char *nickname)
02780 {
02781     certDBEntrySubject *entry;
02782     SECStatus rv;
02783     
02784     if ( nickname == NULL ) {
02785        return(SECFailure);
02786     }
02787     
02788     entry = ReadDBSubjectEntry(dbhandle,&cert->derSubject);
02789     PORT_Assert(entry != NULL);
02790     if ( entry == NULL ) {
02791        goto loser;
02792     }
02793     
02794     PORT_Assert(entry->nickname == NULL);
02795     if ( entry->nickname != NULL ) {
02796        goto loser;
02797     }
02798     
02799     entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname);
02800     
02801     if ( entry->nickname == NULL ) {
02802        goto loser;
02803     }
02804        
02805     /* delete the subject entry */
02806     DeleteDBSubjectEntry(dbhandle, &cert->derSubject);
02807 
02808     /* write the new one */
02809     rv = WriteDBSubjectEntry(dbhandle, entry);
02810     if ( rv != SECSuccess ) {
02811        goto loser;
02812     }
02813 
02814     return(SECSuccess);
02815 
02816 loser:
02817     return(SECFailure);
02818 }
02819 
02820 /*
02821  * create a new version entry
02822  */
02823 static certDBEntryVersion *
02824 NewDBVersionEntry(unsigned int flags)
02825 {
02826     PRArenaPool *arena = NULL;
02827     certDBEntryVersion *entry;
02828     
02829     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02830     if ( arena == NULL ) {
02831        PORT_SetError(SEC_ERROR_NO_MEMORY);
02832        goto loser;
02833     }
02834 
02835     entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena,
02836                                           sizeof(certDBEntryVersion));
02837     if ( entry == NULL ) {
02838        PORT_SetError(SEC_ERROR_NO_MEMORY);
02839        goto loser;
02840     }
02841     entry->common.arena = arena;
02842     entry->common.type = certDBEntryTypeVersion;
02843     entry->common.version = CERT_DB_FILE_VERSION;
02844     entry->common.flags = flags;
02845 
02846     return(entry);
02847 loser:
02848     if ( arena ) {
02849        PORT_FreeArena(arena, PR_FALSE);
02850     }
02851     
02852     return(NULL);
02853 }
02854 
02855 /*
02856  * Read the version entry
02857  */
02858 static certDBEntryVersion *
02859 ReadDBVersionEntry(NSSLOWCERTCertDBHandle *handle)
02860 {
02861     PRArenaPool *arena = NULL;
02862     PRArenaPool *tmparena = NULL;
02863     certDBEntryVersion *entry;
02864     SECItem dbkey;
02865     SECItem dbentry;
02866     SECStatus rv;
02867     
02868     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02869     if ( arena == NULL ) {
02870        PORT_SetError(SEC_ERROR_NO_MEMORY);
02871        goto loser;
02872     }
02873 
02874     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02875     if ( tmparena == NULL ) {
02876        PORT_SetError(SEC_ERROR_NO_MEMORY);
02877        goto loser;
02878     }
02879     
02880     entry = PORT_ArenaZNew(arena, certDBEntryVersion);
02881     if ( entry == NULL ) {
02882        PORT_SetError(SEC_ERROR_NO_MEMORY);
02883        goto loser;
02884     }
02885     entry->common.arena = arena;
02886     entry->common.type = certDBEntryTypeVersion;
02887 
02888     /* now get the database key and format it */
02889     dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
02890     dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
02891     if ( dbkey.data == NULL ) {
02892        goto loser;
02893     }
02894     PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY,
02895              SEC_DB_VERSION_KEY_LEN);
02896 
02897     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
02898     if (rv != SECSuccess) {
02899        goto loser;
02900     }
02901 
02902     PORT_FreeArena(tmparena, PR_FALSE);
02903     return(entry);
02904     
02905 loser:
02906     if ( tmparena ) {
02907        PORT_FreeArena(tmparena, PR_FALSE);
02908     }
02909     if ( arena ) {
02910        PORT_FreeArena(arena, PR_FALSE);
02911     }
02912     
02913     return(NULL);
02914 }
02915 
02916 
02917 /*
02918  * Encode a version entry into byte stream suitable for
02919  * the database
02920  */
02921 static SECStatus
02922 WriteDBVersionEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryVersion *entry)
02923 {
02924     SECItem dbitem, dbkey;
02925     PRArenaPool *tmparena = NULL;
02926     SECStatus rv;
02927     
02928     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02929     if ( tmparena == NULL ) {
02930        goto loser;
02931     }
02932     
02933     /* allocate space for encoded database record, including space
02934      * for low level header
02935      */
02936     dbitem.len = SEC_DB_ENTRY_HEADER_LEN;
02937     
02938     dbitem.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbitem.len);
02939     if ( dbitem.data == NULL) {
02940        PORT_SetError(SEC_ERROR_NO_MEMORY);
02941        goto loser;
02942     }
02943     
02944     /* now get the database key and format it */
02945     dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
02946     dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
02947     if ( dbkey.data == NULL ) {
02948        goto loser;
02949     }
02950     PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY,
02951              SEC_DB_VERSION_KEY_LEN);
02952 
02953     /* now write it to the database */
02954     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
02955     if ( rv != SECSuccess ) {
02956        goto loser;
02957     }
02958     
02959     PORT_FreeArena(tmparena, PR_FALSE);
02960     return(SECSuccess);
02961 
02962 loser:
02963     if ( tmparena ) {
02964        PORT_FreeArena(tmparena, PR_FALSE);
02965     }
02966     return(SECFailure);
02967 }
02968 
02969 /*
02970  * cert is no longer a perm cert, but will remain a temp cert
02971  */
02972 static SECStatus
02973 RemovePermSubjectNode(NSSLOWCERTCertificate *cert)
02974 {
02975     certDBEntrySubject *entry;
02976     unsigned int i;
02977     SECStatus rv;
02978     
02979     entry = ReadDBSubjectEntry(cert->dbhandle,&cert->derSubject);
02980     if ( entry == NULL ) {
02981        return(SECFailure);
02982     }
02983 
02984     PORT_Assert(entry->ncerts);
02985     rv = SECFailure;
02986     
02987     if ( entry->ncerts > 1 ) {
02988        for ( i = 0; i < entry->ncerts; i++ ) {
02989            if ( SECITEM_CompareItem(&entry->certKeys[i], &cert->certKey) ==
02990               SECEqual ) {
02991               /* copy rest of list forward one entry */
02992               for ( i = i + 1; i < entry->ncerts; i++ ) {
02993                   entry->certKeys[i-1] = entry->certKeys[i];
02994                   entry->keyIDs[i-1] = entry->keyIDs[i];
02995               }
02996               entry->ncerts--;
02997               DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
02998               rv = WriteDBSubjectEntry(cert->dbhandle, entry);
02999               break;
03000            }
03001        }
03002     } else {
03003        /* no entries left, delete the perm entry in the DB */
03004        if ( entry->emailAddrs ) {
03005            /* if the subject had an email record, then delete it too */
03006            for (i=0; i < entry->nemailAddrs; i++) {
03007               DeleteDBSMimeEntry(cert->dbhandle, entry->emailAddrs[i]);
03008            }
03009        }
03010        if ( entry->nickname ) {
03011            DeleteDBNicknameEntry(cert->dbhandle, entry->nickname);
03012        }
03013        
03014        DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
03015     }
03016     DestroyDBEntry((certDBEntry *)entry);
03017 
03018     return(rv);
03019 }
03020 
03021 /*
03022  * add a cert to the perm subject list
03023  */
03024 static SECStatus
03025 AddPermSubjectNode(certDBEntrySubject *entry, NSSLOWCERTCertificate *cert, 
03026                                                         char *nickname)
03027 {
03028     SECItem *newCertKeys, *newKeyIDs;
03029     unsigned int i, new_i;
03030     SECStatus rv;
03031     NSSLOWCERTCertificate *cmpcert;
03032     unsigned int nnlen;
03033     unsigned int ncerts;
03034     PRBool added = PR_FALSE;
03035 
03036     PORT_Assert(entry);    
03037     ncerts = entry->ncerts;
03038        
03039     if ( nickname && entry->nickname ) {
03040        /* nicknames must be the same */
03041        PORT_Assert(PORT_Strcmp(nickname, entry->nickname) == 0);
03042     }
03043 
03044     if ( ( entry->nickname == NULL ) && ( nickname != NULL ) ) {
03045        /* copy nickname into the entry */
03046        nnlen = PORT_Strlen(nickname) + 1;
03047        entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena,nnlen);
03048        if ( entry->nickname == NULL ) {
03049            return(SECFailure);
03050        }
03051        PORT_Memcpy(entry->nickname, nickname, nnlen);
03052     }
03053        
03054     /* a DB entry already exists, so add this cert */
03055     newCertKeys = (SECItem *)PORT_ArenaAlloc(entry->common.arena,
03056                                     sizeof(SECItem) * ( ncerts + 1 ) );
03057     newKeyIDs = (SECItem *)PORT_ArenaAlloc(entry->common.arena,
03058                                     sizeof(SECItem) * ( ncerts + 1 ) );
03059 
03060     if ( ( newCertKeys == NULL ) || ( newKeyIDs == NULL ) ) {
03061            return(SECFailure);
03062     }
03063 
03064     for ( i = 0, new_i=0; i < ncerts; i++ ) {
03065        cmpcert = nsslowcert_FindCertByKey(cert->dbhandle,
03066                                             &entry->certKeys[i]);
03067        /* The entry has been corrupted, remove it from the list */
03068        if (!cmpcert) {
03069            continue;
03070        }
03071 
03072        if ( nsslowcert_IsNewer(cert, cmpcert) ) {
03073            nsslowcert_DestroyCertificate(cmpcert);
03074            /* insert before cmpcert */
03075            rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[new_i],
03076                                   &cert->certKey);
03077            if ( rv != SECSuccess ) {
03078               return(SECFailure);
03079            }
03080            rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[new_i],
03081                                   &cert->subjectKeyID);
03082            if ( rv != SECSuccess ) {
03083               return(SECFailure);
03084            }
03085            new_i++;
03086            /* copy the rest of the entry */
03087            for ( ; i < ncerts; i++ ,new_i++) {
03088               newCertKeys[new_i] = entry->certKeys[i];
03089               newKeyIDs[new_i] = entry->keyIDs[i];
03090            }
03091 
03092            /* update certKeys and keyIDs */
03093            entry->certKeys = newCertKeys;
03094            entry->keyIDs = newKeyIDs;
03095               
03096            /* set new count value */
03097            entry->ncerts = new_i;
03098            added = PR_TRUE;
03099            break;
03100        }
03101        nsslowcert_DestroyCertificate(cmpcert);
03102        /* copy this cert entry */
03103        newCertKeys[new_i] = entry->certKeys[i];
03104        newKeyIDs[new_i] = entry->keyIDs[i];
03105        new_i++; /* only increment if we copied the entries */
03106     }
03107 
03108     if ( !added ) {
03109        /* insert new one at end */
03110        rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[new_i],
03111                               &cert->certKey);
03112        if ( rv != SECSuccess ) {
03113            return(SECFailure);
03114        }
03115        rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[new_i],
03116                               &cert->subjectKeyID);
03117        if ( rv != SECSuccess ) {
03118            return(SECFailure);
03119        }
03120        new_i++;
03121 
03122        /* update certKeys and keyIDs */
03123        entry->certKeys = newCertKeys;
03124        entry->keyIDs = newKeyIDs;
03125               
03126        /* increment count */
03127        entry->ncerts = new_i;
03128     }
03129     DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
03130     rv = WriteDBSubjectEntry(cert->dbhandle, entry);
03131     return(rv);
03132 }
03133 
03134 
03135 SECStatus
03136 nsslowcert_TraversePermCertsForSubject(NSSLOWCERTCertDBHandle *handle,
03137                              SECItem *derSubject,
03138                              NSSLOWCERTCertCallback cb, void *cbarg)
03139 {
03140     certDBEntrySubject *entry;
03141     unsigned int i;
03142     NSSLOWCERTCertificate *cert;
03143     SECStatus rv = SECSuccess;
03144     
03145     entry = ReadDBSubjectEntry(handle, derSubject);
03146 
03147     if ( entry == NULL ) {
03148        return(SECFailure);
03149     }
03150     
03151     for( i = 0; i < entry->ncerts; i++ ) {
03152        cert = nsslowcert_FindCertByKey(handle, &entry->certKeys[i]);
03153        if (!cert) {
03154            continue;
03155        }
03156        rv = (* cb)(cert, cbarg);
03157        nsslowcert_DestroyCertificate(cert);
03158        if ( rv == SECFailure ) {
03159            break;
03160        }
03161     }
03162 
03163     DestroyDBEntry((certDBEntry *)entry);
03164 
03165     return(rv);
03166 }
03167 
03168 int
03169 nsslowcert_NumPermCertsForSubject(NSSLOWCERTCertDBHandle *handle,
03170                                                   SECItem *derSubject)
03171 {
03172     certDBEntrySubject *entry;
03173     int ret;
03174     
03175     entry = ReadDBSubjectEntry(handle, derSubject);
03176 
03177     if ( entry == NULL ) {
03178        return(SECFailure);
03179     }
03180 
03181     ret = entry->ncerts;
03182     
03183     DestroyDBEntry((certDBEntry *)entry);
03184     
03185     return(ret);
03186 }
03187 
03188 SECStatus
03189 nsslowcert_TraversePermCertsForNickname(NSSLOWCERTCertDBHandle *handle,
03190                      char *nickname, NSSLOWCERTCertCallback cb, void *cbarg)
03191 {
03192     certDBEntryNickname *nnentry = NULL;
03193     certDBEntrySMime *smentry = NULL;
03194     SECStatus rv;
03195     SECItem *derSubject = NULL;
03196     
03197     nnentry = ReadDBNicknameEntry(handle, nickname);
03198     if ( nnentry ) {
03199        derSubject = &nnentry->subjectName;
03200     } else {
03201        smentry = nsslowcert_ReadDBSMimeEntry(handle, nickname);
03202        if ( smentry ) {
03203            derSubject = &smentry->subjectName;
03204        }
03205     }
03206     
03207     if ( derSubject ) {
03208        rv = nsslowcert_TraversePermCertsForSubject(handle, derSubject,
03209                                          cb, cbarg);
03210     } else {
03211        rv = SECFailure;
03212     }
03213 
03214     if ( nnentry ) {
03215        DestroyDBEntry((certDBEntry *)nnentry);
03216     }
03217     if ( smentry ) {
03218        DestroyDBEntry((certDBEntry *)smentry);
03219     }
03220     
03221     return(rv);
03222 }
03223 
03224 int
03225 nsslowcert_NumPermCertsForNickname(NSSLOWCERTCertDBHandle *handle, 
03226                                                         char *nickname)
03227 {
03228     certDBEntryNickname *entry;
03229     int ret;
03230     
03231     entry = ReadDBNicknameEntry(handle, nickname);
03232     
03233     if ( entry ) {
03234        ret = nsslowcert_NumPermCertsForSubject(handle, &entry->subjectName);
03235        DestroyDBEntry((certDBEntry *)entry);
03236     } else {
03237        ret = 0;
03238     }
03239     return(ret);
03240 }
03241 
03242 /*
03243  * add a nickname to a cert that doesn't have one
03244  */
03245 static SECStatus
03246 AddNicknameToPermCert(NSSLOWCERTCertDBHandle *dbhandle,
03247                             NSSLOWCERTCertificate *cert, char *nickname)
03248 {
03249     certDBEntryCert *entry;
03250     int rv;
03251 
03252     entry = cert->dbEntry;
03253     PORT_Assert(entry != NULL);
03254     if ( entry == NULL ) {
03255        goto loser;
03256     }
03257 
03258     pkcs11_freeNickname(entry->nickname,entry->nicknameSpace);
03259     entry->nickname = NULL;
03260     entry->nickname = pkcs11_copyNickname(nickname,entry->nicknameSpace,
03261                                    sizeof(entry->nicknameSpace));
03262 
03263     rv = WriteDBCertEntry(dbhandle, entry);
03264     if ( rv ) {
03265        goto loser;
03266     }
03267 
03268     pkcs11_freeNickname(cert->nickname,cert->nicknameSpace);
03269     cert->nickname = NULL;
03270     cert->nickname = pkcs11_copyNickname(nickname,cert->nicknameSpace,
03271                                    sizeof(cert->nicknameSpace));
03272 
03273     return(SECSuccess);
03274     
03275 loser:
03276     return(SECFailure);
03277 }
03278 
03279 /*
03280  * add a nickname to a cert that is already in the perm database, but doesn't
03281  * have one yet (it is probably an e-mail cert).
03282  */
03283 SECStatus
03284 nsslowcert_AddPermNickname(NSSLOWCERTCertDBHandle *dbhandle,
03285                             NSSLOWCERTCertificate *cert, char *nickname)
03286 {
03287     SECStatus rv = SECFailure;
03288     certDBEntrySubject *entry = NULL;
03289     certDBEntryNickname *nicknameEntry = NULL;
03290     
03291     nsslowcert_LockDB(dbhandle);
03292 
03293     entry = ReadDBSubjectEntry(dbhandle, &cert->derSubject);
03294     if (entry == NULL) goto loser;
03295 
03296     if ( entry->nickname == NULL ) {
03297 
03298        /* no nickname for subject */
03299        rv = AddNicknameToSubject(dbhandle, cert, nickname);
03300        if ( rv != SECSuccess ) {
03301            goto loser;
03302        }
03303        rv = AddNicknameToPermCert(dbhandle, cert, nickname);
03304        if ( rv != SECSuccess ) {
03305            goto loser;
03306        }
03307        nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0);
03308        if ( nicknameEntry == NULL ) {
03309            goto loser;
03310        }
03311     
03312        rv = WriteDBNicknameEntry(dbhandle, nicknameEntry);
03313        if ( rv != SECSuccess ) {
03314            goto loser;
03315        }
03316     } else {
03317        /* subject already has a nickname */
03318        rv = AddNicknameToPermCert(dbhandle, cert, entry->nickname);
03319        if ( rv != SECSuccess ) {
03320            goto loser;
03321        }
03322        /* make sure nickname entry exists. If the database was corrupted,
03323         * we may have lost the nickname entry. Add it back now  */
03324        nicknameEntry = ReadDBNicknameEntry(dbhandle, entry->nickname);
03325        if (nicknameEntry == NULL ) {
03326            nicknameEntry = NewDBNicknameEntry(entry->nickname, 
03327                                                  &cert->derSubject, 0);
03328            if ( nicknameEntry == NULL ) {
03329               goto loser;
03330            }
03331     
03332            rv = WriteDBNicknameEntry(dbhandle, nicknameEntry);
03333            if ( rv != SECSuccess ) {
03334               goto loser;
03335            }
03336        }
03337     }
03338     rv = SECSuccess;
03339 
03340 loser:
03341     if (entry) {
03342        DestroyDBEntry((certDBEntry *)entry);
03343     }
03344     if (nicknameEntry) {
03345        DestroyDBEntry((certDBEntry *)nicknameEntry);
03346     }
03347     nsslowcert_UnlockDB(dbhandle);
03348     return(rv);
03349 }
03350 
03351 static certDBEntryCert *
03352 AddCertToPermDB(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTCertificate *cert,
03353               char *nickname, NSSLOWCERTCertTrust *trust)
03354 {
03355     certDBEntryCert *certEntry = NULL;
03356     certDBEntryNickname *nicknameEntry = NULL;
03357     certDBEntrySubject *subjectEntry = NULL;
03358     int state = 0;
03359     SECStatus rv;
03360     PRBool donnentry = PR_FALSE;
03361 
03362     if ( nickname ) {
03363        donnentry = PR_TRUE;
03364     }
03365 
03366     subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject);
03367        
03368     if ( subjectEntry && subjectEntry->nickname ) {
03369        donnentry = PR_FALSE;
03370        nickname = subjectEntry->nickname;
03371     }
03372     
03373     certEntry = NewDBCertEntry(&cert->derCert, nickname, trust, 0);
03374     if ( certEntry == NULL ) {
03375        goto loser;
03376     }
03377     
03378     if ( donnentry ) {
03379        nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0);
03380        if ( nicknameEntry == NULL ) {
03381            goto loser;
03382        }
03383     }
03384     
03385     rv = WriteDBCertEntry(handle, certEntry);
03386     if ( rv != SECSuccess ) {
03387        goto loser;
03388     }
03389     state = 1;
03390     
03391     if ( nicknameEntry ) {
03392        rv = WriteDBNicknameEntry(handle, nicknameEntry);
03393        if ( rv != SECSuccess ) {
03394            goto loser;
03395        }
03396     }
03397     
03398     state = 2;
03399 
03400     /* "Change" handles if necessary */
03401     if (cert->dbhandle) {
03402        sftk_freeCertDB(cert->dbhandle);
03403     }
03404     cert->dbhandle = nsslowcert_reference(handle);
03405     
03406     /* add to or create new subject entry */
03407     if ( subjectEntry ) {
03408        /* REWRITE BASED ON SUBJECT ENTRY */
03409        rv = AddPermSubjectNode(subjectEntry, cert, nickname);
03410        if ( rv != SECSuccess ) {
03411            goto loser;
03412        }
03413     } else {
03414        /* make a new subject entry - this case is only used when updating
03415         * an old version of the database.  This is OK because the oldnickname
03416         * db format didn't allow multiple certs with the same subject.
03417         */
03418        /* where does subjectKeyID and certKey come from? */
03419        subjectEntry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey,
03420                                     &cert->subjectKeyID, nickname,
03421                                     NULL, 0);
03422        if ( subjectEntry == NULL ) {
03423            goto loser;
03424        }
03425        rv = WriteDBSubjectEntry(handle, subjectEntry);
03426        if ( rv != SECSuccess ) {
03427            goto loser;
03428        }
03429     }
03430     
03431     state = 3;
03432     
03433     if ( nicknameEntry ) {
03434        DestroyDBEntry((certDBEntry *)nicknameEntry);
03435     }
03436     
03437     if ( subjectEntry ) {
03438        DestroyDBEntry((certDBEntry *)subjectEntry);
03439     }
03440 
03441     return(certEntry);
03442 
03443 loser:
03444     /* don't leave partial entry in the database */
03445     if ( state > 0 ) {
03446        rv = DeleteDBCertEntry(handle, &cert->certKey);
03447     }
03448     if ( ( state > 1 ) && donnentry ) {
03449        rv = DeleteDBNicknameEntry(handle, nickname);
03450     }
03451     if ( state > 2 ) {
03452        rv = DeleteDBSubjectEntry(handle, &cert->derSubject);
03453     }
03454     if ( certEntry ) {
03455        DestroyDBEntry((certDBEntry *)certEntry);
03456     }
03457     if ( nicknameEntry ) {
03458        DestroyDBEntry((certDBEntry *)nicknameEntry);
03459     }
03460     if ( subjectEntry ) {
03461        DestroyDBEntry((certDBEntry *)subjectEntry);
03462     }
03463 
03464     return(NULL);
03465 }
03466 
03467 /* forward declaration */
03468 static SECStatus
03469 UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb);
03470 
03471 /*
03472  * version 8 uses the same schema as version 7. The only differences are
03473  * 1) version 8 db uses the blob shim to store data entries > 32k.
03474  * 2) version 8 db sets the db block size to 32k.
03475  * both of these are dealt with by the handle.
03476  */
03477 
03478 static SECStatus
03479 UpdateV8DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
03480 {
03481     return UpdateV7DB(handle,updatedb);
03482 }
03483 
03484 
03485 /*
03486  * we could just blindly sequence through reading key data pairs and writing
03487  * them back out, but some cert.db's have gotten quite large and may have some
03488  * subtle corruption problems, so instead we cycle through the certs and
03489  * CRL's and S/MIME profiles and rebuild our subject lists from those records.
03490  */
03491 static SECStatus
03492 UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
03493 {
03494     DBT key, data;
03495     int ret;
03496     NSSLOWCERTCertificate *cert;
03497     PRBool isKRL = PR_FALSE;
03498     certDBEntryType entryType;
03499     SECItem dbEntry, dbKey;
03500     certDBEntryRevocation crlEntry;
03501     certDBEntryCert certEntry;
03502     certDBEntrySMime smimeEntry;
03503     SECStatus rv;
03504 
03505     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
03506 
03507     if ( ret ) {
03508        return(SECFailure);
03509     }
03510     
03511     do {
03512        unsigned char *dataBuf = (unsigned char *)data.data;
03513        unsigned char *keyBuf = (unsigned char *)key.data;
03514        dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN];
03515        dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN;
03516        entryType = (certDBEntryType) keyBuf[0];
03517        dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN];
03518        dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN;
03519        if ((dbEntry.len <= 0) || (dbKey.len <= 0)) {
03520            continue;
03521        }
03522 
03523        switch (entryType) {
03524        /* these entries will get regenerated as we read the 
03525         * rest of the data from the database */
03526        case certDBEntryTypeVersion:
03527        case certDBEntryTypeSubject:
03528        case certDBEntryTypeContentVersion:
03529        case certDBEntryTypeNickname:
03530        /* smime profiles need entries created after the certs have
03531          * been imported, loop over them in a second run */
03532        case certDBEntryTypeSMimeProfile:
03533            break;
03534 
03535        case certDBEntryTypeCert:
03536            /* decode Entry */
03537            certEntry.common.version = (unsigned int)dataBuf[0];
03538            certEntry.common.type = entryType;
03539            certEntry.common.flags = (unsigned int)dataBuf[2];
03540            rv = DecodeDBCertEntry(&certEntry,&dbEntry);
03541            if (rv != SECSuccess) {
03542               break;
03543            }
03544            /* should we check for existing duplicates? */
03545            cert = nsslowcert_DecodeDERCertificate(&certEntry.derCert, 
03546                                           certEntry.nickname);
03547            if (cert) {
03548               nsslowcert_UpdatePermCert(handle, cert, certEntry.nickname,
03549                                                  &certEntry.trust);
03550               nsslowcert_DestroyCertificate(cert);
03551            }
03552            /* free any data the decode may have allocated. */
03553            pkcs11_freeStaticData(certEntry.derCert.data, 
03554                                           certEntry.derCertSpace);
03555            pkcs11_freeNickname(certEntry.nickname, certEntry.nicknameSpace);
03556            break;
03557 
03558        case certDBEntryTypeKeyRevocation:
03559            isKRL = PR_TRUE;
03560            /* fall through */
03561        case certDBEntryTypeRevocation:
03562            crlEntry.common.version = (unsigned int)dataBuf[0];
03563            crlEntry.common.type = entryType;
03564            crlEntry.common.flags = (unsigned int)dataBuf[2];
03565            crlEntry.common.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
03566            if (crlEntry.common.arena == NULL) {
03567               break;
03568            }
03569            rv = DecodeDBCrlEntry(&crlEntry,&dbEntry);
03570            if (rv != SECSuccess) {
03571               break;
03572            }
03573            nsslowcert_UpdateCrl(handle, &crlEntry.derCrl, &dbKey, 
03574                                           crlEntry.url, isKRL);
03575            /* free data allocated by the decode */
03576            PORT_FreeArena(crlEntry.common.arena, PR_FALSE);
03577            crlEntry.common.arena = NULL;
03578            break;
03579 
03580        default:
03581            break;
03582        }
03583     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
03584 
03585     /* now loop again updating just the SMimeProfile. */
03586     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
03587 
03588     if ( ret ) {
03589        return(SECFailure);
03590     }
03591     
03592     do {
03593        unsigned char *dataBuf = (unsigned char *)data.data;
03594        unsigned char *keyBuf = (unsigned char *)key.data;
03595        dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN];
03596        dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN;
03597        entryType = (certDBEntryType) keyBuf[0];
03598        if (entryType != certDBEntryTypeSMimeProfile) {
03599            continue;
03600        }
03601        dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN];
03602        dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN;
03603        if ((dbEntry.len <= 0) || (dbKey.len <= 0)) {
03604            continue;
03605        }
03606         smimeEntry.common.version = (unsigned int)dataBuf[0];
03607        smimeEntry.common.type = entryType;
03608        smimeEntry.common.flags = (unsigned int)dataBuf[2];
03609        smimeEntry.common.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
03610        /* decode entry */
03611        rv = DecodeDBSMimeEntry(&smimeEntry,&dbEntry,(char *)dbKey.data);
03612        if (rv == SECSuccess) {
03613            nsslowcert_UpdateSMimeProfile(handle, smimeEntry.emailAddr,
03614               &smimeEntry.subjectName, &smimeEntry.smimeOptions,
03615                                            &smimeEntry.optionsDate);
03616        }
03617        PORT_FreeArena(smimeEntry.common.arena, PR_FALSE);
03618        smimeEntry.common.arena = NULL;
03619     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
03620 
03621     (* updatedb->close)(updatedb);
03622 
03623     /* a database update is a good time to go back and verify the integrity of
03624      * the keys and certs */
03625     handle->dbVerify = PR_TRUE; 
03626     return(SECSuccess);
03627 }
03628 
03629 /*
03630  * NOTE - Version 6 DB did not go out to the real world in a release,
03631  * so we can remove this function in a later release.
03632  */
03633 static SECStatus
03634 UpdateV6DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
03635 {
03636     int ret;
03637     DBT key, data;
03638     unsigned char *buf, *tmpbuf = NULL;
03639     certDBEntryType type;
03640     certDBEntryNickname *nnEntry = NULL;
03641     certDBEntrySubject *subjectEntry = NULL;
03642     certDBEntrySMime *emailEntry = NULL;
03643     char *nickname;
03644     char *emailAddr;
03645     SECStatus rv;
03646     
03647     /*
03648      * Sequence through the old database and copy all of the entries
03649      * to the new database.  Subject name entries will have the new
03650      * fields inserted into them (with zero length).
03651      */
03652     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
03653     if ( ret ) {
03654        return(SECFailure);
03655     }
03656 
03657     do {
03658        buf = (unsigned char *)data.data;
03659        
03660        if ( data.size >= 3 ) {
03661            if ( buf[0] == 6 ) { /* version number */
03662               type = (certDBEntryType)buf[1];
03663               if ( type == certDBEntryTypeSubject ) {
03664                   /* expando subjecto entrieo */
03665                   tmpbuf = (unsigned char *)PORT_Alloc(data.size + 4);
03666                   if ( tmpbuf ) {
03667                      /* copy header stuff */
03668                      PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN + 2);
03669                      /* insert 4 more bytes of zero'd header */
03670                      PORT_Memset(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 2],
03671                                 0, 4);
03672                      /* copy rest of the data */
03673                      PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6],
03674                                 &buf[SEC_DB_ENTRY_HEADER_LEN + 2],
03675                                 data.size - (SEC_DB_ENTRY_HEADER_LEN + 2));
03676 
03677                      data.data = (void *)tmpbuf;
03678                      data.size += 4;
03679                      buf = tmpbuf;
03680                   }
03681               } else if ( type == certDBEntryTypeCert ) {
03682                   /* expando certo entrieo */
03683                   tmpbuf = (unsigned char *)PORT_Alloc(data.size + 3);
03684                   if ( tmpbuf ) {
03685                      /* copy header stuff */
03686                      PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN);
03687 
03688                      /* copy trust flage, setting msb's to 0 */
03689                      tmpbuf[SEC_DB_ENTRY_HEADER_LEN] = 0;
03690                      tmpbuf[SEC_DB_ENTRY_HEADER_LEN+1] =
03691                          buf[SEC_DB_ENTRY_HEADER_LEN];
03692                      tmpbuf[SEC_DB_ENTRY_HEADER_LEN+2] = 0;
03693                      tmpbuf[SEC_DB_ENTRY_HEADER_LEN+3] =
03694                          buf[SEC_DB_ENTRY_HEADER_LEN+1];
03695                      tmpbuf[SEC_DB_ENTRY_HEADER_LEN+4] = 0;
03696                      tmpbuf[SEC_DB_ENTRY_HEADER_LEN+5] =
03697                          buf[SEC_DB_ENTRY_HEADER_LEN+2];
03698                      
03699                      /* copy rest of the data */
03700                      PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6],
03701                                 &buf[SEC_DB_ENTRY_HEADER_LEN + 3],
03702                                 data.size - (SEC_DB_ENTRY_HEADER_LEN + 3));
03703 
03704                      data.data = (void *)tmpbuf;
03705                      data.size += 3;
03706                      buf = tmpbuf;
03707                   }
03708 
03709               }
03710 
03711               /* update the record version number */
03712               buf[0] = CERT_DB_FILE_VERSION;
03713 
03714               /* copy to the new database */
03715               ret = certdb_Put(handle->permCertDB, &key, &data, 0);
03716               if ( tmpbuf ) {
03717                   PORT_Free(tmpbuf);
03718                   tmpbuf = NULL;
03719               }
03720            }
03721        }
03722     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
03723 
03724     ret = certdb_Sync(handle->permCertDB, 0);
03725 
03726     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
03727     if ( ret ) {
03728        return(SECFailure);
03729     }
03730 
03731     do {
03732        buf = (unsigned char *)data.data;
03733        
03734        if ( data.size >= 3 ) {
03735            if ( buf[0] == CERT_DB_FILE_VERSION ) { /* version number */
03736               type = (certDBEntryType)buf[1];
03737               if ( type == certDBEntryTypeNickname ) {
03738                   nickname = &((char *)key.data)[1];
03739 
03740                   /* get the matching nickname entry in the new DB */
03741                   nnEntry = ReadDBNicknameEntry(handle, nickname);
03742                   if ( nnEntry == NULL ) {
03743                      goto endloop;
03744                   }
03745                   
03746                   /* find the subject entry pointed to by nickname */
03747                   subjectEntry = ReadDBSubjectEntry(handle,
03748                                                 &nnEntry->subjectName);
03749                   if ( subjectEntry == NULL ) {
03750                      goto endloop;
03751                   }
03752                   
03753                   subjectEntry->nickname =
03754                      (char *)PORT_ArenaAlloc(subjectEntry->common.arena,
03755                                           key.size - 1);
03756                   if ( subjectEntry->nickname ) {
03757                      PORT_Memcpy(subjectEntry->nickname, nickname,
03758                                 key.size - 1);
03759                      rv = WriteDBSubjectEntry(handle, subjectEntry);
03760                   }
03761               } else if ( type == certDBEntryTypeSMimeProfile ) {
03762                   emailAddr = &((char *)key.data)[1];
03763 
03764                   /* get the matching smime entry in the new DB */
03765                   emailEntry = nsslowcert_ReadDBSMimeEntry(handle, emailAddr);
03766                   if ( emailEntry == NULL ) {
03767                      goto endloop;
03768                   }
03769                   
03770                   /* find the subject entry pointed to by nickname */
03771                   subjectEntry = ReadDBSubjectEntry(handle,
03772                                                 &emailEntry->subjectName);
03773                   if ( subjectEntry == NULL ) {
03774                      goto endloop;
03775                   }
03776                   
03777                   subjectEntry->emailAddrs = (char **)
03778                             PORT_ArenaAlloc(subjectEntry->common.arena,
03779                                           sizeof(char *));
03780                   if ( subjectEntry->emailAddrs ) {
03781                      subjectEntry->emailAddrs[0] =
03782                           (char *)PORT_ArenaAlloc(subjectEntry->common.arena,
03783                                           key.size - 1);
03784                      if ( subjectEntry->emailAddrs[0] ) {
03785                          PORT_Memcpy(subjectEntry->emailAddrs[0], emailAddr,
03786                                 key.size - 1);
03787                          subjectEntry->nemailAddrs = 1;
03788                          rv = WriteDBSubjectEntry(handle, subjectEntry);
03789                      }
03790                   }
03791               }
03792               
03793 endloop:
03794               if ( subjectEntry ) {
03795                   DestroyDBEntry((certDBEntry *)subjectEntry);
03796                   subjectEntry = NULL;
03797               }
03798               if ( nnEntry ) {
03799                   DestroyDBEntry((certDBEntry *)nnEntry);
03800                   nnEntry = NULL;
03801               }
03802               if ( emailEntry ) {
03803                   DestroyDBEntry((certDBEntry *)emailEntry);
03804                   emailEntry = NULL;
03805               }
03806            }
03807        }
03808     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
03809 
03810     ret = certdb_Sync(handle->permCertDB, 0);
03811 
03812     (* updatedb->close)(updatedb);
03813     return(SECSuccess);
03814 }
03815 
03816 
03817 static SECStatus
03818 updateV5Callback(NSSLOWCERTCertificate *cert, SECItem *k, void *pdata)
03819 {
03820     NSSLOWCERTCertDBHandle *handle;
03821     certDBEntryCert *entry;
03822     NSSLOWCERTCertTrust *trust;
03823     
03824     handle = (NSSLOWCERTCertDBHandle *)pdata;
03825     trust = &cert->dbEntry->trust;
03826 
03827     /* SSL user certs can be used for email if they have an email addr */
03828     if ( cert->emailAddr && ( trust->sslFlags & CERTDB_USER ) &&
03829        ( trust->emailFlags == 0 ) ) {
03830        trust->emailFlags = CERTDB_USER;
03831     }
03832     /* servers didn't set the user flags on the server cert.. */
03833     if (PORT_Strcmp(cert->dbEntry->nickname,"Server-Cert") == 0) {
03834        trust->sslFlags |= CERTDB_USER;
03835     }
03836     
03837     entry = AddCertToPermDB(handle, cert, cert->dbEntry->nickname,
03838                          &cert->dbEntry->trust);
03839     if ( entry ) {
03840        DestroyDBEntry((certDBEntry *)entry);
03841     }
03842     
03843     return(SECSuccess);
03844 }
03845 
03846 static SECStatus
03847 UpdateV5DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
03848 {
03849     NSSLOWCERTCertDBHandle updatehandle;
03850     SECStatus rv;
03851     
03852     updatehandle.permCertDB = updatedb;
03853     updatehandle.dbMon = PZ_NewMonitor(nssILockCertDB);
03854     updatehandle.dbVerify = 0;
03855     updatehandle.ref      = 1; /* prevent premature close */
03856     
03857     rv = nsslowcert_TraversePermCerts(&updatehandle, updateV5Callback,
03858                             (void *)handle);
03859     
03860     PZ_DestroyMonitor(updatehandle.dbMon);
03861 
03862     (* updatedb->close)(updatedb);
03863     return(SECSuccess);
03864 }
03865 
03866 static PRBool
03867 isV4DB(DB *db) {
03868     DBT key,data;
03869     int ret;
03870 
03871     key.data = "Version";
03872     key.size = 7;
03873 
03874     ret = (*db->get)(db, &key, &data, 0);
03875     if (ret) {
03876        return PR_FALSE;
03877     }
03878 
03879     if ((data.size == 1) && (*(unsigned char *)data.data <= 4))  {
03880        return PR_TRUE;
03881     }
03882 
03883     return PR_FALSE;
03884 }
03885 
03886 static SECStatus
03887 UpdateV4DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
03888 {
03889     DBT key, data;
03890     certDBEntryCert *entry, *entry2;
03891     int ret;
03892     PRArenaPool *arena = NULL;
03893     NSSLOWCERTCertificate *cert;
03894 
03895     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
03896 
03897     if ( ret ) {
03898        return(SECFailure);
03899     }
03900 
03901     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
03902     if (arena == NULL) {
03903        return(SECFailure);
03904     }
03905     
03906     do {
03907        if ( data.size != 1 ) { /* skip version number */
03908 
03909            /* decode the old DB entry */
03910            entry = (certDBEntryCert *)
03911               DecodeV4DBCertEntry((unsigned char*)data.data, data.size);
03912            
03913            if ( entry ) {
03914               cert = nsslowcert_DecodeDERCertificate(&entry->derCert, 
03915                                            entry->nickname);
03916 
03917               if ( cert != NULL ) {
03918                   /* add to new database */
03919                   entry2 = AddCertToPermDB(handle, cert, entry->nickname,
03920                                         &entry->trust);
03921                   
03922                   nsslowcert_DestroyCertificate(cert);
03923                   if ( entry2 ) {
03924                      DestroyDBEntry((certDBEntry *)entry2);
03925                   }
03926               }
03927               DestroyDBEntry((certDBEntry *)entry);
03928            }
03929        }
03930     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
03931 
03932     PORT_FreeArena(arena, PR_FALSE);
03933     (* updatedb->close)(updatedb);
03934     return(SECSuccess);
03935 }
03936 
03937 
03938 /*
03939  * return true if a database key conflict exists
03940  */
03941 PRBool
03942 nsslowcert_CertDBKeyConflict(SECItem *derCert, NSSLOWCERTCertDBHandle *handle)
03943 {
03944     SECStatus rv;
03945     DBT tmpdata;
03946     DBT namekey;
03947     int ret;
03948     SECItem keyitem;
03949     PRArenaPool *arena = NULL;
03950     SECItem derKey;
03951     
03952     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
03953     if ( arena == NULL ) {
03954        goto loser;
03955     }
03956 
03957     /* get the db key of the cert */
03958     rv = nsslowcert_KeyFromDERCert(arena, derCert, &derKey);
03959     if ( rv != SECSuccess ) {
03960         goto loser;
03961     }
03962 
03963     rv = EncodeDBCertKey(&derKey, arena, &keyitem);
03964     if ( rv != SECSuccess ) {
03965        goto loser;
03966     }
03967     
03968     namekey.data = keyitem.data;
03969     namekey.size = keyitem.len;
03970     
03971     ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0);
03972     if ( ret == 0 ) {
03973        goto loser;
03974     }
03975 
03976     PORT_FreeArena(arena, PR_FALSE);
03977     
03978     return(PR_FALSE);
03979 loser:
03980     if ( arena ) {
03981        PORT_FreeArena(arena, PR_FALSE);
03982     }
03983     
03984     return(PR_TRUE);
03985 }
03986 
03987 /*
03988  * return true if a nickname conflict exists
03989  * NOTE: caller must have already made sure that this exact cert
03990  * doesn't exist in the DB
03991  */
03992 static PRBool
03993 nsslowcert_CertNicknameConflict(char *nickname, SECItem *derSubject,
03994                       NSSLOWCERTCertDBHandle *handle)
03995 {
03996     PRBool rv;
03997     certDBEntryNickname *entry;
03998     
03999     if ( nickname == NULL ) {
04000        return(PR_FALSE);
04001     }
04002     
04003     entry = ReadDBNicknameEntry(handle, nickname);
04004 
04005     if ( entry == NULL ) {
04006        /* no entry for this nickname, so no conflict */
04007        return(PR_FALSE);
04008     }
04009 
04010     rv = PR_TRUE;
04011     if ( SECITEM_CompareItem(derSubject, &entry->subjectName) == SECEqual ) {
04012        /* if subject names are the same, then no conflict */
04013        rv = PR_FALSE;
04014     }
04015 
04016     DestroyDBEntry((certDBEntry *)entry);
04017     return(rv);
04018 }
04019 
04020 #ifdef DBM_USING_NSPR
04021 #define NO_RDONLY    PR_RDONLY
04022 #define NO_RDWR             PR_RDWR
04023 #define NO_CREATE    (PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE)
04024 #else
04025 #define NO_RDONLY    O_RDONLY
04026 #define NO_RDWR             O_RDWR
04027 #define NO_CREATE    (O_RDWR | O_CREAT | O_TRUNC)
04028 #endif
04029 
04030 /*
04031  * open an old database that needs to be updated
04032  */
04033 static DB *
04034 nsslowcert_openolddb(NSSLOWCERTDBNameFunc namecb, void *cbarg, int version)
04035 {
04036     char * tmpname;
04037     DB *updatedb = NULL;
04038 
04039     tmpname = (* namecb)(cbarg, version); /* get v6 db name */
04040     if ( tmpname ) {
04041        updatedb = dbopen( tmpname, NO_RDONLY, 0600, DB_HASH, 0 );
04042        PORT_Free(tmpname);
04043     }
04044     return updatedb;
04045 }
04046 
04047 static SECStatus
04048 openNewCertDB(const char *appName, const char *prefix, const char *certdbname, 
04049     NSSLOWCERTCertDBHandle *handle, NSSLOWCERTDBNameFunc namecb, void *cbarg)
04050 {
04051     SECStatus rv;
04052     certDBEntryVersion *versionEntry = NULL;
04053     DB *updatedb = NULL;
04054     int status = RDB_FAIL;
04055 
04056     if (appName) {
04057        handle->permCertDB=rdbopen( appName, prefix, "cert", NO_CREATE, &status);
04058     } else {
04059        handle->permCertDB=dbsopen(certdbname, NO_CREATE, 0600, DB_HASH, 0);
04060     }
04061 
04062     /* if create fails then we lose */
04063     if ( handle->permCertDB == 0 ) {
04064        return status == RDB_RETRY ? SECWouldBlock : SECFailure;
04065     }
04066 
04067     rv = db_BeginTransaction(handle->permCertDB);
04068     if (rv != SECSuccess) {
04069        db_InitComplete(handle->permCertDB);
04070        return SECFailure;
04071     }
04072 
04073     /* Verify version number; */
04074     versionEntry = NewDBVersionEntry(0);
04075     if ( versionEntry == NULL ) {
04076        rv = SECFailure;
04077        goto loser;
04078     }
04079        
04080     rv = WriteDBVersionEntry(handle, versionEntry);
04081 
04082     DestroyDBEntry((certDBEntry *)versionEntry);
04083 
04084     if ( rv != SECSuccess ) {
04085        goto loser;
04086     }
04087 
04088     /* rv must already be Success here because of previous if statement */
04089     /* try to upgrade old db here */
04090     if (appName &&
04091        (updatedb = dbsopen(certdbname, NO_RDONLY, 0600, DB_HASH, 0)) != NULL) {
04092        rv = UpdateV8DB(handle, updatedb);
04093     } else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,7)) != NULL) {
04094        rv = UpdateV7DB(handle, updatedb);
04095     } else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,6)) != NULL) {
04096        rv = UpdateV6DB(handle, updatedb);
04097     } else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,5)) != NULL) {
04098        rv = UpdateV5DB(handle, updatedb);
04099     } else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,4)) != NULL) {
04100        /* NES has v5 format db's with v4 db names! */
04101        if (isV4DB(updatedb)) {
04102            rv = UpdateV4DB(handle,updatedb);
04103        } else {
04104            rv = UpdateV5DB(handle,updatedb);
04105        }
04106     }
04107 
04108 
04109 loser:
04110     db_FinishTransaction(handle->permCertDB,rv != SECSuccess);
04111     db_InitComplete(handle->permCertDB);
04112     return rv;
04113 }
04114 
04115 static int
04116 nsslowcert_GetVersionNumber( NSSLOWCERTCertDBHandle *handle)
04117 {
04118     certDBEntryVersion *versionEntry = NULL;
04119     int version = 0;
04120 
04121     versionEntry = ReadDBVersionEntry(handle); 
04122     if ( versionEntry == NULL ) {
04123        return 0;
04124     }
04125     version = versionEntry->common.version;
04126     DestroyDBEntry((certDBEntry *)versionEntry);
04127     return version;
04128 }
04129 
04130 /*
04131  * Open the certificate database and index databases.  Create them if
04132  * they are not there or bad.
04133  */
04134 static SECStatus
04135 nsslowcert_OpenPermCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly,
04136                             const char *appName, const char *prefix,
04137                             NSSLOWCERTDBNameFunc namecb, void *cbarg)
04138 {
04139     SECStatus rv;
04140     int openflags;
04141     char *certdbname;
04142     int version = 0;
04143     
04144     certdbname = (* namecb)(cbarg, CERT_DB_FILE_VERSION);
04145     if ( certdbname == NULL ) {
04146        return(SECFailure);
04147     }
04148 
04149     openflags = readOnly ? NO_RDONLY : NO_RDWR;
04150 
04151     /*
04152      * first open the permanent file based database.
04153      */
04154     if (appName) {
04155        handle->permCertDB = rdbopen( appName, prefix, "cert", openflags, NULL);
04156     } else {
04157        handle->permCertDB = dbsopen( certdbname, openflags, 0600, DB_HASH, 0 );
04158     }
04159 
04160     /* check for correct version number */
04161     if ( handle->permCertDB ) {
04162        version = nsslowcert_GetVersionNumber(handle);
04163        if ((version != CERT_DB_FILE_VERSION) &&
04164               !(appName && version == CERT_DB_V7_FILE_VERSION)) {
04165            goto loser;
04166        }
04167     } else if ( readOnly ) {
04168        /* don't create if readonly */
04169            /* Try openning a version 7 database */
04170            handle->permCertDB = nsslowcert_openolddb(namecb,cbarg, 7);
04171            if (!handle->permCertDB) {
04172               goto loser;
04173            }
04174            if (nsslowcert_GetVersionNumber(handle) != 7) {
04175               goto loser;
04176            }
04177     } else {
04178         /* if first open fails, try to create a new DB */
04179        rv = openNewCertDB(appName,prefix,certdbname,handle,namecb,cbarg);
04180        if (rv == SECWouldBlock) {
04181            /* only the rdb version can fail with wouldblock */
04182            handle->permCertDB = 
04183                      rdbopen( appName, prefix, "cert", openflags, NULL);
04184 
04185            /* check for correct version number */
04186            if ( !handle->permCertDB ) {
04187               goto loser;
04188            }
04189            version = nsslowcert_GetVersionNumber(handle);
04190            if ((version != CERT_DB_FILE_VERSION) &&
04191               !(appName && version == CERT_DB_V7_FILE_VERSION)) {
04192               goto loser;
04193            }
04194        } else if (rv != SECSuccess) {
04195            goto loser;
04196        }
04197     }
04198 
04199     PORT_Free(certdbname);
04200     
04201     return (SECSuccess);
04202     
04203 loser:
04204 
04205     PORT_SetError(SEC_ERROR_BAD_DATABASE);
04206     
04207     if ( handle->permCertDB ) {
04208        certdb_Close(handle->permCertDB);
04209        handle->permCertDB = 0;
04210     }
04211 
04212     PORT_Free(certdbname);
04213 
04214     return(SECFailure);
04215 }
04216 
04217 /*
04218  * delete all DB records associated with a particular certificate
04219  */
04220 static SECStatus
04221 DeletePermCert(NSSLOWCERTCertificate *cert)
04222 {
04223     SECStatus rv;
04224     SECStatus ret;
04225 
04226     ret = SECSuccess;
04227     
04228     rv = DeleteDBCertEntry(cert->dbhandle, &cert->certKey);
04229     if ( rv != SECSuccess ) {
04230        ret = SECFailure;
04231     }
04232     
04233     rv = RemovePermSubjectNode(cert);
04234 
04235 
04236     return(ret);
04237 }
04238 
04239 /*
04240  * Delete a certificate from the permanent database.
04241  */
04242 SECStatus
04243 nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert)
04244 {
04245     SECStatus rv;
04246     
04247     nsslowcert_LockDB(cert->dbhandle);
04248 
04249     rv = db_BeginTransaction(cert->dbhandle->permCertDB);
04250     if ( rv != SECSuccess ) {
04251        goto loser;
04252     }
04253     /* delete the records from the permanent database */
04254     rv = DeletePermCert(cert);
04255 
04256     /* get rid of dbcert and stuff pointing to it */
04257     DestroyDBEntry((certDBEntry *)cert->dbEntry);
04258     cert->dbEntry = NULL;
04259     cert->trust = NULL;
04260 
04261     db_FinishTransaction(cert->dbhandle->permCertDB,rv != SECSuccess);
04262 loser:
04263        
04264     nsslowcert_UnlockDB(cert->dbhandle);
04265     return(rv);
04266 }
04267 
04268 /*
04269  * Traverse all of the entries in the database of a particular type
04270  * call the given function for each one.
04271  */
04272 SECStatus
04273 nsslowcert_TraverseDBEntries(NSSLOWCERTCertDBHandle *handle,
04274                     certDBEntryType type,
04275                     SECStatus (* callback)(SECItem *data, SECItem *key,
04276                                        certDBEntryType type, void *pdata),
04277                     void *udata )
04278 {
04279     DBT data;
04280     DBT key;
04281     SECStatus rv;
04282     int ret;
04283     SECItem dataitem;
04284     SECItem keyitem;
04285     unsigned char *buf;
04286     unsigned char *keybuf;
04287     
04288     ret = certdb_Seq(handle->permCertDB, &key, &data, R_FIRST);
04289 
04290     if ( ret ) {
04291        return(SECFailure);
04292     }
04293     
04294     do {
04295        buf = (unsigned char *)data.data;
04296        
04297        if ( buf[1] == (unsigned char)type ) {
04298            dataitem.len = data.size;
04299            dataitem.data = buf;
04300             dataitem.type = siBuffer;
04301            keyitem.len = key.size - SEC_DB_KEY_HEADER_LEN;
04302            keybuf = (unsigned char *)key.data;
04303            keyitem.data = &keybuf[SEC_DB_KEY_HEADER_LEN];
04304             keyitem.type = siBuffer;
04305            /* type should equal keybuf[0].  */
04306 
04307            rv = (* callback)(&dataitem, &keyitem, type, udata);
04308            if ( rv != SECSuccess ) {
04309               return(rv);
04310            }
04311        }
04312     } while ( certdb_Seq(handle->permCertDB, &key, &data, R_NEXT) == 0 );
04313 
04314     return(SECSuccess);
04315 }
04316 /*
04317  * Decode a certificate and enter it into the temporary certificate database.
04318  * Deal with nicknames correctly
04319  *
04320  * This is the private entry point.
04321  */
04322 static NSSLOWCERTCertificate *
04323 DecodeACert(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry)
04324 {
04325     NSSLOWCERTCertificate *cert = NULL;
04326     
04327     cert = nsslowcert_DecodeDERCertificate(&entry->derCert, entry->nickname );
04328     
04329     if ( cert == NULL ) {
04330        goto loser;
04331     }
04332 
04333     cert->dbhandle = nsslowcert_reference(handle);
04334     cert->dbEntry = entry;
04335     cert->trust = &entry->trust;
04336 
04337     return(cert);
04338 
04339 loser:
04340     return(0);
04341 }
04342 
04343 static NSSLOWCERTTrust *
04344 CreateTrust(void)
04345 {
04346     NSSLOWCERTTrust *trust = NULL;
04347 
04348     nsslowcert_LockFreeList();
04349     trust = trustListHead;
04350     if (trust) {
04351        trustListCount--;
04352        trustListHead = trust->next;
04353     }
04354     PORT_Assert(trustListCount >= 0);
04355     nsslowcert_UnlockFreeList();
04356     if (trust) {
04357        return trust;
04358     }
04359 
04360     return PORT_ZNew(NSSLOWCERTTrust);
04361 }
04362 
04363 static void
04364 DestroyTrustFreeList(void)
04365 {
04366     NSSLOWCERTTrust *trust;
04367 
04368     nsslowcert_LockFreeList();
04369     while (NULL != (trust = trustListHead)) {
04370        trustListCount--;
04371        trustListHead = trust->next;
04372        PORT_Free(trust);
04373     }
04374     PORT_Assert(!trustListCount);
04375     trustListCount = 0;
04376     nsslowcert_UnlockFreeList();
04377 }
04378 
04379 static NSSLOWCERTTrust * 
04380 DecodeTrustEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry, 
04381                  SECItem *dbKey)
04382 {
04383     NSSLOWCERTTrust *trust = CreateTrust();
04384     if (trust == NULL) {
04385        return trust;
04386     }
04387     trust->dbhandle = nsslowcert_reference(handle);
04388     trust->dbEntry = entry;
04389     trust->dbKey.data = pkcs11_copyStaticData(dbKey->data,dbKey->len,
04390                             trust->dbKeySpace, sizeof(trust->dbKeySpace));
04391     if (!trust->dbKey.data) {
04392        PORT_Free(trust);
04393        return NULL;
04394     }
04395     trust->dbKey.len = dbKey->len;
04396  
04397     trust->trust = &entry->trust;
04398     trust->derCert = &entry->derCert;
04399 
04400     return(trust);
04401 }
04402 
04403 typedef struct {
04404     PermCertCallback certfunc;
04405     NSSLOWCERTCertDBHandle *handle;
04406     void *data;
04407 } PermCertCallbackState;
04408 
04409 /*
04410  * traversal callback to decode certs and call callers callback
04411  */
04412 static SECStatus
04413 certcallback(SECItem *dbdata, SECItem *dbkey, certDBEntryType type, void *data)
04414 {
04415     PermCertCallbackState *mystate;
04416     SECStatus rv;
04417     certDBEntryCert *entry;
04418     SECItem entryitem;
04419     NSSLOWCERTCertificate *cert;
04420     PRArenaPool *arena = NULL;
04421     
04422     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
04423     if ( arena == NULL ) {
04424        goto loser;
04425     }
04426     
04427     entry = (certDBEntryCert *)PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
04428     mystate = (PermCertCallbackState *)data;
04429     entry->common.version = (unsigned int)dbdata->data[0];
04430     entry->common.type = (certDBEntryType)dbdata->data[1];
04431     entry->common.flags = (unsigned int)dbdata->data[2];
04432     entry->common.arena = arena;
04433     
04434     entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN;
04435     entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN];
04436     
04437     rv = DecodeDBCertEntry(entry, &entryitem);
04438     if (rv != SECSuccess ) {
04439        goto loser;
04440     }
04441     entry->derCert.type = siBuffer;
04442    
04443     /* note: Entry is 'inheritted'.  */
04444     cert = DecodeACert(mystate->handle, entry);
04445 
04446     rv = (* mystate->certfunc)(cert, dbkey, mystate->data);
04447 
04448     /* arena stored in entry destroyed by nsslowcert_DestroyCertificate */
04449     nsslowcert_DestroyCertificateNoLocking(cert);
04450 
04451     return(rv);
04452 
04453 loser:
04454     if ( arena ) {
04455        PORT_FreeArena(arena, PR_FALSE);
04456     }
04457     return(SECFailure);
04458 }
04459 
04460 /*
04461  * Traverse all of the certificates in the permanent database and
04462  * call the given function for each one; expect the caller to have lock.
04463  */
04464 static SECStatus
04465 TraversePermCertsNoLocking(NSSLOWCERTCertDBHandle *handle,
04466                         SECStatus (* certfunc)(NSSLOWCERTCertificate *cert,
04467                                             SECItem *k,
04468                                             void *pdata),
04469                         void *udata )
04470 {
04471     SECStatus rv;
04472     PermCertCallbackState mystate;
04473 
04474     mystate.certfunc = certfunc;
04475     mystate.handle = handle;
04476     mystate.data = udata;
04477     rv = nsslowcert_TraverseDBEntries(handle, certDBEntryTypeCert, certcallback,
04478                             (void *)&mystate);
04479     
04480     return(rv);
04481 }
04482 
04483 /*
04484  * Traverse all of the certificates in the permanent database and
04485  * call the given function for each one.
04486  */
04487 SECStatus
04488 nsslowcert_TraversePermCerts(NSSLOWCERTCertDBHandle *handle,
04489                     SECStatus (* certfunc)(NSSLOWCERTCertificate *cert, SECItem *k,
04490                                        void *pdata),
04491                     void *udata )
04492 {
04493     SECStatus rv;
04494 
04495     nsslowcert_LockDB(handle);
04496     rv = TraversePermCertsNoLocking(handle, certfunc, udata);
04497     nsslowcert_UnlockDB(handle);
04498     
04499     return(rv);
04500 }
04501 
04502 
04503 
04504 /*
04505  * Close the database
04506  */
04507 void
04508 nsslowcert_ClosePermCertDB(NSSLOWCERTCertDBHandle *handle)
04509 {
04510     if ( handle ) {
04511        if ( handle->permCertDB ) {
04512            certdb_Close( handle->permCertDB );
04513            handle->permCertDB = NULL;
04514        }
04515        if (handle->dbMon) {
04516            PZ_DestroyMonitor(handle->dbMon);
04517            handle->dbMon = NULL;
04518        }
04519     }
04520     return;
04521 }
04522 
04523 /*
04524  * Get the trust attributes from a certificate
04525  */
04526 SECStatus
04527 nsslowcert_GetCertTrust(NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust)
04528 {
04529     SECStatus rv;
04530     
04531     nsslowcert_LockCertTrust(cert);
04532     
04533     if ( cert->trust == NULL ) {
04534        rv = SECFailure;
04535     } else {
04536        *trust = *cert->trust;
04537        rv = SECSuccess;
04538     }
04539     
04540     nsslowcert_UnlockCertTrust(cert);
04541     return(rv);
04542 }
04543 
04544 /*
04545  * Change the trust attributes of a certificate and make them permanent
04546  * in the database.
04547  */
04548 SECStatus
04549 nsslowcert_ChangeCertTrust(NSSLOWCERTCertDBHandle *handle, 
04550                      NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust)
04551 {
04552     certDBEntryCert *entry;
04553     int rv;
04554     SECStatus ret;
04555     
04556     nsslowcert_LockDB(handle);
04557     nsslowcert_LockCertTrust(cert);
04558     /* only set the trust on permanent certs */
04559     if ( cert->trust == NULL ) {
04560        ret = SECFailure;
04561        goto done;
04562     }
04563 
04564     *cert->trust = *trust;
04565     if ( cert->dbEntry == NULL ) {
04566        ret = SECSuccess; /* not in permanent database */
04567        goto done;
04568     }
04569     
04570     entry = cert->dbEntry;
04571     entry->trust = *trust;
04572     
04573     rv = WriteDBCertEntry(handle, entry);
04574     if ( rv ) {
04575        ret = SECFailure;
04576        goto done;
04577     }
04578 
04579     ret = SECSuccess;
04580     
04581 done:
04582     nsslowcert_UnlockCertTrust(cert);
04583     nsslowcert_UnlockDB(handle);
04584     return(ret);
04585 }
04586 
04587 
04588 static SECStatus
04589 nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
04590     NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust)
04591 {
04592     char *oldnn;
04593     certDBEntryCert *entry;
04594     PRBool conflict;
04595     SECStatus ret;
04596 
04597     PORT_Assert(!cert->dbEntry);
04598 
04599     /* don't add a conflicting nickname */
04600     conflict = nsslowcert_CertNicknameConflict(nickname, &cert->derSubject,
04601                                    dbhandle);
04602     if ( conflict ) {
04603        ret = SECFailure;
04604        goto done;
04605     }
04606     
04607     /* save old nickname so that we can delete it */
04608     oldnn = cert->nickname;
04609 
04610     entry = AddCertToPermDB(dbhandle, cert, nickname, trust);
04611     
04612     if ( entry == NULL ) {
04613        ret = SECFailure;
04614        goto done;
04615     }
04616 
04617     pkcs11_freeNickname(oldnn,cert->nicknameSpace);
04618     
04619     cert->nickname = (entry->nickname) ? pkcs11_copyNickname(entry->nickname,
04620               cert->nicknameSpace, sizeof(cert->nicknameSpace)) : NULL;
04621     cert->trust = &entry->trust;
04622     cert->dbEntry = entry;
04623     
04624     ret = SECSuccess;
04625 done:
04626     return(ret);
04627 }
04628 
04629 SECStatus
04630 nsslowcert_AddPermCert(NSSLOWCERTCertDBHandle *dbhandle,
04631     NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust)
04632 {
04633     SECStatus ret;
04634     SECStatus rv;
04635 
04636     nsslowcert_LockDB(dbhandle);
04637     rv = db_BeginTransaction(dbhandle->permCertDB);
04638     if (rv != SECSuccess) {
04639        nsslowcert_UnlockDB(dbhandle);
04640        return SECFailure;
04641     }
04642 
04643     ret = nsslowcert_UpdatePermCert(dbhandle, cert, nickname, trust);
04644     
04645     db_FinishTransaction(dbhandle->permCertDB, ret != SECSuccess);
04646     nsslowcert_UnlockDB(dbhandle);
04647     return(ret);
04648 }
04649 
04650 /*
04651  * Open the certificate database and index databases.  Create them if
04652  * they are not there or bad.
04653  */
04654 SECStatus
04655 nsslowcert_OpenCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly,
04656                const char *appName, const char *prefix,
04657               NSSLOWCERTDBNameFunc namecb, void *cbarg, PRBool openVolatile)
04658 {
04659     int rv;
04660 
04661     certdb_InitDBLock(handle);
04662     
04663     handle->dbMon = PZ_NewMonitor(nssILockCertDB);
04664     PORT_Assert(handle->dbMon != NULL);
04665     handle->dbVerify = PR_FALSE;
04666 
04667     rv = nsslowcert_OpenPermCertDB(handle, readOnly, appName, prefix, 
04668                                                  namecb, cbarg);
04669     if ( rv ) {
04670        goto loser;
04671     }
04672 
04673     return (SECSuccess);
04674     
04675 loser:
04676 
04677     PORT_SetError(SEC_ERROR_BAD_DATABASE);
04678     return(SECFailure);
04679 }
04680 
04681 PRBool
04682 nsslowcert_needDBVerify(NSSLOWCERTCertDBHandle *handle)
04683 {
04684     if (!handle) return PR_FALSE;
04685     return handle->dbVerify;
04686 }
04687 
04688 void
04689 nsslowcert_setDBVerify(NSSLOWCERTCertDBHandle *handle, PRBool value)
04690 {
04691     handle->dbVerify = value;
04692 }
04693 
04694 
04695 /*
04696  * Lookup a certificate in the databases.
04697  */
04698 static NSSLOWCERTCertificate *
04699 FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey, PRBool lockdb)
04700 {
04701     NSSLOWCERTCertificate *cert = NULL;
04702     certDBEntryCert *entry;
04703     PRBool locked = PR_FALSE;
04704     
04705     if ( lockdb ) {
04706        locked = PR_TRUE;
04707        nsslowcert_LockDB(handle);
04708     }
04709        
04710     /* find in perm database */
04711     entry = ReadDBCertEntry(handle, certKey);
04712        
04713     if ( entry == NULL ) {
04714        goto loser;
04715     }
04716   
04717     /* inherit entry */  
04718     cert = DecodeACert(handle, entry);
04719 
04720 loser:
04721     if (cert == NULL) {
04722        if (entry) {
04723            DestroyDBEntry((certDBEntry *)entry);
04724        }
04725     }
04726 
04727     if ( locked ) {
04728        nsslowcert_UnlockDB(handle);
04729     }
04730     
04731     return(cert);
04732 }
04733 
04734 /*
04735  * Lookup a certificate in the databases.
04736  */
04737 static NSSLOWCERTTrust *
04738 FindTrustByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey, PRBool lockdb)
04739 {
04740     NSSLOWCERTTrust *trust = NULL;
04741     certDBEntryCert *entry;
04742     PRBool locked = PR_FALSE;
04743     
04744     if ( lockdb ) {
04745        locked = PR_TRUE;
04746        nsslowcert_LockDB(handle);
04747     }
04748        
04749     /* find in perm database */
04750     entry = ReadDBCertEntry(handle, certKey);
04751        
04752     if ( entry == NULL ) {
04753        goto loser;
04754     }
04755 
04756     if (!nsslowcert_hasTrust(&entry->trust)) {
04757        goto loser;
04758     }
04759   
04760     /* inherit entry */  
04761     trust = DecodeTrustEntry(handle, entry, certKey);
04762 
04763 loser:
04764     if (trust == NULL) {
04765        if (entry) {
04766            DestroyDBEntry((certDBEntry *)entry);
04767        }
04768     }
04769 
04770     if ( locked ) {
04771        nsslowcert_UnlockDB(handle);
04772     }
04773     
04774     return(trust);
04775 }
04776 
04777 /*
04778  * Lookup a certificate in the databases without locking
04779  */
04780 NSSLOWCERTCertificate *
04781 nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
04782 {
04783     return(FindCertByKey(handle, certKey, PR_FALSE));
04784 }
04785 
04786 /*
04787  * Lookup a trust object in the databases without locking
04788  */
04789 NSSLOWCERTTrust *
04790 nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
04791 {
04792     return(FindTrustByKey(handle, certKey, PR_FALSE));
04793 }
04794 
04795 /*
04796  * Generate a key from an issuerAndSerialNumber, and find the
04797  * associated cert in the database.
04798  */
04799 NSSLOWCERTCertificate *
04800 nsslowcert_FindCertByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTIssuerAndSN *issuerAndSN)
04801 {
04802     SECItem certKey;
04803     SECItem *sn = &issuerAndSN->serialNumber;
04804     SECItem *issuer = &issuerAndSN->derIssuer;
04805     NSSLOWCERTCertificate *cert;
04806     int data_left = sn->len-1;
04807     int data_len = sn->len;
04808     int index = 0;
04809 
04810     /* automatically detect DER encoded serial numbers and remove the der
04811      * encoding since the database expects unencoded data. 
04812      * if it's DER encoded, there must be at least 3 bytes, tag, len, data */
04813     if ((sn->len >= 3) && (sn->data[0] == 0x2)) {
04814        /* remove the der encoding of the serial number before generating the
04815         * key.. */
04816        data_left = sn->len-2;
04817        data_len = sn->data[1];
04818        index = 2;
04819 
04820        /* extended length ? (not very likely for a serial number) */
04821        if (data_len & 0x80) {
04822            int len_count = data_len & 0x7f;
04823 
04824            data_len = 0;
04825            data_left -= len_count;
04826            if (data_left > 0) {
04827               while (len_count --) {
04828                   data_len = (data_len << 8) | sn->data[index++];
04829               }
04830            } 
04831        }
04832        /* XXX leaving any leading zeros on the serial number for backwards
04833         * compatibility
04834         */
04835        /* not a valid der, must be just an unlucky serial number value */
04836        if (data_len != data_left) {
04837            data_len = sn->len;
04838            index = 0;
04839        }
04840     }
04841 
04842     certKey.type = 0;
04843     certKey.data = (unsigned char*)PORT_Alloc(sn->len + issuer->len);
04844     certKey.len = data_len + issuer->len;
04845     
04846     if ( certKey.data == NULL ) {
04847        return(0);
04848     }
04849 
04850     /* first try the serial number as hand-decoded above*/
04851     /* copy the serialNumber */
04852     PORT_Memcpy(certKey.data, &sn->data[index], data_len);
04853 
04854     /* copy the issuer */
04855     PORT_Memcpy( &certKey.data[data_len],issuer->data,issuer->len);
04856 
04857     cert = nsslowcert_FindCertByKey(handle, &certKey);
04858     if (cert) {
04859        PORT_Free(certKey.data);
04860        return (cert);
04861     }
04862 
04863     /* didn't find it, try by der encoded serial number */
04864     /* copy the serialNumber */
04865     PORT_Memcpy(certKey.data, sn->data, sn->len);
04866 
04867     /* copy the issuer */
04868     PORT_Memcpy( &certKey.data[sn->len], issuer->data, issuer->len);
04869     certKey.len = sn->len + issuer->len;
04870 
04871     cert = nsslowcert_FindCertByKey(handle, &certKey);
04872     
04873     PORT_Free(certKey.data);
04874     
04875     return(cert);
04876 }
04877 
04878 /*
04879  * Generate a key from an issuerAndSerialNumber, and find the
04880  * associated cert in the database.
04881  */
04882 NSSLOWCERTTrust *
04883 nsslowcert_FindTrustByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, 
04884                                    NSSLOWCERTIssuerAndSN *issuerAndSN)
04885 {
04886     SECItem certKey;
04887     SECItem *sn = &issuerAndSN->serialNumber;
04888     SECItem *issuer = &issuerAndSN->derIssuer;
04889     NSSLOWCERTTrust *trust;
04890     unsigned char keyBuf[512];
04891     int data_left = sn->len-1;
04892     int data_len = sn->len;
04893     int index = 0;
04894     int len;
04895 
04896     /* automatically detect DER encoded serial numbers and remove the der
04897      * encoding since the database expects unencoded data. 
04898      * if it's DER encoded, there must be at least 3 bytes, tag, len, data */
04899     if ((sn->len >= 3) && (sn->data[0] == 0x2)) {
04900        /* remove the der encoding of the serial number before generating the
04901         * key.. */
04902        data_left = sn->len-2;
04903        data_len = sn->data[1];
04904        index = 2;
04905 
04906        /* extended length ? (not very likely for a serial number) */
04907        if (data_len & 0x80) {
04908            int len_count = data_len & 0x7f;
04909 
04910            data_len = 0;
04911            data_left -= len_count;
04912            if (data_left > 0) {
04913               while (len_count --) {
04914                   data_len = (data_len << 8) | sn->data[index++];
04915               }
04916            } 
04917        }
04918        /* XXX leaving any leading zeros on the serial number for backwards
04919         * compatibility
04920         */
04921        /* not a valid der, must be just an unlucky serial number value */
04922        if (data_len != data_left) {
04923            data_len = sn->len;
04924            index = 0;
04925        }
04926     }
04927 
04928     certKey.type = 0;
04929     certKey.len = data_len + issuer->len;
04930     len = sn->len + issuer->len;
04931     if (len > sizeof (keyBuf)) {
04932        certKey.data = (unsigned char*)PORT_Alloc(len);
04933     } else {
04934        certKey.data = keyBuf;
04935     }
04936     
04937     if ( certKey.data == NULL ) {
04938        return(0);
04939     }
04940 
04941     /* first try the serial number as hand-decoded above*/
04942     /* copy the serialNumber */
04943     PORT_Memcpy(certKey.data, &sn->data[index], data_len);
04944 
04945     /* copy the issuer */
04946     PORT_Memcpy( &certKey.data[data_len],issuer->data,issuer->len);
04947 
04948     trust = nsslowcert_FindTrustByKey(handle, &certKey);
04949     if (trust) {
04950        pkcs11_freeStaticData(certKey.data, keyBuf);
04951        return (trust);
04952     }
04953 
04954     if (index == 0) {
04955        pkcs11_freeStaticData(certKey.data, keyBuf);
04956        return NULL;
04957     }
04958 
04959     /* didn't find it, try by der encoded serial number */
04960     /* copy the serialNumber */
04961     PORT_Memcpy(certKey.data, sn->data, sn->len);
04962 
04963     /* copy the issuer */
04964     PORT_Memcpy( &certKey.data[sn->len], issuer->data, issuer->len);
04965     certKey.len = sn->len + issuer->len;
04966 
04967     trust = nsslowcert_FindTrustByKey(handle, &certKey);
04968     
04969     pkcs11_freeStaticData(certKey.data, keyBuf);
04970     
04971     return(trust);
04972 }
04973 
04974 /*
04975  * look for the given DER certificate in the database
04976  */
04977 NSSLOWCERTCertificate *
04978 nsslowcert_FindCertByDERCert(NSSLOWCERTCertDBHandle *handle, SECItem *derCert)
04979 {
04980     PRArenaPool *arena;
04981     SECItem certKey;
04982     SECStatus rv;
04983     NSSLOWCERTCertificate *cert = NULL;
04984     
04985     /* create a scratch arena */
04986     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
04987     if ( arena == NULL ) {
04988        return(NULL);
04989     }
04990     
04991     /* extract the database key from the cert */
04992     rv = nsslowcert_KeyFromDERCert(arena, derCert, &certKey);
04993     if ( rv != SECSuccess ) {
04994        goto loser;
04995     }
04996 
04997     /* find the certificate */
04998     cert = nsslowcert_FindCertByKey(handle, &certKey);
04999     
05000 loser:
05001     PORT_FreeArena(arena, PR_FALSE);
05002     return(cert);
05003 }
05004 
05005 static void
05006 DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb)
05007 {
05008     int refCount;
05009     NSSLOWCERTCertDBHandle *handle;
05010     
05011     if ( cert ) {
05012 
05013        handle = cert->dbhandle;
05014 
05015        /*
05016         * handle may be NULL, for example if the cert was created with
05017         * nsslowcert_DecodeDERCertificate.
05018         */
05019        if ( lockdb && handle ) {
05020            nsslowcert_LockDB(handle);
05021            /* keep a reference until we unlock, so handle won't disappear
05022             * before we are through with it */
05023            nsslowcert_reference(handle);
05024        }
05025 
05026         nsslowcert_LockCertRefCount(cert);
05027        PORT_Assert(cert->referenceCount > 0);
05028        refCount = --cert->referenceCount;
05029         nsslowcert_UnlockCertRefCount(cert);
05030 
05031        if ( ( refCount == 0 ) ) {
05032            certDBEntryCert *entry  = cert->dbEntry;
05033 
05034            if ( entry ) {
05035               DestroyDBEntry((certDBEntry *)entry);
05036             }
05037 
05038            pkcs11_freeNickname(cert->nickname,cert->nicknameSpace);
05039            pkcs11_freeStaticData(cert->certKey.data,cert->certKeySpace);
05040            cert->certKey.data = NULL;
05041            cert->nickname = NULL;
05042 
05043            /* zero cert before freeing. Any stale references to this cert
05044             * after this point will probably cause an exception.  */
05045            PORT_Memset(cert, 0, sizeof *cert);
05046 
05047            /* use reflock to protect the free list */
05048            nsslowcert_LockFreeList();
05049            if (certListCount > MAX_CERT_LIST_COUNT) {
05050               PORT_Free(cert);
05051            } else {
05052               certListCount++;
05053               cert->next = certListHead;
05054               certListHead = cert;
05055            }
05056            nsslowcert_UnlockFreeList();
05057            if (handle) {
05058                sftk_freeCertDB(handle);
05059            }
05060               
05061            cert = NULL;
05062         }
05063        if ( lockdb && handle ) {
05064            nsslowcert_UnlockDB(handle);
05065            sftk_freeCertDB(handle);
05066        }
05067     }
05068 
05069     return;
05070 }
05071 
05072 NSSLOWCERTCertificate *
05073 nsslowcert_CreateCert(void)
05074 {
05075     NSSLOWCERTCertificate *cert;
05076     nsslowcert_LockFreeList();
05077     cert = certListHead;
05078     if (cert) {
05079        certListHead = cert->next;
05080        certListCount--;
05081     }
05082     PORT_Assert(certListCount >= 0);
05083     nsslowcert_UnlockFreeList();
05084     if (cert) {
05085        return cert;
05086     }
05087     return PORT_ZNew(NSSLOWCERTCertificate);
05088 }
05089 
05090 static void
05091 DestroyCertFreeList(void)
05092 {
05093     NSSLOWCERTCertificate *cert;
05094 
05095     nsslowcert_LockFreeList();
05096     while (NULL != (cert = certListHead)) {
05097        certListCount--;
05098        certListHead = cert->next;
05099        PORT_Free(cert);
05100     }
05101     PORT_Assert(!certListCount);
05102     certListCount = 0;
05103     nsslowcert_UnlockFreeList();
05104 }
05105 
05106 void
05107 nsslowcert_DestroyTrust(NSSLOWCERTTrust *trust)
05108 {
05109     certDBEntryCert *entry  = trust->dbEntry;
05110 
05111     if ( entry ) {
05112        DestroyDBEntry((certDBEntry *)entry);
05113     }
05114     if (trust->dbhandle) {
05115        sftk_freeCertDB(trust->dbhandle);
05116     }
05117     pkcs11_freeStaticData(trust->dbKey.data,trust->dbKeySpace);
05118     PORT_Memset(trust, 0, sizeof(*trust));
05119 
05120     nsslowcert_LockFreeList();
05121     if (trustListCount > MAX_TRUST_LIST_COUNT) {
05122        PORT_Free(trust);
05123     } else {
05124        trustListCount++;
05125        trust->next = trustListHead;
05126        trustListHead = trust;
05127     }
05128     nsslowcert_UnlockFreeList();
05129 
05130     return;
05131 }
05132 
05133 void
05134 nsslowcert_DestroyCertificate(NSSLOWCERTCertificate *cert)
05135 {
05136     DestroyCertificate(cert, PR_TRUE);
05137     return;
05138 }
05139 
05140 static void
05141 nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert)
05142 {
05143     DestroyCertificate(cert, PR_FALSE);
05144     return;
05145 }
05146 
05147 /*
05148  * Lookup a CRL in the databases. We mirror the same fast caching data base
05149  *  caching stuff used by certificates....?
05150  */
05151 certDBEntryRevocation *
05152 nsslowcert_FindCrlByKey(NSSLOWCERTCertDBHandle *handle, 
05153                                           SECItem *crlKey, PRBool isKRL)
05154 {
05155     SECItem keyitem;
05156     DBT key;
05157     SECStatus rv;
05158     PRArenaPool *arena = NULL;
05159     certDBEntryRevocation *entry = NULL;
05160     certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation  
05161                                    : certDBEntryTypeRevocation;
05162     
05163     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
05164     if ( arena == NULL ) {
05165        goto loser;
05166     }
05167     
05168     rv = EncodeDBGenericKey(crlKey, arena, &keyitem, crlType);
05169     if ( rv != SECSuccess ) {
05170        goto loser;
05171     }
05172     
05173     key.data = keyitem.data;
05174     key.size = keyitem.len;
05175 
05176     /* find in perm database */
05177     entry = ReadDBCrlEntry(handle, crlKey, crlType);
05178        
05179     if ( entry == NULL ) {
05180        goto loser;
05181     }
05182 
05183 loser:
05184     if ( arena ) {
05185        PORT_FreeArena(arena, PR_FALSE);
05186     }
05187     
05188     return entry;
05189 }
05190 
05191 /*
05192  * replace the existing URL in the data base with a new one
05193  */
05194 static SECStatus
05195 nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 
05196                      SECItem *crlKey, char *url, PRBool isKRL)
05197 {
05198     SECStatus rv = SECFailure;
05199     certDBEntryRevocation *entry = NULL;
05200     certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation  
05201                                    : certDBEntryTypeRevocation;
05202     DeleteDBCrlEntry(handle, crlKey, crlType);
05203 
05204     /* Write the new entry into the data base */
05205     entry = NewDBCrlEntry(derCrl, url, crlType, 0);
05206     if (entry == NULL) goto done;
05207 
05208     rv = WriteDBCrlEntry(handle, entry, crlKey);
05209     if (rv != SECSuccess) goto done;
05210 
05211 done:
05212     if (entry) {
05213        DestroyDBEntry((certDBEntry *)entry);
05214     }
05215     return rv;
05216 }
05217 
05218 SECStatus
05219 nsslowcert_AddCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 
05220                      SECItem *crlKey, char *url, PRBool isKRL)
05221 {
05222     SECStatus rv;
05223 
05224     rv = db_BeginTransaction(handle->permCertDB);
05225     if (rv != SECSuccess) {
05226        return SECFailure;
05227     }
05228     rv = nsslowcert_UpdateCrl(handle, derCrl, crlKey, url, isKRL);
05229 
05230     db_FinishTransaction(handle->permCertDB, rv != SECSuccess);
05231     return rv;
05232 }
05233 
05234 SECStatus
05235 nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle, SECItem *derName,
05236                                                          PRBool isKRL)
05237 {
05238     SECStatus rv;
05239     certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation  
05240                                    : certDBEntryTypeRevocation;
05241     rv = db_BeginTransaction(handle->permCertDB);
05242     if (rv != SECSuccess) {
05243        return SECFailure;
05244     }
05245     
05246     rv = DeleteDBCrlEntry(handle, derName, crlType);
05247     if (rv != SECSuccess) goto done;
05248   
05249 done:
05250     db_FinishTransaction(handle->permCertDB, rv != SECSuccess);
05251     return rv;
05252 }
05253 
05254 
05255 PRBool
05256 nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust)
05257 {
05258     if (trust == NULL) {
05259        return PR_FALSE;
05260     }
05261     return !((trust->sslFlags & CERTDB_TRUSTED_UNKNOWN) && 
05262               (trust->emailFlags & CERTDB_TRUSTED_UNKNOWN) && 
05263                      (trust->objectSigningFlags & CERTDB_TRUSTED_UNKNOWN));
05264 }
05265 
05266 /*
05267  * This function has the logic that decides if another person's cert and
05268  * email profile from an S/MIME message should be saved.  It can deal with
05269  * the case when there is no profile.
05270  */
05271 static SECStatus
05272 nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, 
05273        char *emailAddr, SECItem *derSubject, SECItem *emailProfile, 
05274                                                  SECItem *profileTime)
05275 {
05276     certDBEntrySMime *entry = NULL;
05277     SECStatus rv = SECFailure;;
05278 
05279 
05280     /* find our existing entry */
05281     entry = nsslowcert_ReadDBSMimeEntry(dbhandle, emailAddr);
05282 
05283     if ( entry ) {
05284        /* keep our old db entry consistant for old applications. */
05285        if (!SECITEM_ItemsAreEqual(derSubject, &entry->subjectName)) {
05286            nsslowcert_UpdateSubjectEmailAddr(dbhandle, &entry->subjectName, 
05287                             emailAddr, nsslowcert_remove);
05288        } 
05289        DestroyDBEntry((certDBEntry *)entry);
05290        entry = NULL;
05291     }
05292 
05293     /* now save the entry */
05294     entry = NewDBSMimeEntry(emailAddr, derSubject, emailProfile,
05295                             profileTime, 0);
05296     if ( entry == NULL ) {
05297        rv = SECFailure;
05298        goto loser;
05299     }
05300 
05301     nsslowcert_LockDB(dbhandle);
05302 
05303     rv = DeleteDBSMimeEntry(dbhandle, emailAddr);
05304     /* if delete fails, try to write new entry anyway... */
05305 
05306     /* link subject entry back here */
05307     rv = nsslowcert_UpdateSubjectEmailAddr(dbhandle, derSubject, emailAddr,
05308                                    nsslowcert_add);
05309     if ( rv != SECSuccess ) {
05310            nsslowcert_UnlockDB(dbhandle);
05311            goto loser;
05312     }
05313        
05314     rv = WriteDBSMimeEntry(dbhandle, entry);
05315     if ( rv != SECSuccess ) {
05316            nsslowcert_UnlockDB(dbhandle);
05317            goto loser;
05318     }
05319 
05320     nsslowcert_UnlockDB(dbhandle);
05321 
05322     rv = SECSuccess;
05323     
05324 loser:
05325     if ( entry ) {
05326        DestroyDBEntry((certDBEntry *)entry);
05327     }
05328     return(rv);
05329 }
05330 
05331 SECStatus
05332 nsslowcert_SaveSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, char *emailAddr, 
05333        SECItem *derSubject, SECItem *emailProfile, SECItem *profileTime)
05334 {
05335     SECStatus rv = SECFailure;;
05336 
05337     rv = db_BeginTransaction(dbhandle->permCertDB);
05338     if (rv != SECSuccess) {
05339        return SECFailure;
05340     }
05341 
05342     rv = nsslowcert_UpdateSMimeProfile(dbhandle, emailAddr, 
05343         derSubject, emailProfile, profileTime);
05344     
05345     db_FinishTransaction(dbhandle->permCertDB, rv != SECSuccess);
05346     return(rv);
05347 }
05348 
05349 void
05350 nsslowcert_DestroyFreeLists(void)
05351 {
05352     DestroyCertEntryFreeList();
05353     DestroyTrustFreeList();
05354     DestroyCertFreeList();
05355     PZ_DestroyLock(freeListLock);
05356     freeListLock = NULL;
05357 }
05358 
05359 void
05360 nsslowcert_DestroyGlobalLocks(void)
05361 {
05362     if (dbLock) {
05363        PZ_DestroyLock(dbLock);
05364        dbLock = NULL;
05365     }
05366     if (certRefCountLock) {
05367        PZ_DestroyLock(certRefCountLock);
05368        certRefCountLock = NULL;
05369     }
05370     if (certTrustLock) {
05371        PZ_DestroyLock(certTrustLock);
05372        certTrustLock = NULL;
05373     }
05374 }
05375 
05376 certDBEntry *
05377 nsslowcert_DecodeAnyDBEntry(SECItem *dbData, SECItem *dbKey, 
05378                  certDBEntryType entryType, void *pdata)
05379 {
05380     PLArenaPool *arena = NULL;
05381     certDBEntry *entry;
05382     SECStatus rv;
05383     SECItem dbEntry;
05384 
05385 
05386     if ((dbData->len < SEC_DB_ENTRY_HEADER_LEN) || (dbKey->len == 0)) {
05387        PORT_SetError(SEC_ERROR_INVALID_ARGS);
05388        goto loser;
05389     }
05390     dbEntry.data = &dbData->data[SEC_DB_ENTRY_HEADER_LEN];
05391     dbEntry.len  = dbData->len - SEC_DB_ENTRY_HEADER_LEN;
05392 
05393     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
05394     if (arena == NULL) {
05395        goto loser;
05396     }
05397     entry = PORT_ArenaZNew(arena, certDBEntry);
05398     if (!entry)
05399        goto loser;
05400 
05401     entry->common.version = (unsigned int)dbData->data[0];
05402     entry->common.flags   = (unsigned int)dbData->data[2];
05403     entry->common.type    = entryType;
05404     entry->common.arena   = arena;
05405 
05406     switch (entryType) {
05407     case certDBEntryTypeContentVersion: /* This type appears to be unused */
05408     case certDBEntryTypeVersion:        /* This type has only the common hdr */
05409        rv = SECSuccess;
05410        break;
05411 
05412     case certDBEntryTypeSubject:
05413        rv = DecodeDBSubjectEntry(&entry->subject, &dbEntry, dbKey);
05414        break;
05415 
05416     case certDBEntryTypeNickname:
05417        rv = DecodeDBNicknameEntry(&entry->nickname, &dbEntry,
05418                                    (char *)dbKey->data);
05419        break;
05420 
05421     /* smime profiles need entries created after the certs have
05422      * been imported, loop over them in a second run */
05423     case certDBEntryTypeSMimeProfile:
05424        rv = DecodeDBSMimeEntry(&entry->smime, &dbEntry, (char *)dbKey->data);
05425        break;
05426 
05427     case certDBEntryTypeCert:
05428        rv = DecodeDBCertEntry(&entry->cert, &dbEntry);
05429        break;
05430 
05431     case certDBEntryTypeKeyRevocation:
05432     case certDBEntryTypeRevocation:
05433        rv = DecodeDBCrlEntry(&entry->revocation, &dbEntry);
05434        break;
05435 
05436     default:
05437        PORT_SetError(SEC_ERROR_INVALID_ARGS);
05438        rv = SECFailure;
05439     }
05440 
05441     if (rv == SECSuccess)
05442        return entry;
05443 
05444 loser:
05445     if (arena)
05446        PORT_FreeArena(arena, PR_FALSE);
05447     return NULL;
05448 }
05449