/security/nss/lib/softoken/legacydb/pcertdb.c
http://github.com/zpao/v8monkey · C · 5388 lines · 3939 code · 871 blank · 578 comment · 914 complexity · cb1cf42a254592733b815c8c285e0205 MD5 · raw file
Large files are truncated click here to view the full file
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * 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 the Initial Developer are Copyright (C) 1994-2000
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
- /*
- * Permanent Certificate database handling code
- *
- * $Id: pcertdb.c,v 1.12 2010/07/20 01:26:04 wtc%google.com Exp $
- */
- #include "lowkeyti.h"
- #include "pcert.h"
- #include "mcom_db.h"
- #include "pcert.h"
- #include "secitem.h"
- #include "secder.h"
- #include "secerr.h"
- #include "lgdb.h"
- /* forward declaration */
- NSSLOWCERTCertificate *
- nsslowcert_FindCertByDERCertNoLocking(NSSLOWCERTCertDBHandle *handle, SECItem *derCert);
- static SECStatus
- nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle,
- char *emailAddr, SECItem *derSubject, SECItem *emailProfile,
- SECItem *profileTime);
- static SECStatus
- nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
- NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust);
- static SECStatus
- nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl,
- SECItem *crlKey, char *url, PRBool isKRL);
- static NSSLOWCERTCertificate *certListHead = NULL;
- static NSSLOWCERTTrust *trustListHead = NULL;
- static certDBEntryCert *entryListHead = NULL;
- static int certListCount = 0;
- static int trustListCount = 0;
- static int entryListCount = 0;
- #define MAX_CERT_LIST_COUNT 10
- #define MAX_TRUST_LIST_COUNT 10
- #define MAX_ENTRY_LIST_COUNT 10
- /*
- * the following functions are wrappers for the db library that implement
- * a global lock to make the database thread safe.
- */
- static PZLock *dbLock = NULL;
- static PZLock *certRefCountLock = NULL;
- static PZLock *certTrustLock = NULL;
- static PZLock *freeListLock = NULL;
- void
- certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle)
- {
- if (dbLock == NULL) {
- dbLock = PZ_NewLock(nssILockCertDB);
- PORT_Assert(dbLock != NULL);
- }
- }
- SECStatus
- nsslowcert_InitLocks(void)
- {
- if (freeListLock == NULL) {
- freeListLock = PZ_NewLock(nssILockRefLock);
- if (freeListLock == NULL) {
- return SECFailure;
- }
- }
- if (certRefCountLock == NULL) {
- certRefCountLock = PZ_NewLock(nssILockRefLock);
- if (certRefCountLock == NULL) {
- return SECFailure;
- }
- }
- if (certTrustLock == NULL ) {
- certTrustLock = PZ_NewLock(nssILockCertDB);
- if (certTrustLock == NULL) {
- return SECFailure;
- }
- }
-
- return SECSuccess;
- }
- /*
- * Acquire the global lock on the cert database.
- * This lock is currently used for the following operations:
- * adding or deleting a cert to either the temp or perm databases
- * converting a temp to perm or perm to temp
- * changing (maybe just adding!?) the trust of a cert
- * chaning the DB status checking Configuration
- */
- static void
- nsslowcert_LockDB(NSSLOWCERTCertDBHandle *handle)
- {
- PZ_EnterMonitor(handle->dbMon);
- return;
- }
- /*
- * Free the global cert database lock.
- */
- static void
- nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle)
- {
- PRStatus prstat;
-
- prstat = PZ_ExitMonitor(handle->dbMon);
-
- PORT_Assert(prstat == PR_SUCCESS);
-
- return;
- }
- /*
- * Acquire the cert reference count lock
- * There is currently one global lock for all certs, but I'm putting a cert
- * arg here so that it will be easy to make it per-cert in the future if
- * that turns out to be necessary.
- */
- static void
- nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert)
- {
- PORT_Assert(certRefCountLock != NULL);
-
- PZ_Lock(certRefCountLock);
- return;
- }
- /*
- * Free the cert reference count lock
- */
- static void
- nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert)
- {
- PRStatus prstat;
- PORT_Assert(certRefCountLock != NULL);
-
- prstat = PZ_Unlock(certRefCountLock);
-
- PORT_Assert(prstat == PR_SUCCESS);
- return;
- }
- /*
- * Acquire the cert trust lock
- * There is currently one global lock for all certs, but I'm putting a cert
- * arg here so that it will be easy to make it per-cert in the future if
- * that turns out to be necessary.
- */
- static void
- nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert)
- {
- PORT_Assert(certTrustLock != NULL);
- PZ_Lock(certTrustLock);
- return;
- }
- /*
- * Free the cert trust lock
- */
- static void
- nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert)
- {
- PRStatus prstat;
- PORT_Assert(certTrustLock != NULL);
-
- prstat = PZ_Unlock(certTrustLock);
-
- PORT_Assert(prstat == PR_SUCCESS);
- return;
- }
- /*
- * Acquire the cert reference count lock
- * There is currently one global lock for all certs, but I'm putting a cert
- * arg here so that it will be easy to make it per-cert in the future if
- * that turns out to be necessary.
- */
- static void
- nsslowcert_LockFreeList(void)
- {
- PORT_Assert(freeListLock != NULL);
-
- SKIP_AFTER_FORK(PZ_Lock(freeListLock));
- return;
- }
- /*
- * Free the cert reference count lock
- */
- static void
- nsslowcert_UnlockFreeList(void)
- {
- PRStatus prstat = PR_SUCCESS;
- PORT_Assert(freeListLock != NULL);
-
- SKIP_AFTER_FORK(prstat = PZ_Unlock(freeListLock));
-
- PORT_Assert(prstat == PR_SUCCESS);
- return;
- }
- NSSLOWCERTCertificate *
- nsslowcert_DupCertificate(NSSLOWCERTCertificate *c)
- {
- if (c) {
- nsslowcert_LockCertRefCount(c);
- ++c->referenceCount;
- nsslowcert_UnlockCertRefCount(c);
- }
- return c;
- }
- static int
- certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
-
- PORT_Assert(dbLock != NULL);
- PZ_Lock(dbLock);
- ret = (* db->get)(db, key, data, flags);
- prstat = PZ_Unlock(dbLock);
- return(ret);
- }
- static int
- certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags)
- {
- PRStatus prstat;
- int ret = 0;
- PORT_Assert(dbLock != NULL);
- PZ_Lock(dbLock);
- ret = (* db->put)(db, key, data, flags);
-
- prstat = PZ_Unlock(dbLock);
- return(ret);
- }
- static int
- certdb_Sync(DB *db, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
- PORT_Assert(dbLock != NULL);
- PZ_Lock(dbLock);
- ret = (* db->sync)(db, flags);
-
- prstat = PZ_Unlock(dbLock);
- return(ret);
- }
- #define DB_NOT_FOUND -30991 /* from DBM 3.2 */
- static int
- certdb_Del(DB *db, DBT *key, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
- PORT_Assert(dbLock != NULL);
- PZ_Lock(dbLock);
- ret = (* db->del)(db, key, flags);
-
- prstat = PZ_Unlock(dbLock);
- /* don't fail if the record is already deleted */
- if (ret == DB_NOT_FOUND) {
- ret = 0;
- }
- return(ret);
- }
- static int
- certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags)
- {
- PRStatus prstat;
- int ret;
-
- PORT_Assert(dbLock != NULL);
- PZ_Lock(dbLock);
-
- ret = (* db->seq)(db, key, data, flags);
- prstat = PZ_Unlock(dbLock);
- return(ret);
- }
- static void
- certdb_Close(DB *db)
- {
- PRStatus prstat = PR_SUCCESS;
- PORT_Assert(dbLock != NULL);
- SKIP_AFTER_FORK(PZ_Lock(dbLock));
- (* db->close)(db);
-
- SKIP_AFTER_FORK(prstat = PZ_Unlock(dbLock));
- return;
- }
- void
- pkcs11_freeNickname(char *nickname, char *space)
- {
- if (nickname && nickname != space) {
- PORT_Free(nickname);
- }
- }
- char *
- pkcs11_copyNickname(char *nickname,char *space, int spaceLen)
- {
- int len;
- char *copy = NULL;
- len = PORT_Strlen(nickname)+1;
- if (len <= spaceLen) {
- copy = space;
- PORT_Memcpy(copy,nickname,len);
- } else {
- copy = PORT_Strdup(nickname);
- }
- return copy;
- }
- void
- pkcs11_freeStaticData (unsigned char *data, unsigned char *space)
- {
- if (data && data != space) {
- PORT_Free(data);
- }
- }
- unsigned char *
- pkcs11_allocStaticData(int len, unsigned char *space, int spaceLen)
- {
- unsigned char *data = NULL;
- if (len <= spaceLen) {
- data = space;
- } else {
- data = (unsigned char *) PORT_Alloc(len);
- }
- return data;
- }
- unsigned char *
- pkcs11_copyStaticData(unsigned char *data, int len,
- unsigned char *space, int spaceLen)
- {
- unsigned char *copy = pkcs11_allocStaticData(len, space, spaceLen);
- if (copy) {
- PORT_Memcpy(copy,data,len);
- }
- return copy;
- }
- /*
- * destroy a database entry
- */
- static void
- DestroyDBEntry(certDBEntry *entry)
- {
- PRArenaPool *arena = entry->common.arena;
- /* must be one of our certDBEntry from the free list */
- if (arena == NULL) {
- certDBEntryCert *certEntry;
- if ( entry->common.type != certDBEntryTypeCert) {
- return;
- }
- certEntry = (certDBEntryCert *)entry;
- pkcs11_freeStaticData(certEntry->derCert.data, certEntry->derCertSpace);
- pkcs11_freeNickname(certEntry->nickname, certEntry->nicknameSpace);
- nsslowcert_LockFreeList();
- if (entryListCount > MAX_ENTRY_LIST_COUNT) {
- PORT_Free(certEntry);
- } else {
- entryListCount++;
- PORT_Memset(certEntry, 0, sizeof( *certEntry));
- certEntry->next = entryListHead;
- entryListHead = certEntry;
- }
- nsslowcert_UnlockFreeList();
- return;
- }
- /* 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;
- }
- /* forward references */
- static void nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert);
- static SECStatus
- DeleteDBEntry(NSSLOWCERTCertDBHandle *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(NSSLOWCERTCertDBHandle *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;
- /* version 7 has the same schema, we may be using a v7 db if we openned
- * the databases readonly. */
- if (!((buf[0] == (unsigned char)CERT_DB_FILE_VERSION)
- || (buf[0] == (unsigned char) CERT_DB_V7_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 ) {
- if (arena) {
- 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 = &buf[SEC_DB_ENTRY_HEADER_LEN];
- }
- } else {
- dbentry->data = NULL;
- }
-
- return(SECSuccess);
- loser:
- return(SECFailure);
- }
- /**
- ** Implement low level database access
- **/
- static SECStatus
- WriteDBEntry(NSSLOWCERTCertDBHandle *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] = (PRUint8)( entry->trust.sslFlags >> 8 );
- buf[1] = (PRUint8)( entry->trust.sslFlags );
- buf[2] = (PRUint8)( entry->trust.emailFlags >> 8 );
- buf[3] = (PRUint8)( entry->trust.emailFlags );
- buf[4] = (PRUint8)( entry->trust.objectSigningFlags >> 8 );
- buf[5] = (PRUint8)( entry->trust.objectSigningFlags );
- buf[6] = (PRUint8)( entry->derCert.len >> 8 );
- buf[7] = (PRUint8)( entry->derCert.len );
- buf[8] = (PRUint8)( nnlen >> 8 );
- buf[9] = (PRUint8)( nnlen );
-
- 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(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey)
- {
- unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN;
- if (len > NSS_MAX_LEGACY_DB_KEY_SIZE)
- goto loser;
- if (arena) {
- dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
- } else {
- if (dbkey->len < len) {
- dbkey->data = (unsigned char *)PORT_Alloc(len);
- }
- }
- dbkey->len = 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(const 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;
- if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
- goto loser;
- 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;
- unsigned 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:
- case 8:
- 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] );
- lenoff = dbentry->len - ( entry->derCert.len + nnlen + headerlen );
- if ( lenoff ) {
- if ( lenoff < 0 || (lenoff & 0xffff) != 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- /* The cert size exceeded 64KB. Reconstruct the correct length. */
- entry->derCert.len += lenoff;
- }
-
- /* copy the dercert */
- entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen],
- entry->derCert.len,entry->derCertSpace,sizeof(entry->derCertSpace));
- if ( entry->derCert.data == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- /* copy the nickname */
- if ( nnlen > 1 ) {
- entry->nickname = (char *)pkcs11_copyStaticData(
- &dbentry->data[headerlen+entry->derCert.len], nnlen,
- (unsigned char *)entry->nicknameSpace,
- sizeof(entry->nicknameSpace));
- if ( entry->nickname == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- } 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,
- NSSLOWCERTCertTrust *trust, int flags)
- {
- certDBEntryCert *entry;
- PRArenaPool *arena = NULL;
- int nnlen;
-
- arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
- if ( !arena ) {
- goto loser;
- }
-
- entry = PORT_ArenaZNew(arena, 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->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];
- entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen);
- if ( !entry->derCert.data ) {
- goto loser;
- }
- entry->derCert.len = certlen;
- PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen);
- if ( nnlen ) {
- entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen);
- if ( !entry->nickname ) {
- goto loser;
- }
- PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen);
-
- if (PORT_Strcmp(entry->nickname, "Server-Cert") == 0) {
- entry->trust.sslFlags |= CERTDB_USER;
- }
- } else {
- entry->nickname = 0;
- }
- 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(NSSLOWCERTCertDBHandle *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 = nsslowcert_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(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
- {
- SECItem dbkey;
- SECStatus rv;
- dbkey.data= NULL;
- dbkey.len = 0;
- rv = EncodeDBCertKey(certKey, NULL, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey);
- if ( rv == SECFailure ) {
- goto loser;
- }
- PORT_Free(dbkey.data);
- return(SECSuccess);
- loser:
- if (dbkey.data) {
- PORT_Free(dbkey.data);
- }
- return(SECFailure);
- }
- static certDBEntryCert *
- CreateCertEntry(void)
- {
- certDBEntryCert *entry;
- nsslowcert_LockFreeList();
- entry = entryListHead;
- if (entry) {
- entryListCount--;
- entryListHead = entry->next;
- }
- PORT_Assert(entryListCount >= 0);
- nsslowcert_UnlockFreeList();
- if (entry) {
- return entry;
- }
- return PORT_ZNew(certDBEntryCert);
- }
- static void
- DestroyCertEntryFreeList(void)
- {
- certDBEntryCert *entry;
- nsslowcert_LockFreeList();
- while (NULL != (entry = entryListHead)) {
- entryListCount--;
- entryListHead = entry->next;
- PORT_Free(entry);
- }
- PORT_Assert(!entryListCount);
- entryListCount = 0;
- nsslowcert_UnlockFreeList();
- }
- /*
- * Read a certificate entry
- */
- static certDBEntryCert *
- ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
- {
- certDBEntryCert *entry;
- SECItem dbkey;
- SECItem dbentry;
- SECStatus rv;
- unsigned char buf[512];
- dbkey.data = buf;
- dbkey.len = sizeof(buf);
- entry = CreateCertEntry();
- if ( entry == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- entry->common.arena = NULL;
- entry->common.type = certDBEntryTypeCert;
- rv = EncodeDBCertKey(certKey, NULL, &dbkey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
- if ( rv == SECFailure ) {
- goto loser;
- }
- rv = DecodeDBCertEntry(entry, &dbentry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- pkcs11_freeStaticData(dbkey.data,buf);
- dbkey.data = NULL;
- return(entry);
-
- loser:
- pkcs11_freeStaticData(dbkey.data,buf);
- dbkey.data = NULL;
- if ( entry ) {
- DestroyDBEntry((certDBEntry *)entry);
- }
-
- 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] = (PRUint8)( entry->derCrl.len >> 8 );
- buf[1] = (PRUint8)( entry->derCrl.len );
- buf[2] = (PRUint8)( nnlen >> 8 );
- buf[3] = (PRUint8)( nnlen );
-
- 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 urlLen;
- int lenDiff;
- /* 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] );
- urlLen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
- lenDiff = dbentry->len -
- (entry->derCrl.len + urlLen + DB_CRL_ENTRY_HEADER_LEN);
- if (lenDiff) {
- if (lenDiff < 0 || (lenDiff & 0xffff) != 0) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- /* CRL entry is greater than 64 K. Hack to make this continue to work */
- entry->derCrl.len += lenDiff;
- }
-
- /* copy the der CRL */
- 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 (urlLen != 0) {
- entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, urlLen);
- 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],
- urlLen);
- }
-
- 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 = PORT_ArenaZNew(arena, 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(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry,
- SECItem *crlKey )
- {
- SECItem dbkey;
- PRArenaPool *tmparena = NULL;
- SECItem encodedEntry;
- SECStatus rv;
-
- tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( tmparena == NULL ) {
- goto loser;
- }
- rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry);
- if ( rv == SECFailure ) {
- goto loser;
- }
- rv = EncodeDBGenericKey(crlKey, 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(NSSLOWCERTCertDBHandle *handle, const 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(NSSLOWCERTCertDBHandle *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, NULL);
- 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);
- }
- void
- nsslowcert_DestroyDBEntry(certDBEntry *entry)
- {
- DestroyDBEntry(entry);
- 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) {
- goto loser;
- }
-
- /* fill in database record */
- buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
- buf[0] = (PRUint8)( entry->subjectName.len >> 8 );
- buf[1] = (PRUint8)( entry->subjectName.len );
- 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;
- if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
- goto loser;
- 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,
- char *nickname)
- {
- int lenDiff;
- /* 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] );
- lenDiff = dbentry->len -
- (entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN);
- if (lenDiff) {
- if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- /* The entry size exceeded 64KB. Reconstruct the correct length. */
- entry->subjectName.len += lenDiff;
- }
- /* 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);
- entry->subjectName.type = siBuffer;
-
- entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena,
- PORT_Strlen(nickname)+1);
- if ( entry->nickname ) {
- PORT_Strcpy(entry->nickname, nickname);
- }
-
- 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(NSSLOWCERTCertDBHandle *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(NSSLOWCERTCertDBHandle *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, nickname);
- 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(NSSLOWCERTCertDBHandle *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);
-
- }
- 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] = (PRUint8)( entry->subjectName.len >> 8 );
- buf[1] = (PRUint8)( entry->subjectName.len );
- buf[2] = (PRUint8)( entry->smimeOptions.len >> 8 );
- buf[3] = (PRUint8)( entry->smimeOptions.len );
- buf[4] = (PRUint8)( entry->optionsDate.len >> 8 );
- buf[5] = (PRUint8)( entry->optionsDate.len );
- /* 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;
- if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
- goto loser;
- 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)
- {
- int lenDiff;
- /* 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] );
- lenDiff = dbentry->len - (entry->subjectName.len +
- entry->smimeOptions.len +
- entry->optionsDate.len +
- DB_SMIME_ENTRY_HEADER_LEN);
- if (lenDiff) {
- if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- /* The entry size exceeded 64KB. Reconstruct the correct length. */
- entry->subjectName.len += lenDiff;
- }
- /* 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_ArenaAlloc(entry->common.arena,
- 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(NSSLOWCERTCertDBHandle *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
- */
- certDBEntrySMime *
- nsslowcert_ReadDBSMimeEntry(NSSLOWCERTCertDBHandle *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 (…