keydb.c

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

C
2,311
字号
/* * 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. * * Private Key Database code * * $Id: keydb.c,v 1.3 2000/10/01 17:13:34 wtc%netscape.com Exp $ */#include "keylow.h"#include "keydbt.h"#include "seccomon.h"#include "sechash.h"#include "secder.h"#include "secasn1.h"#include "secoid.h"#include "blapi.h"#include "secitem.h"#include "cert.h"#include "mcom_db.h"#include "secpkcs5.h"#include "secerr.h"#include "private.h"/* * Record keys for keydb */#define SALT_STRING "global-salt"#define VERSION_STRING "Version"#define KEYDB_PW_CHECK_STRING	"password-check"#define KEYDB_PW_CHECK_LEN	14/* Size of the global salt for key database */#define SALT_LENGTH     16/* ASN1 Templates for new decoder/encoder *//* * Attribute value for PKCS8 entries (static?) */const SEC_ASN1Template SECKEY_AttributeTemplate[] = {    { SEC_ASN1_SEQUENCE, 	0, NULL, sizeof(SECKEYAttribute) },    { SEC_ASN1_OBJECT_ID, offsetof(SECKEYAttribute, attrType) },    { SEC_ASN1_SET_OF, offsetof(SECKEYAttribute, attrValue), 	SEC_AnyTemplate },    { 0 }};const SEC_ASN1Template SECKEY_SetOfAttributeTemplate[] = {    { SEC_ASN1_SET_OF, 0, SECKEY_AttributeTemplate },};const SEC_ASN1Template SECKEY_PrivateKeyInfoTemplate[] = {    { SEC_ASN1_SEQUENCE,	0, NULL, sizeof(SECKEYPrivateKeyInfo) },    { SEC_ASN1_INTEGER,	offsetof(SECKEYPrivateKeyInfo,version) },    { SEC_ASN1_INLINE,	offsetof(SECKEYPrivateKeyInfo,algorithm),	SECOID_AlgorithmIDTemplate },    { SEC_ASN1_OCTET_STRING,	offsetof(SECKEYPrivateKeyInfo,privateKey) },    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,	offsetof(SECKEYPrivateKeyInfo,attributes),	SECKEY_SetOfAttributeTemplate },    { 0 }};const SEC_ASN1Template SECKEY_PointerToPrivateKeyInfoTemplate[] = {    { SEC_ASN1_POINTER, 0, SECKEY_PrivateKeyInfoTemplate }};const SEC_ASN1Template SECKEY_EncryptedPrivateKeyInfoTemplate[] = {    { SEC_ASN1_SEQUENCE,	0, NULL, sizeof(SECKEYEncryptedPrivateKeyInfo) },    { SEC_ASN1_INLINE,	offsetof(SECKEYEncryptedPrivateKeyInfo,algorithm),	SECOID_AlgorithmIDTemplate },    { SEC_ASN1_OCTET_STRING,	offsetof(SECKEYEncryptedPrivateKeyInfo,encryptedData) },    { 0 }};const SEC_ASN1Template SECKEY_PointerToEncryptedPrivateKeyInfoTemplate[] = {	{ SEC_ASN1_POINTER, 0, SECKEY_EncryptedPrivateKeyInfoTemplate }};/* ====== Default key databse encryption algorithm ====== */static SECOidTag defaultKeyDBAlg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;/* * Default algorithm for encrypting data in the key database */SECOidTagSECKEY_GetDefaultKeyDBAlg(void){    return(defaultKeyDBAlg);}voidSECKEY_SetDefaultKeyDBAlg(SECOidTag alg){    defaultKeyDBAlg = alg;    return;}static voidsec_destroy_dbkey(SECKEYDBKey *dbkey){    if ( dbkey && dbkey->arena ) {	PORT_FreeArena(dbkey->arena, PR_FALSE);    }}static voidfree_dbt(DBT *dbt){    if ( dbt ) {	PORT_Free(dbt->data);	PORT_Free(dbt);    }        return;}/* * format of key database entries for version 3 of database: *	byte offset	field *	-----------	----- *	0		version *	1		salt-len *	2		nn-len *	3..		salt-data *	...		nickname *	...		encrypted-key-data */static DBT *encode_dbkey(SECKEYDBKey *dbkey){    DBT *bufitem = NULL;    unsigned char *buf;    int nnlen;    char *nn;        bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT));    if ( bufitem == NULL ) {	goto loser;    }        if ( dbkey->nickname ) {	nn = dbkey->nickname;	nnlen = PORT_Strlen(nn) + 1;    } else {	nn = "";	nnlen = 1;    }        /* compute the length of the record */    /* 1 + 1 + 1 == version number header + salt length + nn len */    bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1;        bufitem->data = (void *)PORT_ZAlloc(bufitem->size);    if ( bufitem->data == NULL ) {	goto loser;    }    buf = (unsigned char *)bufitem->data;        /* set version number */    buf[0] = PRIVATE_KEY_DB_FILE_VERSION;    /* set length of salt */    PORT_Assert(dbkey->salt.len < 256);    buf[1] = dbkey->salt.len;    /* set length of nickname */    PORT_Assert(nnlen < 256);    buf[2] = nnlen;    /* copy salt */    PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len);    /* copy nickname */    PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen);    /* copy encrypted key */    PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data,	      dbkey->derPK.len);        return(bufitem);    loser:    if ( bufitem ) {	free_dbt(bufitem);    }        return(NULL);}static SECKEYDBKey *decode_dbkey(DBT *bufitem, int expectedVersion){    SECKEYDBKey *dbkey;    PLArenaPool *arena = NULL;    unsigned char *buf;    int version;    int keyoff;    int nnlen;    int saltoff;        buf = (unsigned char *)bufitem->data;    version = buf[0];        if ( version != expectedVersion ) {	goto loser;    }        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);    if ( arena == NULL ) {	goto loser;    }        dbkey = (SECKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(SECKEYDBKey));    if ( dbkey == NULL ) {	goto loser;    }    dbkey->arena = arena;    dbkey->salt.data = NULL;    dbkey->derPK.data = NULL;        dbkey->salt.len = buf[1];    dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len);    if ( dbkey->salt.data == NULL ) {	goto loser;    }    saltoff = 2;    keyoff = 2 + dbkey->salt.len;        if ( expectedVersion == PRIVATE_KEY_DB_FILE_VERSION ) {	nnlen = buf[2];	if ( nnlen ) {	    dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1);	    if ( dbkey->nickname ) {		PORT_Memcpy(dbkey->nickname, &buf[keyoff+1], nnlen);	    }	}	keyoff += ( nnlen + 1 );	saltoff = 3;    }    PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len);        dbkey->derPK.len = bufitem->size - keyoff;    dbkey->derPK.data = (unsigned char *)PORT_ArenaZAlloc(arena,dbkey->derPK.len);    if ( dbkey->derPK.data == NULL ) {	goto loser;    }        PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len);        return(dbkey);    loser:    if ( arena ) {	PORT_FreeArena(arena, PR_FALSE);    }        return(NULL);}static SECKEYDBKey *get_dbkey(SECKEYKeyDBHandle *handle, DBT *index){    SECKEYDBKey *dbkey;    DBT entry;    SECStatus rv;        /* get it from the database */    rv = (SECStatus)(* handle->db->get)(handle->db, index, &entry, 0);    if ( rv ) {	PORT_SetError(SEC_ERROR_BAD_DATABASE);	return NULL;    }    /* set up dbkey struct */    dbkey = decode_dbkey(&entry, PRIVATE_KEY_DB_FILE_VERSION);    return(dbkey);}static SECStatusput_dbkey(SECKEYKeyDBHandle *handle, DBT *index, SECKEYDBKey *dbkey, PRBool update){    DBT *keydata = NULL;    int status;        keydata = encode_dbkey(dbkey);    if ( keydata == NULL ) {	goto loser;    }        /* put it in the database */    if ( update ) {	status = (* handle->db->put)(handle->db, index, keydata, 0);    } else {	status = (* handle->db->put)(handle->db, index, keydata,				     R_NOOVERWRITE);    }        if ( status ) {	goto loser;    }    /* sync the database */    status = (* handle->db->sync)(handle->db, 0);    if ( status ) {	goto loser;    }    free_dbt(keydata);    return(SECSuccess);loser:    if ( keydata ) {	free_dbt(keydata);    }        return(SECFailure);}SECStatusSECKEY_TraverseKeys(SECKEYKeyDBHandle *handle, 		 SECStatus (* keyfunc)(DBT *k, DBT *d, void *pdata),		 void *udata ){    DBT data;    DBT key;    SECStatus status;    int rv;    if (handle == NULL) {	return(SECFailure);    }    rv = (* handle->db->seq)(handle->db, &key, &data, R_FIRST);    if ( rv ) {	return(SECFailure);    }        do {	/* skip version record */	if ( data.size > 1 ) {	    if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {		if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {		    continue;		}	    }	    /* skip password check */	    if ( key.size == KEYDB_PW_CHECK_LEN ) {		if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,				 KEYDB_PW_CHECK_LEN) == 0 ) {		    continue;		}	    }	    	    status = (* keyfunc)(&key, &data, udata);	    if (status != SECSuccess) {		return(status);	    }	}    } while ( (* handle->db->seq)(handle->db, &key, &data, R_NEXT) == 0 );    return(SECSuccess);}typedef struct keyNode {    struct keyNode *next;    DBT key;} keyNode;typedef struct {    PLArenaPool *arena;    keyNode *head;} keyList;static SECStatussec_add_key_to_list(DBT *key, DBT *data, void *arg){    keyList *keylist;    keyNode *node;    void *keydata;        keylist = (keyList *)arg;    /* allocate the node struct */    node = (keyNode*)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode));    if ( node == NULL ) {	return(SECFailure);    }        /* allocate room for key data */    keydata = PORT_ArenaZAlloc(keylist->arena, key->size);    if ( keydata == NULL ) {	return(SECFailure);    }    /* link node into list */    node->next = keylist->head;    keylist->head = node;    /* copy key into node */    PORT_Memcpy(keydata, key->data, key->size);    node->key.size = key->size;    node->key.data = keydata;        return(SECSuccess);}static SECItem *decodeKeyDBGlobalSalt(DBT *saltData){    SECItem *saltitem;        saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if ( saltitem == NULL ) {	return(NULL);    }        saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size);    if ( saltitem->data == NULL ) {	PORT_Free(saltitem);	return(NULL);    }        saltitem->len = saltData->size;    PORT_Memcpy(saltitem->data, saltData->data, saltitem->len);        return(saltitem);}static SECItem *GetKeyDBGlobalSalt(SECKEYKeyDBHandle *handle){    DBT saltKey;    DBT saltData;    int ret;        saltKey.data = SALT_STRING;    saltKey.size = sizeof(SALT_STRING) - 1;    ret = (* handle->db->get)(handle->db, &saltKey, &saltData, 0);    if ( ret ) {	return(NULL);    }    return(decodeKeyDBGlobalSalt(&saltData));}static SECStatusmakeGlobalVersion(SECKEYKeyDBHandle *handle){    unsigned char version;    DBT versionData;    DBT versionKey;    int status;        version = PRIVATE_KEY_DB_FILE_VERSION;    versionData.data = &version;    versionData.size = 1;    versionKey.data = VERSION_STRING;    versionKey.size = sizeof(VERSION_STRING)-1;		    /* put version string into the database now */    status = (* handle->db->put)(handle->db, &versionKey, &versionData, 0);    if ( status ) {	return(SECFailure);    }    return(SECSuccess);}static SECStatusmakeGlobalSalt(SECKEYKeyDBHandle *handle){    DBT saltKey;    DBT saltData;    unsigned char saltbuf[16];    int status;        saltKey.data = SALT_STRING;    saltKey.size = sizeof(SALT_STRING) - 1;    saltData.data = (void *)saltbuf;    saltData.size = sizeof(saltbuf);    RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf));    /* put global salt into the database now */    status = (* handle->db->put)( handle->db, &saltKey, &saltData, 0);    if ( status ) {	return(SECFailure);    }    return(SECSuccess);}static char *keyDBFilenameCallback(void *arg, int dbVersion){    return(PORT_Strdup((char *)arg));}SECKEYKeyDBHandle *SECKEY_OpenKeyDBFilename(char *dbname, PRBool readOnly){    return(SECKEY_OpenKeyDB(readOnly, keyDBFilenameCallback,			   (void *)dbname));}SECKEYKeyDBHandle *SECKEY_OpenKeyDB(PRBool readOnly, SECKEYDBNameFunc namecb, void *cbarg){    SECKEYKeyDBHandle *handle;    DBT versionKey;    DBT versionData;    int rv;    int openflags;    char *dbname = NULL;    PRBool updated = PR_FALSE;        handle = (SECKEYKeyDBHandle *)PORT_ZAlloc (sizeof(SECKEYKeyDBHandle));    if (handle == NULL) {	PORT_SetError (SEC_ERROR_NO_MEMORY);	return NULL;    }    versionKey.data = VERSION_STRING;    versionKey.size = sizeof(VERSION_STRING)-1;        if ( readOnly ) {	openflags = O_RDONLY;

⌨️ 快捷键说明

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