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