pcertdb.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,743 行 · 第 1/5 页

C
2,743
字号
/* * 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;voidcertdb_InitDBLock(void){    if (dbLock == NULL) {	nss_InitLock(&dbLock);	PORT_Assert(dbLock != NULL);    }    return;}static intcertdb_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 intcertdb_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 intcertdb_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 intcertdb_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 intcertdb_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 voidcertdb_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 SECStatusDeleteDBEntry(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 SECStatusReadDBEntry(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 SECStatusWriteDBEntry(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 SECStatusEncodeDBCertEntry(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 SECStatusEncodeDBCertKey(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 SECStatusEncodeDBGenericKey(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 SECStatusDecodeDBCertEntry(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;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?