pcertdb.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:171k
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- /*
- * Permanent Certificate database handling code
- *
- * $Id: pcertdb.c,v 1.4 2000/10/02 23:23:50 wtc%netscape.com Exp $
- */
- #include "prtime.h"
- #include "cert.h"
- #include "mcom_db.h"
- #include "certdb.h"
- #include "secitem.h"
- #include "secder.h"
- /* Call to PK11_FreeSlot below */
- #include "secasn1.h"
- #include "secerr.h"
- #include "prlock.h"
- #include "prmon.h"
- #include "nsslocks.h"
- #include "base64.h"
- #include "sechash.h"
- #include "plhash.h"
- #include "cdbhdl.h"
- /*
- * the following functions are wrappers for the db library that implement
- * a global lock to make the database thread safe.
- */
- static PRLock *dbLock = NULL;
- void
- certdb_InitDBLock(void)
- {
- if (dbLock == NULL) {
- nss_InitLock(&dbLock);
- PORT_Assert(dbLock != NULL);
- }
- return;
- }
- static int
- certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
-
- PORT_Assert(dbLock != NULL);
- PR_Lock(dbLock);
-
- ret = (* db->get)(db, key, data, flags);
- prstat = PR_Unlock(dbLock);
- return(ret);
- }
- static int
- certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
- PORT_Assert(dbLock != NULL);
- PR_Lock(dbLock);
- ret = (* db->put)(db, key, data, flags);
-
- prstat = PR_Unlock(dbLock);
- return(ret);
- }
- static int
- certdb_Sync(DB *db, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
- PORT_Assert(dbLock != NULL);
- PR_Lock(dbLock);
- ret = (* db->sync)(db, flags);
-
- prstat = PR_Unlock(dbLock);
- return(ret);
- }
- static int
- certdb_Del(DB *db, DBT *key, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
- PORT_Assert(dbLock != NULL);
- PR_Lock(dbLock);
- ret = (* db->del)(db, key, flags);
-
- prstat = PR_Unlock(dbLock);
- return(ret);
- }
- static int
- certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
-
- PORT_Assert(dbLock != NULL);
- PR_Lock(dbLock);
-
- ret = (* db->seq)(db, key, data, flags);
- prstat = PR_Unlock(dbLock);
- return(ret);
- }
- static void
- certdb_Close(DB *db)
- {
- PRStatus prstat;
- PORT_Assert(dbLock != NULL);
- PR_Lock(dbLock);
- (* db->close)(db);
-
- prstat = PR_Unlock(dbLock);
- return;
- }
- /* forward references */
- static void CERT_DestroyCertificateNoLocking(CERTCertificate *cert);
- static SECStatus AddCertToSPKDigestTable(CERTCertDBHandle *handle,
- CERTCertificate *cert);
- static SECStatus RemoveCertFromSPKDigestTable(CERTCertDBHandle *handle,
- CERTCertificate *cert);
- static SECStatus
- DeleteDBEntry(CERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey)
- {
- DBT key;
- int ret;
- /* init the database key */
- key.data = dbkey->data;
- key.size = dbkey->len;
-
- dbkey->data[0] = (unsigned char)type;
- /* delete entry from database */
- ret = certdb_Del(handle->permCertDB, &key, 0 );
- if ( ret != 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- ret = certdb_Sync(handle->permCertDB, 0);
- if ( ret ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- return(SECSuccess);
-
- loser:
- return(SECFailure);
- }
- static SECStatus
- ReadDBEntry(CERTCertDBHandle *handle, certDBEntryCommon *entry,
- SECItem *dbkey, SECItem *dbentry, PRArenaPool *arena)
- {
- DBT data, key;
- int ret;
- unsigned char *buf;
-
- /* init the database key */
- key.data = dbkey->data;
- key.size = dbkey->len;
-
- dbkey->data[0] = (unsigned char)entry->type;
- /* read entry from database */
- ret = certdb_Get(handle->permCertDB, &key, &data, 0 );
- if ( ret != 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* validate the entry */
- if ( data.size < SEC_DB_ENTRY_HEADER_LEN ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- buf = (unsigned char *)data.data;
- if ( buf[0] != (unsigned char)CERT_DB_FILE_VERSION ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- if ( buf[1] != (unsigned char)entry->type ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- /* copy out header information */
- entry->version = (unsigned int)buf[0];
- entry->type = (certDBEntryType)buf[1];
- entry->flags = (unsigned int)buf[2];
-
- /* format body of entry for return to caller */
- dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN;
- if ( dbentry->len ) {
- dbentry->data = (unsigned char *)PORT_ArenaAlloc(arena, dbentry->len);
- if ( dbentry->data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- PORT_Memcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN],
- dbentry->len);
- } else {
- dbentry->data = NULL;
- }
-
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /**
- ** Implement low level database access
- **/
- static SECStatus
- WriteDBEntry(CERTCertDBHandle *handle, certDBEntryCommon *entry,
- SECItem *dbkey, SECItem *dbentry)
- {
- int ret;
- DBT data, key;
- unsigned char *buf;
-
- data.data = dbentry->data;
- data.size = dbentry->len;
-
- buf = (unsigned char*)data.data;
-
- buf[0] = (unsigned char)entry->version;
- buf[1] = (unsigned char)entry->type;
- buf[2] = (unsigned char)entry->flags;
-
- key.data = dbkey->data;
- key.size = dbkey->len;
-
- dbkey->data[0] = (unsigned char)entry->type;
- /* put the record into the database now */
- ret = certdb_Put(handle->permCertDB, &key, &data, 0);
- if ( ret != 0 ) {
- goto loser;
- }
- ret = certdb_Sync( handle->permCertDB, 0 );
-
- if ( ret ) {
- goto loser;
- }
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * encode a database cert record
- */
- static SECStatus
- EncodeDBCertEntry(certDBEntryCert *entry, PRArenaPool *arena, SECItem *dbitem)
- {
- unsigned int nnlen;
- unsigned char *buf;
- char *nn;
- char zbuf = 0;
-
- if ( entry->nickname ) {
- nn = entry->nickname;
- } else {
- nn = &zbuf;
- }
- nnlen = PORT_Strlen(nn) + 1;
-
- /* allocate space for encoded database record, including space
- * for low level header
- */
- dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN +
- SEC_DB_ENTRY_HEADER_LEN;
-
- dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
- if ( dbitem->data == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- /* fill in database record */
- buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
-
- buf[0] = ( entry->trust.sslFlags >> 8 ) & 0xff;
- buf[1] = entry->trust.sslFlags & 0xff;
- buf[2] = ( entry->trust.emailFlags >> 8 ) & 0xff;
- buf[3] = entry->trust.emailFlags & 0xff;
- buf[4] = ( entry->trust.objectSigningFlags >> 8 ) & 0xff;
- buf[5] = entry->trust.objectSigningFlags & 0xff;
- buf[6] = ( entry->derCert.len >> 8 ) & 0xff;
- buf[7] = entry->derCert.len & 0xff;
- buf[8] = ( nnlen >> 8 ) & 0xff;
- buf[9] = nnlen & 0xff;
-
- PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data,
- entry->derCert.len);
- PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN + entry->derCert.len],
- nn, nnlen);
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * encode a database key for a cert record
- */
- static SECStatus
- EncodeDBCertKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey)
- {
- dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN;
- dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
- if ( dbkey->data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
- certKey->data, certKey->len);
- dbkey->data[0] = certDBEntryTypeCert;
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- static SECStatus
- EncodeDBGenericKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey,
- certDBEntryType entryType)
- {
- /*
- * we only allow _one_ KRL key!
- */
- if (entryType == certDBEntryTypeKeyRevocation) {
- dbkey->len = SEC_DB_KEY_HEADER_LEN;
- dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
- if ( dbkey->data == NULL ) {
- goto loser;
- }
- dbkey->data[0] = (unsigned char) entryType;
- return(SECSuccess);
- }
-
- dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN;
- dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
- if ( dbkey->data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
- certKey->data, certKey->len);
- dbkey->data[0] = (unsigned char) entryType;
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- static SECStatus
- DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry)
- {
- unsigned int nnlen;
- int headerlen;
- int lenoff;
- /* allow updates of old versions of the database */
- switch ( entry->common.version ) {
- case 5:
- headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
- lenoff = 3;
- break;
- case 6:
- /* should not get here */
- PORT_Assert(0);
- headerlen = DB_CERT_V6_ENTRY_HEADER_LEN;
- lenoff = 3;
- break;
- case 7:
- headerlen = DB_CERT_ENTRY_HEADER_LEN;
- lenoff = 6;
- break;
- default:
- /* better not get here */
- PORT_Assert(0);
- headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
- lenoff = 3;
- break;
- }
-
- /* is record long enough for header? */
- if ( dbentry->len < headerlen ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* is database entry correct length? */
- entry->derCert.len = ( ( dbentry->data[lenoff] << 8 ) |
- dbentry->data[lenoff+1] );
- nnlen = ( ( dbentry->data[lenoff+2] << 8 ) | dbentry->data[lenoff+3] );
- if ( ( entry->derCert.len + nnlen + headerlen )
- != dbentry->len) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* copy the dercert */
- entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
- entry->derCert.len);
- if ( entry->derCert.data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->derCert.data, &dbentry->data[headerlen],
- entry->derCert.len);
- /* copy the nickname */
- if ( nnlen > 1 ) {
- entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena, nnlen);
- if ( entry->nickname == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->nickname,
- &dbentry->data[headerlen +
- entry->derCert.len],
- nnlen);
- } else {
- entry->nickname = NULL;
- }
-
- if ( entry->common.version < 7 ) {
- /* allow updates of v5 db */
- entry->trust.sslFlags = dbentry->data[0];
- entry->trust.emailFlags = dbentry->data[1];
- entry->trust.objectSigningFlags = dbentry->data[2];
- } else {
- entry->trust.sslFlags = ( dbentry->data[0] << 8 ) | dbentry->data[1];
- entry->trust.emailFlags = ( dbentry->data[2] << 8 ) | dbentry->data[3];
- entry->trust.objectSigningFlags =
- ( dbentry->data[4] << 8 ) | dbentry->data[5];
- }
-
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * Create a new certDBEntryCert from existing data
- */
- static certDBEntryCert *
- NewDBCertEntry(SECItem *derCert, char *nickname,
- CERTCertTrust *trust, int flags)
- {
- certDBEntryCert *entry;
- PRArenaPool *arena = NULL;
- int nnlen;
-
- arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
- if ( !arena ) {
- goto loser;
- }
-
- entry = (certDBEntryCert *)PORT_ArenaZAlloc(arena, sizeof(certDBEntryCert));
- if ( entry == NULL ) {
- goto loser;
- }
-
- /* fill in the dbCert */
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeCert;
- entry->common.version = CERT_DB_FILE_VERSION;
- entry->common.flags = flags;
-
- if ( trust ) {
- entry->trust = *trust;
- }
- entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, derCert->len);
- if ( !entry->derCert.data ) {
- goto loser;
- }
- entry->derCert.len = derCert->len;
- PORT_Memcpy(entry->derCert.data, derCert->data, derCert->len);
-
- nnlen = ( nickname ? strlen(nickname) + 1 : 0 );
-
- if ( nnlen ) {
- entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
- if ( !entry->nickname ) {
- goto loser;
- }
- PORT_Memcpy(entry->nickname, nickname, nnlen);
-
- } else {
- entry->nickname = 0;
- }
- return(entry);
- loser:
-
- /* allocation error, free arena and return */
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return(0);
- }
- /*
- * Decode a version 4 DBCert from the byte stream database format
- * and construct a current database entry struct
- */
- static certDBEntryCert *
- DecodeV4DBCertEntry(unsigned char *buf, int len)
- {
- certDBEntryCert *entry;
- int certlen;
- int nnlen;
- PRArenaPool *arena;
-
- /* make sure length is at least long enough for the header */
- if ( len < DBCERT_V4_HEADER_LEN ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- return(0);
- }
- /* get other lengths */
- certlen = buf[3] << 8 | buf[4];
- nnlen = buf[5] << 8 | buf[6];
-
- /* make sure DB entry is the right size */
- if ( ( certlen + nnlen + DBCERT_V4_HEADER_LEN ) != len ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- return(0);
- }
- /* allocate arena */
- arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
- if ( !arena ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return(0);
- }
-
- /* allocate structure and members */
- entry = (certDBEntryCert *) PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
- if ( !entry ) {
- goto loser;
- }
- entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen);
- if ( !entry->derCert.data ) {
- goto loser;
- }
- entry->derCert.len = certlen;
-
- if ( nnlen ) {
- entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen);
- if ( !entry->nickname ) {
- goto loser;
- }
- } else {
- entry->nickname = 0;
- }
- entry->common.arena = arena;
- entry->common.version = CERT_DB_FILE_VERSION;
- entry->common.type = certDBEntryTypeCert;
- entry->common.flags = 0;
- entry->trust.sslFlags = buf[0];
- entry->trust.emailFlags = buf[1];
- entry->trust.objectSigningFlags = buf[2];
- PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen);
- PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen);
- return(entry);
-
- loser:
- PORT_FreeArena(arena, PR_FALSE);
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return(0);
- }
- /*
- * Encode a Certificate database entry into byte stream suitable for
- * the database
- */
- static SECStatus
- WriteDBCertEntry(CERTCertDBHandle *handle, certDBEntryCert *entry)
- {
- SECItem dbitem, dbkey;
- PRArenaPool *tmparena = NULL;
- SECItem tmpitem;
- SECStatus rv;
-
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- goto loser;
- }
-
- rv = EncodeDBCertEntry(entry, tmparena, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* get the database key and format it */
- rv = CERT_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem);
- if ( rv == SECFailure ) {
- goto loser;
- }
- rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey);
- if ( rv == SECFailure ) {
- goto loser;
- }
-
- /* now write it to the database */
- rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- return(SECFailure);
- }
- /*
- * delete a certificate entry
- */
- static SECStatus
- DeleteDBCertEntry(CERTCertDBHandle *handle, SECItem *certKey)
- {
- SECItem dbkey;
- PRArenaPool *arena = NULL;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- rv = EncodeDBCertKey(certKey, arena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey);
- if ( rv == SECFailure ) {
- goto loser;
- }
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(SECFailure);
- }
- /*
- * Read a certificate entry
- */
- static certDBEntryCert *
- ReadDBCertEntry(CERTCertDBHandle *handle, SECItem *certKey)
- {
- PRArenaPool *arena = NULL;
- PRArenaPool *tmparena = NULL;
- certDBEntryCert *entry;
- SECItem dbkey;
- SECItem dbentry;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- entry = (certDBEntryCert *)PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeCert;
- rv = EncodeDBCertKey(certKey, tmparena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
- if ( rv == SECFailure ) {
- goto loser;
- }
- rv = DecodeDBCertEntry(entry, &dbentry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(entry);
-
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * encode a database cert record
- */
- static SECStatus
- EncodeDBCrlEntry(certDBEntryRevocation *entry, PRArenaPool *arena, SECItem *dbitem)
- {
- unsigned int nnlen = 0;
- unsigned char *buf;
-
- if (entry->url) {
- nnlen = PORT_Strlen(entry->url) + 1;
- }
-
- /* allocate space for encoded database record, including space
- * for low level header
- */
- dbitem->len = entry->derCrl.len + nnlen
- + SEC_DB_ENTRY_HEADER_LEN + DB_CRL_ENTRY_HEADER_LEN;
-
- dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
- if ( dbitem->data == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- /* fill in database record */
- buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
-
- buf[0] = ( entry->derCrl.len >> 8 ) & 0xff;
- buf[1] = entry->derCrl.len & 0xff;
- buf[2] = ( nnlen >> 8 ) & 0xff;
- buf[3] = nnlen & 0xff;
-
- PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data,
- entry->derCrl.len);
- if (nnlen != 0) {
- PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
- entry->url, nnlen);
- }
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- static SECStatus
- DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry)
- {
- unsigned int nnlen;
-
- /* is record long enough for header? */
- if ( dbentry->len < DB_CRL_ENTRY_HEADER_LEN ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* is database entry correct length? */
- entry->derCrl.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
- nnlen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
- if ( ( entry->derCrl.len + nnlen + DB_CRL_ENTRY_HEADER_LEN )
- != dbentry->len) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* copy the dercert */
- entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
- entry->derCrl.len);
- if ( entry->derCrl.data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN],
- entry->derCrl.len);
- /* copy the url */
- entry->url = NULL;
- if (nnlen != 0) {
- entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, nnlen);
- if ( entry->url == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->url,
- &dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
- nnlen);
- }
-
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * Create a new certDBEntryRevocation from existing data
- */
- static certDBEntryRevocation *
- NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags)
- {
- certDBEntryRevocation *entry;
- PRArenaPool *arena = NULL;
- int nnlen;
-
- arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
- if ( !arena ) {
- goto loser;
- }
-
- entry = (certDBEntryRevocation*)
- PORT_ArenaZAlloc(arena, sizeof(certDBEntryRevocation));
- if ( entry == NULL ) {
- goto loser;
- }
-
- /* fill in the dbRevolcation */
- entry->common.arena = arena;
- entry->common.type = crlType;
- entry->common.version = CERT_DB_FILE_VERSION;
- entry->common.flags = flags;
-
- entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len);
- if ( !entry->derCrl.data ) {
- goto loser;
- }
- if (url) {
- nnlen = PORT_Strlen(url) + 1;
- entry->url = (char *)PORT_ArenaAlloc(arena, nnlen);
- if ( !entry->url ) {
- goto loser;
- }
- PORT_Memcpy(entry->url, url, nnlen);
- } else {
- entry->url = NULL;
- }
-
- entry->derCrl.len = derCrl->len;
- PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len);
- return(entry);
- loser:
-
- /* allocation error, free arena and return */
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return(0);
- }
- static SECStatus
- WriteDBCrlEntry(CERTCertDBHandle *handle, certDBEntryRevocation *entry )
- {
- SECItem dbkey;
- PRArenaPool *tmparena = NULL;
- SECItem tmpitem,encodedEntry;
- SECStatus rv;
-
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- goto loser;
- }
- /* get the database key and format it */
- rv = CERT_KeyFromDERCrl(tmparena, &entry->derCrl, &tmpitem);
- if ( rv == SECFailure ) {
- goto loser;
- }
- rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry);
- if ( rv == SECFailure ) {
- goto loser;
- }
- rv = EncodeDBGenericKey(&tmpitem, tmparena, &dbkey, entry->common.type);
- if ( rv == SECFailure ) {
- goto loser;
- }
-
- /* now write it to the database */
- rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- return(SECFailure);
- }
- /*
- * delete a crl entry
- */
- static SECStatus
- DeleteDBCrlEntry(CERTCertDBHandle *handle, SECItem *crlKey,
- certDBEntryType crlType)
- {
- SECItem dbkey;
- PRArenaPool *arena = NULL;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = DeleteDBEntry(handle, crlType, &dbkey);
- if ( rv == SECFailure ) {
- goto loser;
- }
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(SECFailure);
- }
- /*
- * Read a certificate entry
- */
- static certDBEntryRevocation *
- ReadDBCrlEntry(CERTCertDBHandle *handle, SECItem *certKey,
- certDBEntryType crlType)
- {
- PRArenaPool *arena = NULL;
- PRArenaPool *tmparena = NULL;
- certDBEntryRevocation *entry;
- SECItem dbkey;
- SECItem dbentry;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- entry = (certDBEntryRevocation *)
- PORT_ArenaAlloc(arena, sizeof(certDBEntryRevocation));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = crlType;
- rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
- if ( rv == SECFailure ) {
- goto loser;
- }
- rv = DecodeDBCrlEntry(entry, &dbentry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(entry);
-
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * destroy a database entry
- */
- static void
- DestroyDBEntry(certDBEntry *entry)
- {
- PRArenaPool *arena = entry->common.arena;
- /* Zero out the entry struct, so that any further attempts to use it
- * will cause an exception (e.g. null pointer reference). */
- PORT_Memset(&entry->common, 0, sizeof entry->common);
- PORT_FreeArena(arena, PR_FALSE);
- return;
- }
- /*
- * Encode a database nickname record
- */
- static SECStatus
- EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena,
- SECItem *dbitem)
- {
- unsigned char *buf;
-
- /* allocate space for encoded database record, including space
- * for low level header
- */
- dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN +
- SEC_DB_ENTRY_HEADER_LEN;
-
- dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
- if ( dbitem->data == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- /* fill in database record */
- buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
-
- buf[0] = ( entry->subjectName.len >> 8 ) & 0xff;
- buf[1] = entry->subjectName.len & 0xff;
-
- PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data,
- entry->subjectName.len);
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * Encode a database key for a nickname record
- */
- static SECStatus
- EncodeDBNicknameKey(char *nickname, PRArenaPool *arena,
- SECItem *dbkey)
- {
- unsigned int nnlen;
-
- nnlen = PORT_Strlen(nickname) + 1; /* includes null */
- /* now get the database key and format it */
- dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN;
- dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
- if ( dbkey->data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], nickname, nnlen);
- dbkey->data[0] = certDBEntryTypeNickname;
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- static SECStatus
- DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry)
- {
- /* is record long enough for header? */
- if ( dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* is database entry correct length? */
- entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
- if (( entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN ) !=
- dbentry->len ){
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* copy the certkey */
- entry->subjectName.data =
- (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
- entry->subjectName.len);
- if ( entry->subjectName.data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->subjectName.data,
- &dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN],
- entry->subjectName.len);
-
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * create a new nickname entry
- */
- static certDBEntryNickname *
- NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags)
- {
- PRArenaPool *arena = NULL;
- certDBEntryNickname *entry;
- int nnlen;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
- sizeof(certDBEntryNickname));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- /* init common fields */
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeNickname;
- entry->common.version = CERT_DB_FILE_VERSION;
- entry->common.flags = flags;
- /* copy the nickname */
- nnlen = PORT_Strlen(nickname) + 1;
-
- entry->nickname = (char*)PORT_ArenaAlloc(arena, nnlen);
- if ( entry->nickname == NULL ) {
- goto loser;
- }
-
- PORT_Memcpy(entry->nickname, nickname, nnlen);
-
- rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- return(entry);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * delete a nickname entry
- */
- static SECStatus
- DeleteDBNicknameEntry(CERTCertDBHandle *handle, char *nickname)
- {
- PRArenaPool *arena = NULL;
- SECStatus rv;
- SECItem dbkey;
-
- if ( nickname == NULL ) {
- return(SECSuccess);
- }
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- rv = EncodeDBNicknameKey(nickname, arena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey);
- if ( rv == SECFailure ) {
- goto loser;
- }
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(SECFailure);
- }
- /*
- * Read a nickname entry
- */
- static certDBEntryNickname *
- ReadDBNicknameEntry(CERTCertDBHandle *handle, char *nickname)
- {
- PRArenaPool *arena = NULL;
- PRArenaPool *tmparena = NULL;
- certDBEntryNickname *entry;
- SECItem dbkey;
- SECItem dbentry;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
- sizeof(certDBEntryNickname));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeNickname;
- rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
- if ( rv == SECFailure ) {
- goto loser;
- }
- /* is record long enough for header? */
- if ( dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- rv = DecodeDBNicknameEntry(entry, &dbentry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(entry);
-
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * Encode a nickname entry into byte stream suitable for
- * the database
- */
- static SECStatus
- WriteDBNicknameEntry(CERTCertDBHandle *handle, certDBEntryNickname *entry)
- {
- SECItem dbitem, dbkey;
- PRArenaPool *tmparena = NULL;
- SECStatus rv;
-
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- goto loser;
- }
-
- rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* now write it to the database */
- rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- return(SECFailure);
-
- }
- /*
- * Encode a database smime record
- */
- static SECStatus
- EncodeDBSMimeEntry(certDBEntrySMime *entry, PRArenaPool *arena,
- SECItem *dbitem)
- {
- unsigned char *buf;
-
- /* allocate space for encoded database record, including space
- * for low level header
- */
- dbitem->len = entry->subjectName.len + entry->smimeOptions.len +
- entry->optionsDate.len +
- DB_SMIME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN;
-
- dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
- if ( dbitem->data == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- /* fill in database record */
- buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
-
- buf[0] = ( entry->subjectName.len >> 8 ) & 0xff;
- buf[1] = entry->subjectName.len & 0xff;
- buf[2] = ( entry->smimeOptions.len >> 8 ) & 0xff;
- buf[3] = entry->smimeOptions.len & 0xff;
- buf[4] = ( entry->optionsDate.len >> 8 ) & 0xff;
- buf[5] = entry->optionsDate.len & 0xff;
- /* if no smime options, then there should not be an options date either */
- PORT_Assert( ! ( ( entry->smimeOptions.len == 0 ) &&
- ( entry->optionsDate.len != 0 ) ) );
-
- PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN], entry->subjectName.data,
- entry->subjectName.len);
- if ( entry->smimeOptions.len ) {
- PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN+entry->subjectName.len],
- entry->smimeOptions.data,
- entry->smimeOptions.len);
- PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len +
- entry->smimeOptions.len],
- entry->optionsDate.data,
- entry->optionsDate.len);
- }
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * Encode a database key for a SMIME record
- */
- static SECStatus
- EncodeDBSMimeKey(char *emailAddr, PRArenaPool *arena,
- SECItem *dbkey)
- {
- unsigned int addrlen;
-
- addrlen = PORT_Strlen(emailAddr) + 1; /* includes null */
- /* now get the database key and format it */
- dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN;
- dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
- if ( dbkey->data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], emailAddr, addrlen);
- dbkey->data[0] = certDBEntryTypeSMimeProfile;
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * Decode a database SMIME record
- */
- static SECStatus
- DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr)
- {
- /* is record long enough for header? */
- if ( dbentry->len < DB_SMIME_ENTRY_HEADER_LEN ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* is database entry correct length? */
- entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
- entry->smimeOptions.len = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
- entry->optionsDate.len = ( ( dbentry->data[4] << 8 ) | dbentry->data[5] );
- if (( entry->subjectName.len + entry->smimeOptions.len +
- entry->optionsDate.len + DB_SMIME_ENTRY_HEADER_LEN ) != dbentry->len){
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- /* copy the subject name */
- entry->subjectName.data =
- (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
- entry->subjectName.len);
- if ( entry->subjectName.data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->subjectName.data,
- &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN],
- entry->subjectName.len);
- /* copy the smime options */
- if ( entry->smimeOptions.len ) {
- entry->smimeOptions.data =
- (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
- entry->smimeOptions.len);
- if ( entry->smimeOptions.data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->smimeOptions.data,
- &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
- entry->subjectName.len],
- entry->smimeOptions.len);
- }
- if ( entry->optionsDate.len ) {
- entry->optionsDate.data =
- (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
- entry->optionsDate.len);
- if ( entry->optionsDate.data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->optionsDate.data,
- &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
- entry->subjectName.len +
- entry->smimeOptions.len],
- entry->optionsDate.len);
- }
- /* both options and options date must either exist or not exist */
- if ( ( ( entry->optionsDate.len == 0 ) ||
- ( entry->smimeOptions.len == 0 ) ) &&
- entry->smimeOptions.len != entry->optionsDate.len ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- entry->emailAddr = (char *)PORT_Alloc(PORT_Strlen(emailAddr)+1);
- if ( entry->emailAddr ) {
- PORT_Strcpy(entry->emailAddr, emailAddr);
- }
-
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * create a new SMIME entry
- */
- static certDBEntrySMime *
- NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions,
- SECItem *optionsDate, unsigned int flags)
- {
- PRArenaPool *arena = NULL;
- certDBEntrySMime *entry;
- int addrlen;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
- sizeof(certDBEntrySMime));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- /* init common fields */
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeSMimeProfile;
- entry->common.version = CERT_DB_FILE_VERSION;
- entry->common.flags = flags;
- /* copy the email addr */
- addrlen = PORT_Strlen(emailAddr) + 1;
-
- entry->emailAddr = (char*)PORT_ArenaAlloc(arena, addrlen);
- if ( entry->emailAddr == NULL ) {
- goto loser;
- }
-
- PORT_Memcpy(entry->emailAddr, emailAddr, addrlen);
-
- /* copy the subject name */
- rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* copy the smime options */
- if ( smimeOptions ) {
- rv = SECITEM_CopyItem(arena, &entry->smimeOptions, smimeOptions);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- } else {
- PORT_Assert(optionsDate == NULL);
- entry->smimeOptions.data = NULL;
- entry->smimeOptions.len = 0;
- }
- /* copy the options date */
- if ( optionsDate ) {
- rv = SECITEM_CopyItem(arena, &entry->optionsDate, optionsDate);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- } else {
- PORT_Assert(smimeOptions == NULL);
- entry->optionsDate.data = NULL;
- entry->optionsDate.len = 0;
- }
-
- return(entry);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * delete a SMIME entry
- */
- static SECStatus
- DeleteDBSMimeEntry(CERTCertDBHandle *handle, char *emailAddr)
- {
- PRArenaPool *arena = NULL;
- SECStatus rv;
- SECItem dbkey;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey);
- if ( rv == SECFailure ) {
- goto loser;
- }
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(SECFailure);
- }
- /*
- * Read a SMIME entry
- */
- static certDBEntrySMime *
- ReadDBSMimeEntry(CERTCertDBHandle *handle, char *emailAddr)
- {
- PRArenaPool *arena = NULL;
- PRArenaPool *tmparena = NULL;
- certDBEntrySMime *entry;
- SECItem dbkey;
- SECItem dbentry;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
- sizeof(certDBEntrySMime));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeSMimeProfile;
- rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
- if ( rv == SECFailure ) {
- goto loser;
- }
- /* is record long enough for header? */
- if ( dbentry.len < DB_SMIME_ENTRY_HEADER_LEN ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- rv = DecodeDBSMimeEntry(entry, &dbentry, emailAddr);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(entry);
-
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * Encode a SMIME entry into byte stream suitable for
- * the database
- */
- static SECStatus
- WriteDBSMimeEntry(CERTCertDBHandle *handle, certDBEntrySMime *entry)
- {
- SECItem dbitem, dbkey;
- PRArenaPool *tmparena = NULL;
- SECStatus rv;
-
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- goto loser;
- }
-
- rv = EncodeDBSMimeEntry(entry, tmparena, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = EncodeDBSMimeKey(entry->emailAddr, tmparena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* now write it to the database */
- rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- return(SECFailure);
-
- }
- /*
- * Encode a database subject record
- */
- static SECStatus
- EncodeDBSubjectEntry(certDBEntrySubject *entry, PRArenaPool *arena,
- SECItem *dbitem)
- {
- unsigned char *buf;
- int len;
- unsigned int ncerts;
- unsigned int i;
- unsigned char *tmpbuf;
- unsigned int nnlen = 0;
- unsigned int eaddrlen = 0;
- int keyidoff;
- SECItem *certKeys;
- SECItem *keyIDs;
-
- if ( entry->nickname ) {
- nnlen = PORT_Strlen(entry->nickname) + 1;
- }
- if ( entry->emailAddr ) {
- eaddrlen = PORT_Strlen(entry->emailAddr) + 1;
- }
-
- ncerts = entry->ncerts;
-
- /* compute the length of the entry */
- keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen;
- len = keyidoff + 4 * ncerts;
- for ( i = 0; i < ncerts; i++ ) {
- len += entry->certKeys[i].len;
- len += entry->keyIDs[i].len;
- }
-
- /* allocate space for encoded database record, including space
- * for low level header
- */
- dbitem->len = len + SEC_DB_ENTRY_HEADER_LEN;
-
- dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
- if ( dbitem->data == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- /* fill in database record */
- buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
-
- buf[0] = ( ncerts >> 8 ) & 0xff;
- buf[1] = ncerts & 0xff;
- buf[2] = ( nnlen >> 8 ) & 0xff;
- buf[3] = nnlen & 0xff;
- buf[4] = ( eaddrlen >> 8 ) & 0xff;
- buf[5] = eaddrlen & 0xff;
- PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN], entry->nickname, nnlen);
- PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN+nnlen], entry->emailAddr,
- eaddrlen);
-
- for ( i = 0; i < ncerts; i++ ) {
- certKeys = entry->certKeys;
- keyIDs = entry->keyIDs;
- buf[keyidoff+i*2] = ( certKeys[i].len >> 8 ) & 0xff;
- buf[keyidoff+1+i*2] = certKeys[i].len & 0xff;
- buf[keyidoff+ncerts*2+i*2] = ( keyIDs[i].len >> 8 ) & 0xff;
- buf[keyidoff+1+ncerts*2+i*2] = keyIDs[i].len & 0xff;
- }
-
- /* temp pointer used to stuff certkeys and keyids into the buffer */
- tmpbuf = &buf[keyidoff+ncerts*4];
- for ( i = 0; i < ncerts; i++ ) {
- certKeys = entry->certKeys;
- PORT_Memcpy(tmpbuf, certKeys[i].data, certKeys[i].len);
- tmpbuf = tmpbuf + certKeys[i].len;
- }
-
- for ( i = 0; i < ncerts; i++ ) {
- keyIDs = entry->keyIDs;
- PORT_Memcpy(tmpbuf, keyIDs[i].data, keyIDs[i].len);
- tmpbuf = tmpbuf + keyIDs[i].len;
- }
- PORT_Assert(tmpbuf == &buf[len]);
-
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * Encode a database key for a subject record
- */
- static SECStatus
- EncodeDBSubjectKey(SECItem *derSubject, PRArenaPool *arena,
- SECItem *dbkey)
- {
- dbkey->len = derSubject->len + SEC_DB_KEY_HEADER_LEN;
- dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
- if ( dbkey->data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], derSubject->data,
- derSubject->len);
- dbkey->data[0] = certDBEntryTypeSubject;
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- static SECStatus
- DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry,
- SECItem *derSubject)
- {
- unsigned int ncerts;
- PRArenaPool *arena;
- unsigned int len, itemlen;
- unsigned char *tmpbuf;
- unsigned int i;
- SECStatus rv;
- unsigned int keyidoff;
- unsigned int nnlen, eaddrlen;
-
- arena = entry->common.arena;
- rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* is record long enough for header? */
- if ( dbentry->len < DB_SUBJECT_ENTRY_HEADER_LEN ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- entry->ncerts = ncerts = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
- nnlen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
- eaddrlen = ( ( dbentry->data[4] << 8 ) | dbentry->data[5] );
- if ( dbentry->len < ( ncerts * 4 + DB_SUBJECT_ENTRY_HEADER_LEN +
- nnlen + eaddrlen) ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena,
- sizeof(SECItem) * ncerts);
- entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena,
- sizeof(SECItem) * ncerts);
- if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- if ( nnlen > 1 ) { /* null terminator is stored */
- entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
- if ( entry->nickname == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->nickname,
- &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN],
- nnlen);
- } else {
- entry->nickname = NULL;
- }
-
- if ( eaddrlen > 1 ) { /* null terminator is stored */
- entry->emailAddr = (char *)PORT_ArenaAlloc(arena, eaddrlen);
- if ( entry->emailAddr == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->emailAddr,
- &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN+nnlen],
- eaddrlen);
- } else {
- entry->emailAddr = NULL;
- }
-
- /* collect the lengths of the certKeys and keyIDs, and total the
- * overall length.
- */
- keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen;
- len = keyidoff + 4 * ncerts;
- tmpbuf = &dbentry->data[0];
-
- for ( i = 0; i < ncerts; i++ ) {
- itemlen = ( tmpbuf[keyidoff + 2*i] << 8 ) | tmpbuf[keyidoff + 1 + 2*i] ;
- len += itemlen;
- entry->certKeys[i].len = itemlen;
- itemlen = ( tmpbuf[keyidoff + 2*ncerts + 2*i] << 8 ) |
- tmpbuf[keyidoff + 1 + 2*ncerts + 2*i] ;
- len += itemlen;
- entry->keyIDs[i].len = itemlen;
- }
-
- /* is database entry correct length? */
- if ( len != dbentry->len ){
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- tmpbuf = &tmpbuf[keyidoff + 4*ncerts];
- for ( i = 0; i < ncerts; i++ ) {
- entry->certKeys[i].data =
- (unsigned char *)PORT_ArenaAlloc(arena, entry->certKeys[i].len);
- if ( entry->certKeys[i].data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->certKeys[i].data, tmpbuf, entry->certKeys[i].len);
- tmpbuf = &tmpbuf[entry->certKeys[i].len];
- }
- for ( i = 0; i < ncerts; i++ ) {
- entry->keyIDs[i].data =
- (unsigned char *)PORT_ArenaAlloc(arena, entry->keyIDs[i].len);
- if ( entry->keyIDs[i].data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(entry->keyIDs[i].data, tmpbuf, entry->keyIDs[i].len);
- tmpbuf = &tmpbuf[entry->keyIDs[i].len];
- }
-
- PORT_Assert(tmpbuf == &dbentry->data[dbentry->len]);
-
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * create a new subject entry with a single cert
- */
- static certDBEntrySubject *
- NewDBSubjectEntry(SECItem *derSubject, SECItem *certKey,
- SECItem *keyID, char *nickname, char *emailAddr,
- unsigned int flags)
- {
- PRArenaPool *arena = NULL;
- certDBEntrySubject *entry;
- SECStatus rv;
- unsigned int nnlen;
- unsigned int eaddrlen;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
- sizeof(certDBEntrySubject));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- /* init common fields */
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeSubject;
- entry->common.version = CERT_DB_FILE_VERSION;
- entry->common.flags = flags;
- /* copy the subject */
- rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- entry->ncerts = 1;
- /* copy nickname */
- if ( nickname && ( *nickname != ' ' ) ) {
- nnlen = PORT_Strlen(nickname) + 1;
- entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
- if ( entry->nickname == NULL ) {
- goto loser;
- }
-
- PORT_Memcpy(entry->nickname, nickname, nnlen);
- } else {
- entry->nickname = NULL;
- }
-
- /* copy email addr */
- if ( emailAddr && ( *emailAddr != ' ' ) ) {
- emailAddr = CERT_FixupEmailAddr(emailAddr);
- if ( emailAddr == NULL ) {
- entry->emailAddr = NULL;
- goto loser;
- }
-
- eaddrlen = PORT_Strlen(emailAddr) + 1;
- entry->emailAddr = (char *)PORT_ArenaAlloc(arena, eaddrlen);
- if ( entry->emailAddr == NULL ) {
- PORT_Free(emailAddr);
- goto loser;
- }
-
- PORT_Memcpy(entry->emailAddr, emailAddr, eaddrlen);
- PORT_Free(emailAddr);
- } else {
- entry->emailAddr = NULL;
- }
-
- /* allocate space for certKeys and keyIDs */
- entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
- entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
- if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) {
- goto loser;
- }
- /* copy the certKey and keyID */
- rv = SECITEM_CopyItem(arena, &entry->certKeys[0], certKey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = SECITEM_CopyItem(arena, &entry->keyIDs[0], keyID);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- return(entry);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * delete a subject entry
- */
- static SECStatus
- DeleteDBSubjectEntry(CERTCertDBHandle *handle, SECItem *derSubject)
- {
- SECItem dbkey;
- PRArenaPool *arena = NULL;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
-
- rv = EncodeDBSubjectKey(derSubject, arena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = DeleteDBEntry(handle, certDBEntryTypeSubject, &dbkey);
- if ( rv == SECFailure ) {
- goto loser;
- }
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(SECFailure);
- }
- /*
- * Read the subject entry
- */
- static certDBEntrySubject *
- ReadDBSubjectEntry(CERTCertDBHandle *handle, SECItem *derSubject)
- {
- PRArenaPool *arena = NULL;
- PRArenaPool *tmparena = NULL;
- certDBEntrySubject *entry;
- SECItem dbkey;
- SECItem dbentry;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
- sizeof(certDBEntrySubject));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeSubject;
- rv = EncodeDBSubjectKey(derSubject, tmparena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
- if ( rv == SECFailure ) {
- goto loser;
- }
- rv = DecodeDBSubjectEntry(entry, &dbentry, derSubject);
- if ( rv == SECFailure ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(entry);
-
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * Encode a subject name entry into byte stream suitable for
- * the database
- */
- static SECStatus
- WriteDBSubjectEntry(CERTCertDBHandle *handle, certDBEntrySubject *entry)
- {
- SECItem dbitem, dbkey;
- PRArenaPool *tmparena = NULL;
- SECStatus rv;
-
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- goto loser;
- }
-
- rv = EncodeDBSubjectEntry(entry, tmparena, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = EncodeDBSubjectKey(&entry->derSubject, tmparena, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* now write it to the database */
- rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- return(SECFailure);
-
- }
- static SECStatus
- UpdateSubjectWithEmailAddr(CERTCertificate *cert, char *emailAddr)
- {
- CERTSubjectList *subjectList;
- PRBool save = PR_FALSE, delold = PR_FALSE;
- certDBEntrySubject *entry;
- SECStatus rv;
-
- emailAddr = CERT_FixupEmailAddr(emailAddr);
- if ( emailAddr == NULL ) {
- return(SECFailure);
- }
-
- subjectList = cert->subjectList;
- PORT_Assert(subjectList != NULL);
-
- if ( subjectList->emailAddr ) {
- if ( PORT_Strcmp(subjectList->emailAddr, emailAddr) != 0 ) {
- save = PR_TRUE;
- delold = PR_TRUE;
- }
- } else {
- save = PR_TRUE;
- }
- if ( delold ) {
- /* delete the old smime entry, because this cert now has a new
- * smime entry pointing to it
- */
- PORT_Assert(save);
- PORT_Assert(subjectList->emailAddr != NULL);
- DeleteDBSMimeEntry(cert->dbhandle, subjectList->emailAddr);
- }
- if ( save ) {
- unsigned int len;
-
- entry = subjectList->entry;
- PORT_Assert(entry != NULL);
- len = PORT_Strlen(emailAddr) + 1;
- entry->emailAddr = (char *)PORT_ArenaAlloc(entry->common.arena, len);
- if ( entry->emailAddr == NULL ) {
- goto loser;
- }
- PORT_Memcpy(entry->emailAddr, emailAddr, len);
-
- /* delete the subject entry */
- DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
- /* write the new one */
- rv = WriteDBSubjectEntry(cert->dbhandle, entry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
- PORT_Free(emailAddr);
- return(SECSuccess);
- loser:
- PORT_Free(emailAddr);
- return(SECFailure);
- }
- /*
- * writes a nickname to an existing subject entry that does not currently
- * have one
- */
- static SECStatus
- AddNicknameToSubject(CERTCertificate *cert, char *nickname)
- {
- CERTSubjectList *subjectList;
- certDBEntrySubject *entry;
- SECStatus rv;
-
- if ( nickname == NULL ) {
- return(SECFailure);
- }
-
- subjectList = cert->subjectList;
- PORT_Assert(subjectList != NULL);
- if ( subjectList == NULL ) {
- goto loser;
- }
-
- entry = subjectList->entry;
- PORT_Assert(entry != NULL);
- if ( entry == NULL ) {
- goto loser;
- }
-
- PORT_Assert(entry->nickname == NULL);
- if ( entry->nickname != NULL ) {
- goto loser;
- }
-
- entry->nickname = (nickname) ? PORT_ArenaStrdup(entry->common.arena, nickname) : NULL;
-
- if ( entry->nickname == NULL ) {
- goto loser;
- }
-
- /* delete the subject entry */
- DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
- /* write the new one */
- rv = WriteDBSubjectEntry(cert->dbhandle, entry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /*
- * create a new version entry
- */
- static certDBEntryVersion *
- NewDBVersionEntry(unsigned int flags)
- {
- PRArenaPool *arena = NULL;
- certDBEntryVersion *entry;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena,
- sizeof(certDBEntryVersion));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeVersion;
- entry->common.version = CERT_DB_FILE_VERSION;
- entry->common.flags = flags;
- return(entry);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * Read the version entry
- */
- static certDBEntryVersion *
- ReadDBVersionEntry(CERTCertDBHandle *handle)
- {
- PRArenaPool *arena = NULL;
- PRArenaPool *tmparena = NULL;
- certDBEntryVersion *entry;
- SECItem dbkey;
- SECItem dbentry;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena,
- sizeof(certDBEntryVersion));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeVersion;
- /* now get the database key and format it */
- dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
- dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
- if ( dbkey.data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY,
- SEC_DB_VERSION_KEY_LEN);
- ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
- PORT_FreeArena(tmparena, PR_FALSE);
- return(entry);
-
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * Encode a version entry into byte stream suitable for
- * the database
- */
- static SECStatus
- WriteDBVersionEntry(CERTCertDBHandle *handle, certDBEntryVersion *entry)
- {
- SECItem dbitem, dbkey;
- PRArenaPool *tmparena = NULL;
- SECStatus rv;
-
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- goto loser;
- }
-
- /* allocate space for encoded database record, including space
- * for low level header
- */
- dbitem.len = SEC_DB_ENTRY_HEADER_LEN;
-
- dbitem.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbitem.len);
- if ( dbitem.data == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- /* now get the database key and format it */
- dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
- dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
- if ( dbkey.data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY,
- SEC_DB_VERSION_KEY_LEN);
- /* now write it to the database */
- rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- return(SECFailure);
- }
- /*
- * create a new version entry
- */
- static certDBEntryContentVersion *
- NewDBContentVersionEntry(unsigned int flags)
- {
- PRArenaPool *arena = NULL;
- certDBEntryContentVersion *entry;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry = (certDBEntryContentVersion *)
- PORT_ArenaAlloc(arena, sizeof(certDBEntryContentVersion));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeContentVersion;
- entry->common.version = CERT_DB_FILE_VERSION;
- entry->common.flags = flags;
- entry->contentVersion = CERT_DB_CONTENT_VERSION;
-
- return(entry);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * Read the version entry
- */
- static certDBEntryContentVersion *
- ReadDBContentVersionEntry(CERTCertDBHandle *handle)
- {
- PRArenaPool *arena = NULL;
- PRArenaPool *tmparena = NULL;
- certDBEntryContentVersion *entry;
- SECItem dbkey;
- SECItem dbentry;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- entry = (certDBEntryContentVersion *)
- PORT_ArenaAlloc(arena, sizeof(certDBEntryContentVersion));
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = arena;
- entry->common.type = certDBEntryTypeContentVersion;
- /* now get the database key and format it */
- dbkey.len = SEC_DB_CONTENT_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
- dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
- if ( dbkey.data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_CONTENT_VERSION_KEY,
- SEC_DB_CONTENT_VERSION_KEY_LEN);
- dbentry.len = 0;
- dbentry.data = NULL;
-
- ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
- if ( dbentry.len != 1 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- entry->contentVersion = dbentry.data[0];
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(entry);
-
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(NULL);
- }
- /*
- * Encode a version entry into byte stream suitable for
- * the database
- */
- static SECStatus
- WriteDBContentVersionEntry(CERTCertDBHandle *handle,
- certDBEntryContentVersion *entry)
- {
- SECItem dbitem, dbkey;
- PRArenaPool *tmparena = NULL;
- SECStatus rv;
-
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- goto loser;
- }
-
- /* allocate space for encoded database record, including space
- * for low level header
- */
- dbitem.len = SEC_DB_ENTRY_HEADER_LEN + 1;
-
- dbitem.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbitem.len);
- if ( dbitem.data == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- dbitem.data[SEC_DB_ENTRY_HEADER_LEN] = entry->contentVersion;
-
- /* now get the database key and format it */
- dbkey.len = SEC_DB_CONTENT_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
- dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
- if ( dbkey.data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_CONTENT_VERSION_KEY,
- SEC_DB_CONTENT_VERSION_KEY_LEN);
- /* now write it to the database */
- rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- PORT_FreeArena(tmparena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( tmparena ) {
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- return(SECFailure);
- }
- /*
- * delete a content version entry
- */
- static SECStatus
- DeleteDBContentVersionEntry(CERTCertDBHandle *handle)
- {
- SECItem dbkey;
- PRArenaPool *arena = NULL;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- /* now get the database key and format it */
- dbkey.len = SEC_DB_CONTENT_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
- dbkey.data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey.len);
- if ( dbkey.data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_CONTENT_VERSION_KEY,
- SEC_DB_CONTENT_VERSION_KEY_LEN);
-
- rv = DeleteDBEntry(handle, certDBEntryTypeContentVersion, &dbkey);
- if ( rv == SECFailure ) {
- goto loser;
- }
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(SECFailure);
- }
- /*
- * Routines and datastructures to manage the list of certificates for a
- * particular subject name.
- */
- /*
- * Create a new certificate subject list. If entry exists, then populate
- * the list with the entries from the permanent database.
- */
- static CERTSubjectList *
- NewSubjectList(certDBEntrySubject *entry)
- {
- PRArenaPool *permarena;
- unsigned int i;
- CERTSubjectList *subjectList;
- CERTSubjectNode *node;
- SECStatus rv;
-
- permarena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( permarena == NULL ) {
- goto loser;
- }
- subjectList = (CERTSubjectList *)PORT_ArenaAlloc(permarena,
- sizeof(CERTSubjectList));
- if ( subjectList == NULL ) {
- goto loser;
- }
- subjectList->arena = permarena;
- subjectList->ncerts = 0;
- subjectList->head = NULL;
- subjectList->tail = NULL;
- subjectList->entry = entry;
- subjectList->emailAddr = NULL;
- if ( entry ) {
-
- /* initialize the list with certs from database entry */
- for ( i = 0; i < entry->ncerts; i++ ) {
- /* Init the node */
- node = (CERTSubjectNode *)PORT_ArenaAlloc(permarena,
- sizeof(CERTSubjectNode));
- if ( node == NULL ) {
- goto loser;
- }
- /* copy certKey and keyID to node */
- rv = SECITEM_CopyItem(permarena, &node->certKey,
- &entry->certKeys[i]);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = SECITEM_CopyItem(permarena, &node->keyID,
- &entry->keyIDs[i]);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* the certs are already in order, so just add them
- * to the tail.
- */
- node->next = NULL;
- if ( subjectList->tail == NULL ) {
- /* first in list */
- subjectList->head = node;
- subjectList->tail = node;
- node->prev = NULL;
- } else {
- /* add to end of list */
- node->prev = subjectList->tail;
- subjectList->tail = node;
- node->prev->next = node;
- }
- subjectList->ncerts++;
- }
- }
-
- return(subjectList);
- loser:
- PORT_FreeArena(permarena, PR_FALSE);
- return(NULL);
- }
- /*
- * Find the Subject entry in the temp database. It it is not in the
- * temp database, then get it from the perm DB. It its not there either,
- * then create a new one.
- */
- static CERTSubjectList *
- FindSubjectList(CERTCertDBHandle *handle, SECItem *subject, PRBool create)
- {
- PRArenaPool *arena = NULL;
- SECItem keyitem;
- SECStatus rv;
- DBT namekey;
- DBT tmpdata;
- int ret;
- CERTSubjectList *subjectList = NULL;
- certDBEntrySubject *entry;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- rv = EncodeDBSubjectKey(subject, arena, &keyitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- namekey.data = keyitem.data;
- namekey.size = keyitem.len;
-
- /* lookup in the temporary database */
- ret = certdb_Get(handle->tempCertDB, &namekey, &tmpdata, 0);
- /* error accessing the database */
- if ( ret < 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- if ( ret == 0 ) { /* found in temp database */
- if ( tmpdata.size != sizeof(CERTCertificate *) ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- /* copy pointer out of database */
- PORT_Memcpy(&subjectList, tmpdata.data, tmpdata.size);
- } else { /* not found in temporary database */
- entry = ReadDBSubjectEntry(handle, subject);
- if ( entry || create ) {
- /* decode or create new subject list */
- subjectList = NewSubjectList(entry);
- /* put it in the temp database */
- if ( subjectList ) {
- tmpdata.data = (unsigned char *)(&subjectList);
- tmpdata.size = sizeof(subjectList);
- ret = certdb_Put(handle->tempCertDB, &namekey,
- &tmpdata, R_NOOVERWRITE);
- if ( ret ) {
- goto loser;
- }
- }
- } else {
- PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
- goto loser;
- }
- }
- goto done;
- loser:
- subjectList = NULL;
-
- done:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(subjectList);
- }
- /*
- * Add a temp cert to the temp subject list
- */
- static SECStatus
- AddTempCertToSubjectList(CERTCertificate *cert)
- {
- CERTSubjectList *subjectList;
- CERTSubjectNode *node, *newnode;
- CERTCertificate *cmpcert;
- PRBool newer;
- SECStatus rv;
-
- PORT_Assert(cert->isperm == PR_FALSE);
- PORT_Assert(cert->subjectList == NULL);
-
- subjectList = FindSubjectList(cert->dbhandle, &cert->derSubject, PR_TRUE);
-
- if ( subjectList == NULL ) {
- goto loser;
- }
- newnode = (CERTSubjectNode*)PORT_ArenaAlloc(subjectList->arena,
- sizeof(CERTSubjectNode));
- /* copy certKey and keyID to node */
- rv = SECITEM_CopyItem(subjectList->arena, &newnode->certKey,
- &cert->certKey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = SECITEM_CopyItem(subjectList->arena, &newnode->keyID,
- &cert->subjectKeyID);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- node = subjectList->head;
- if ( node ) {
- /* list is not empty */
- while ( node ) {
- cmpcert = CERT_FindCertByKeyNoLocking(cert->dbhandle,
- &node->certKey);
- if ( cmpcert ) {
-
- newer = CERT_IsNewer(cert, cmpcert);
- CERT_DestroyCertificateNoLocking(cmpcert);
- if ( newer ) {
- /* insert before this cert */
- newnode->next = node;
- newnode->prev = node->prev;
- if ( newnode->prev ) {
- newnode->prev->next = newnode;
- } else {
- /* at the head of the list */
- subjectList->head = newnode;
- }
- node->prev = newnode;
- goto done;
- }
- }
- node = node->next;
- }
- /* if we get here, we add the node to the end of the list */
- newnode->prev = subjectList->tail;
- newnode->next = NULL;
- subjectList->tail->next = newnode;
- subjectList->tail = newnode;
- } else {
- /* this is a new/empty list */
- newnode->next = NULL;
- newnode->prev = NULL;
- subjectList->head = newnode;
- subjectList->tail = newnode;
- }
-
- done:
- subjectList->ncerts++;
- cert->subjectList = subjectList;
- return(SECSuccess);
-
- loser:
- return(SECFailure);
- }
- /*
- * Find the node in a subjectList that belongs a cert
- */
- static CERTSubjectNode *
- FindCertSubjectNode(CERTCertificate *cert)
- {
- CERTSubjectList *subjectList;
- CERTSubjectNode *node = NULL;
-
- PORT_Assert(cert->subjectList);
-
- subjectList = cert->subjectList;
-
- if ( subjectList ) {
- node = subjectList->head;
- }
-
- while ( node ) {
- if ( SECITEM_CompareItem(&node->certKey, &cert->certKey) == SECEqual ){
- return(node);
- break;
- }
-
- node = node->next;
- }
- return(NULL);
- }
- /*
- * Remove a temp cert from the temp subject list
- */
- static SECStatus
- RemoveTempCertFromSubjectList(CERTCertificate *cert)
- {
- CERTSubjectList *subjectList;
- CERTSubjectNode *node;
- SECItem keyitem;
- DBT namekey;
- SECStatus rv;
- int ret;
- CERTCertDBHandle *handle;
-
- PORT_Assert(cert->subjectList);
- /* don't remove perm certs */
- if ( cert->isperm ) {
- return(SECSuccess);
- }
-
- subjectList = cert->subjectList;
- node = FindCertSubjectNode(cert);
-
- if ( node ) {
- /* found it, unlink it */
- if ( node->next ) {
- node->next->prev = node->prev;
- } else {
- /* removing from tail of list */
- subjectList->tail = node->prev;
- }
- if ( node->prev ) {
- node->prev->next = node->next;
- } else {
- /* removing from head of list */
- subjectList->head = node->next;
- }
- subjectList->ncerts--;
-
- /* dont need to free the node, because it is from subjectList
- * arena.
- */
-
- /* remove reference from cert */
- cert->subjectList = NULL;
-
- /* if the list is now empty, remove the list from the db and free it */
- if ( subjectList->head == NULL ) {
- PORT_Assert(subjectList->ncerts == 0);
- rv = EncodeDBSubjectKey(&cert->derSubject, subjectList->arena,
- &keyitem);
- if ( rv == SECSuccess ) {
- namekey.data = keyitem.data;
- namekey.size = keyitem.len;
- handle = cert->dbhandle;
-
- ret = certdb_Del(handle->tempCertDB, &namekey, 0);
- /* keep going if it fails */
- if ( cert->dbnickname ) {
- rv = SEC_DeleteTempNickname(handle, cert->dbnickname);
- } else if ( cert->nickname ) {
- rv = SEC_DeleteTempNickname(handle, cert->nickname);
- }
-
- /* keep going if it fails */
- }
- PORT_FreeArena(subjectList->arena, PR_FALSE);
- }
- }
- PORT_Assert(cert->subjectList == NULL);
-
- if ( cert->subjectList != NULL ) {
- return(SECFailure);
- }
- return(SECSuccess);
- }
- /*
- * cert is no longer a perm cert, but will remain a temp cert
- */
- static SECStatus
- RemovePermSubjectNode(CERTCertificate *cert)
- {
- CERTSubjectList *subjectList;
- certDBEntrySubject *entry;
- unsigned int i;
- SECStatus rv;
- PORT_Assert(cert->isperm);
- if ( !cert->isperm ) {
- return(SECFailure);
- }
-
- subjectList = cert->subjectList;
- PORT_Assert(subjectList);
- if ( subjectList == NULL ) {
- return(SECFailure);
- }
- entry = subjectList->entry;
- PORT_Assert(entry);
- if ( entry == NULL ) {
- return(SECFailure);
- }
- PORT_Assert(entry->ncerts);
- rv = SECFailure;
-
- if ( entry->ncerts > 1 ) {
- for ( i = 0; i < entry->ncerts; i++ ) {
- if ( SECITEM_CompareItem(&entry->certKeys[i], &cert->certKey) ==
- SECEqual ) {
- /* copy rest of list forward one entry */
- for ( i = i + 1; i < entry->ncerts; i++ ) {
- entry->certKeys[i-1] = entry->certKeys[i];
- entry->keyIDs[i-1] = entry->keyIDs[i];
- }
- entry->ncerts--;
- DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
- rv = WriteDBSubjectEntry(cert->dbhandle, entry);
- break;
- }
- }
- } else {
- /* no entries left, delete the perm entry in the DB */
- if ( subjectList->entry->emailAddr ) {
- /* if the subject had an email record, then delete it too */
- DeleteDBSMimeEntry(cert->dbhandle, subjectList->entry->emailAddr);
- }
-
- DestroyDBEntry((certDBEntry *)subjectList->entry);
- subjectList->entry = NULL;
- DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
- }
- return(rv);
- }
- /*
- * add a cert to the perm subject list
- */
- static SECStatus
- AddPermSubjectNode(CERTCertificate *cert, char *nickname)
- {
- CERTSubjectList *subjectList;
- certDBEntrySubject *entry;
- SECItem *newCertKeys, *newKeyIDs;
- int i;
- SECStatus rv;
- CERTCertificate *cmpcert;
- unsigned int nnlen;
- int ncerts;
-
- subjectList = cert->subjectList;
-
- PORT_Assert(subjectList);
- if ( subjectList == NULL ) {
- return(SECFailure);
- }
- entry = subjectList->entry;
-
- if ( entry ) {
- ncerts = entry->ncerts;
-
- if ( nickname && entry->nickname ) {
- /* nicknames must be the same */
- PORT_Assert(PORT_Strcmp(nickname, entry->nickname) == 0);
- }
- if ( ( entry->nickname == NULL ) && ( nickname != NULL ) ) {
- /* copy nickname into the entry */
- nnlen = PORT_Strlen(nickname) + 1;
- entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena,
- nnlen);
- if ( entry->nickname == NULL ) {
- return(SECFailure);
- }
- PORT_Memcpy(entry->nickname, nickname, nnlen);
- }
-
- /* a DB entry already exists, so add this cert */
- newCertKeys = (SECItem *)PORT_ArenaAlloc(entry->common.arena,
- sizeof(SECItem) *
- ( ncerts + 1 ) );
- newKeyIDs = (SECItem *)PORT_ArenaAlloc(entry->common.arena,
- sizeof(SECItem) *
- ( ncerts + 1 ) );
- if ( ( newCertKeys == NULL ) || ( newKeyIDs == NULL ) ) {
- return(SECFailure);
- }
- for ( i = 0; i < ncerts; i++ ) {
- cmpcert = CERT_FindCertByKeyNoLocking(cert->dbhandle,
- &entry->certKeys[i]);
- PORT_Assert(cmpcert);
-
- if ( CERT_IsNewer(cert, cmpcert) ) {
- /* insert before cmpcert */
- rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[i],
- &cert->certKey);
- if ( rv != SECSuccess ) {
- return(SECFailure);
- }
- rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[i],
- &cert->subjectKeyID);
- if ( rv != SECSuccess ) {
- return(SECFailure);
- }
- /* copy the rest of the entry */
- for ( ; i < ncerts; i++ ) {
- newCertKeys[i+1] = entry->certKeys[i];
- newKeyIDs[i+1] = entry->keyIDs[i];
- }
- /* update certKeys and keyIDs */
- entry->certKeys = newCertKeys;
- entry->keyIDs = newKeyIDs;
-
- /* increment count */
- entry->ncerts++;
- break;
- }
- /* copy this cert entry */
- newCertKeys[i] = entry->certKeys[i];
- newKeyIDs[i] = entry->keyIDs[i];
- }
- if ( entry->ncerts == ncerts ) {
- /* insert new one at end */
- rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[ncerts],
- &cert->certKey);
- if ( rv != SECSuccess ) {
- return(SECFailure);
- }
- rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[ncerts],
- &cert->subjectKeyID);
- if ( rv != SECSuccess ) {
- return(SECFailure);
- }
- /* update certKeys and keyIDs */
- entry->certKeys = newCertKeys;
- entry->keyIDs = newKeyIDs;
-
- /* increment count */
- entry->ncerts++;
- }
- } else {
- /* need to make a new DB entry */
- entry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey,
- &cert->subjectKeyID, nickname,
- NULL, 0);
- cert->subjectList->entry = entry;
- }
- if ( entry ) {
- DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
- rv = WriteDBSubjectEntry(cert->dbhandle, entry);
- } else {
- rv = SECFailure;
- }
-
- return(rv);
- }
- SECStatus
- CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle, SECItem *derSubject,
- CERTCertCallback cb, void *cbarg)
- {
- certDBEntrySubject *entry;
- int i;
- CERTCertificate *cert;
- SECStatus rv = SECSuccess;
-
- entry = ReadDBSubjectEntry(handle, derSubject);
- if ( entry == NULL ) {
- return(SECFailure);
- }
-
- for( i = 0; i < entry->ncerts; i++ ) {
- cert = CERT_FindCertByKey(handle, &entry->certKeys[i]);
- rv = (* cb)(cert, cbarg);
- CERT_DestroyCertificate(cert);
- if ( rv == SECFailure ) {
- break;
- }
- }
- DestroyDBEntry((certDBEntry *)entry);
- return(rv);
- }
- int
- CERT_NumPermCertsForSubject(CERTCertDBHandle *handle, SECItem *derSubject)
- {
- certDBEntrySubject *entry;
- int ret;
-
- entry = ReadDBSubjectEntry(handle, derSubject);
- if ( entry == NULL ) {
- return(SECFailure);
- }
- ret = entry->ncerts;
-
- DestroyDBEntry((certDBEntry *)entry);
-
- return(ret);
- }
- SECStatus
- CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname,
- CERTCertCallback cb, void *cbarg)
- {
- certDBEntryNickname *nnentry = NULL;
- certDBEntrySMime *smentry = NULL;
- SECStatus rv;
- SECItem *derSubject = NULL;
-
- nnentry = ReadDBNicknameEntry(handle, nickname);
- if ( nnentry ) {
- derSubject = &nnentry->subjectName;
- } else {
- smentry = ReadDBSMimeEntry(handle, nickname);
- if ( smentry ) {
- derSubject = &smentry->subjectName;
- }
- }
-
- if ( derSubject ) {
- rv = CERT_TraversePermCertsForSubject(handle, derSubject,
- cb, cbarg);
- } else {
- rv = SECFailure;
- }
- if ( nnentry ) {
- DestroyDBEntry((certDBEntry *)nnentry);
- }
- if ( smentry ) {
- DestroyDBEntry((certDBEntry *)smentry);
- }
-
- return(rv);
- }
- int
- CERT_NumPermCertsForNickname(CERTCertDBHandle *handle, char *nickname)
- {
- certDBEntryNickname *entry;
- int ret;
-
- entry = ReadDBNicknameEntry(handle, nickname);
-
- if ( entry ) {
- ret = CERT_NumPermCertsForSubject(handle, &entry->subjectName);
- DestroyDBEntry((certDBEntry *)entry);
- } else {
- ret = 0;
- }
- return(ret);
- }
- int
- CERT_NumCertsForCertSubject(CERTCertificate *cert)
- {
- int ret = 0;
-
- if ( cert->subjectList ) {
- ret = cert->subjectList->ncerts;
- }
- return(ret);
- }
- int
- CERT_NumPermCertsForCertSubject(CERTCertificate *cert)
- {
- int ret = 0;
-
- if ( cert->subjectList ) {
- if ( cert->subjectList->entry ) {
- ret = cert->subjectList->entry->ncerts;
- }
- }
- return(ret);
- }
- SECStatus
- CERT_TraverseCertsForSubject(CERTCertDBHandle *handle,
- CERTSubjectList *subjectList,
- CERTCertCallback cb, void *cbarg)
- {
- CERTSubjectNode *node;
- CERTCertificate *cert;
- SECStatus rv = SECSuccess;
-
- CERT_LockDB(handle);
- node = subjectList->head;
- while ( node ) {
- cert = CERT_FindCertByKeyNoLocking(handle, &node->certKey);
- PORT_Assert(cert != NULL);
- if ( cert != NULL ) {
- rv = (* cb)(cert, cbarg);
- CERT_DestroyCertificateNoLocking(cert);
- if ( rv == SECFailure ) {
- break;
- }
- }
- node = node->next;
- }
- CERT_UnlockDB(handle);
- return(rv);
- }
- /*
- * Given a cert, find the cert with the same subject name that
- * has the given key usage. If the given cert has the correct keyUsage, then
- * return it, otherwise search the list in order.
- */
- CERTCertificate *
- CERT_FindCertByUsage(CERTCertificate *basecert, unsigned int requiredKeyUsage)
- {
- CERTSubjectNode *node;
- CERTCertificate *cert;
- CERTSubjectList *subjectList;
-
- if ( ( basecert->keyUsage & requiredKeyUsage ) == requiredKeyUsage ) {
- return(CERT_DupCertificate(basecert));
- }
-
- CERT_LockDB(basecert->dbhandle);
- subjectList = basecert->subjectList;
-
- node = subjectList->head;
- while ( node ) {
- cert = CERT_FindCertByKeyNoLocking(basecert->dbhandle, &node->certKey);
- PORT_Assert(cert != NULL);
- if ( cert != NULL ) {
- if ( ( cert->keyUsage & requiredKeyUsage ) ==
- requiredKeyUsage ) {
- CERT_UnlockDB(basecert->dbhandle);
- return(cert);
- }
-
- CERT_DestroyCertificateNoLocking(cert);
- }
- node = node->next;
- }
- CERT_UnlockDB(basecert->dbhandle);
- return(NULL);
- }
- /*
- * add a nickname to a cert that doesn't have one
- */
- static SECStatus
- AddNicknameToPermCert(CERTCertificate *cert, char *nickname)
- {
- certDBEntryCert *entry;
- int rv;
-
- PORT_Assert(cert->isperm);
- if ( !cert->isperm ) {
- goto loser;
- }
- entry = cert->dbEntry;
- PORT_Assert(entry != NULL);
- if ( entry == NULL ) {
- goto loser;
- }
- entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname);
- rv = WriteDBCertEntry(cert->dbhandle, entry);
- if ( rv ) {
- goto loser;
- }
- cert->nickname = PORT_ArenaStrdup(cert->arena, nickname);
- return(SECSuccess);
-
- loser:
- return(SECFailure);
- }
- /*
- * add a nickname to a cert that is already in the perm database, but doesn't
- * have one yet (it is probably an e-mail cert).
- */
- SECStatus
- CERT_AddPermNickname(CERTCertificate *cert, char *nickname)
- {
- SECStatus rv;
-
- CERT_LockDB(cert->dbhandle);
-
- PORT_Assert(cert->nickname == NULL);
- PORT_Assert(cert->isperm);
- PORT_Assert(cert->subjectList != NULL);
- PORT_Assert(cert->subjectList->entry != NULL);
-
- if ( cert->nickname != NULL ) {
- goto done;
- }
- if ( cert->subjectList == NULL ) {
- goto loser;
- }
-
- if ( cert->subjectList->entry == NULL ) {
- goto loser;
- }
- if ( cert->subjectList->entry->nickname == NULL ) {
- /* no nickname for subject */
- rv = AddNicknameToSubject(cert, nickname);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = AddNicknameToPermCert(cert, nickname);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = SEC_AddTempNickname(cert->dbhandle, nickname,
- &cert->derSubject);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- } else {
- /* subject already has a nickname */
- rv = AddNicknameToPermCert(cert, cert->subjectList->entry->nickname);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
- done:
- CERT_UnlockDB(cert->dbhandle);
- return(SECSuccess);
- loser:
- CERT_UnlockDB(cert->dbhandle);
- return(SECFailure);
- }
- static certDBEntryCert *
- AddCertToPermDB(CERTCertDBHandle *handle, CERTCertificate *cert,
- char *nickname, CERTCertTrust *trust)
- {
- certDBEntryCert *certEntry = NULL;
- certDBEntryNickname *nicknameEntry = NULL;
- certDBEntrySubject *subjectEntry = NULL;
- int state = 0;
- SECStatus rv;
- PRBool donnentry = PR_FALSE;
- if ( nickname ) {
- donnentry = PR_TRUE;
- }
-
- if ( cert->subjectList != NULL ) {
- if ( cert->subjectList->entry != NULL ) {
- if ( cert->subjectList->entry->ncerts > 0 ) {
- /* of other certs with same subject exist, then they already
- * have a nickname, so don't add a new one.
- */
- donnentry = PR_FALSE;
- nickname = cert->subjectList->entry->nickname;
- }
- }
- }
-
- certEntry = NewDBCertEntry(&cert->derCert, nickname, trust, 0);
- if ( certEntry == NULL ) {
- goto loser;
- }
-
- if ( donnentry ) {
- nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0);
- if ( nicknameEntry == NULL ) {
- goto loser;
- }
- }
-
- rv = WriteDBCertEntry(handle, certEntry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- state = 1;
-
- if ( nicknameEntry ) {
- rv = WriteDBNicknameEntry(handle, nicknameEntry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
-
- state = 2;
-
- /* add to or create new subject entry */
- if ( cert->subjectList ) {
- rv = AddPermSubjectNode(cert, nickname);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- } else {