keydb.c

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

C
2,311
字号
    } else {	openflags = O_RDWR;    }    dbname = (*namecb)(cbarg, PRIVATE_KEY_DB_FILE_VERSION);    if ( dbname == NULL ) {	goto loser;    }        handle->db = dbopen( dbname, openflags, 0600, DB_HASH, 0 );    /* check for correct version number */    if (handle->db != NULL) {	/* lookup version string in database */	rv = (* handle->db->get)( handle->db, &versionKey, &versionData, 0 );	/* error accessing the database */	if ( rv < 0 ) {	    goto loser;	}	if ( rv == 1 ) {	    /* no version number record, reset the database */	    (* handle->db->close)( handle->db );	    handle->db = NULL;	    goto newdb;	    	}		handle->version = *( (unsigned char *)versionData.data);	    	if (handle->version != PRIVATE_KEY_DB_FILE_VERSION ) {	    /* bogus version number record, reset the database */	    (* handle->db->close)( handle->db );	    handle->db = NULL;	    goto newdb;	}    }newdb:	    /* if first open fails, try to create a new DB */    if ( handle->db == NULL ) {	if ( readOnly ) {	    goto loser;	}		handle->db = dbopen( dbname,			     O_RDWR | O_CREAT | O_TRUNC, 0600, DB_HASH, 0 );        PORT_Free( dbname );        dbname = NULL;	/* if create fails then we lose */	if ( handle->db == NULL ) {	    goto loser;	}	rv = makeGlobalVersion(handle);	if ( rv != SECSuccess ) {	    goto loser;	}	/*	 * try to update from v2 db	 */	dbname = (*namecb)(cbarg, 2);	if ( dbname != NULL ) {	    handle->updatedb = dbopen( dbname, O_RDONLY, 0600, DB_HASH, 0 );	    if ( handle->updatedb ) {		/*		 * Try to update the db using a null password.  If the db		 * doesn't have a password, then this will work.  If it does		 * have a password, then this will fail and we will do the		 * update later		 */		rv = SECKEY_UpdateKeyDBPass1(handle);		if ( rv == SECSuccess ) {		    updated = PR_TRUE;		}	    }	                PORT_Free( dbname );            dbname = NULL;	}	/* we are using the old salt if we updated from an old db */	if ( ! updated ) {	    rv = makeGlobalSalt(handle);	    if ( rv != SECSuccess ) {		goto loser;	    }	}		/* sync the database */	rv = (* handle->db->sync)(handle->db, 0);	if ( rv ) {	    goto loser;	}    }    handle->global_salt = GetKeyDBGlobalSalt(handle);    if ( dbname )        PORT_Free( dbname );    return handle;loser:    if ( dbname )        PORT_Free( dbname );    PORT_SetError(SEC_ERROR_BAD_DATABASE);    if ( handle->db ) {	(* handle->db->close)(handle->db);    }    if ( handle->updatedb ) {	(* handle->updatedb->close)(handle->updatedb);    }    PORT_Free(handle);    return NULL;}/* * Close the database */voidSECKEY_CloseKeyDB(SECKEYKeyDBHandle *handle){    if (handle != NULL) {	if (handle == SECKEY_GetDefaultKeyDB()) {	    SECKEY_SetDefaultKeyDB(NULL);	}	if (handle->db != NULL) {	    (* handle->db->close)(handle->db);	}	PORT_Free(handle);    }}/* Get the key database version */intSECKEY_GetKeyDBVersion(SECKEYKeyDBHandle *handle){    PORT_Assert(handle != NULL);    return handle->version;}/* * Allow use of default key database, so that apps (such as mozilla) do * not have to pass the handle all over the place. */static SECKEYKeyDBHandle *sec_default_key_db = NULL;voidSECKEY_SetDefaultKeyDB(SECKEYKeyDBHandle *handle){    sec_default_key_db = handle;}SECKEYKeyDBHandle *SECKEY_GetDefaultKeyDB(void){    return sec_default_key_db;}/* * Delete a private key that was stored in the database */SECStatusSECKEY_DeleteKey(SECKEYKeyDBHandle *handle, SECItem *pubkey){    DBT namekey;    int rv;    if (handle == NULL) {	PORT_SetError(SEC_ERROR_BAD_DATABASE);	return(SECFailure);    }    /* set up db key and data */    namekey.data = pubkey->data;    namekey.size = pubkey->len;    /* delete it from the database */    rv = (* handle->db->del)(handle->db, &namekey, 0);    if ( rv ) {	PORT_SetError(SEC_ERROR_BAD_DATABASE);	return(SECFailure);    }    /* sync the database */    rv = (* handle->db->sync)(handle->db, 0);    if ( rv ) {	PORT_SetError(SEC_ERROR_BAD_DATABASE);	return(SECFailure);    }    return(SECSuccess);}/* * Store a key in the database, indexed by its public key modulus.(value!) */SECStatusSECKEY_StoreKeyByPublicKey(SECKEYKeyDBHandle *handle, 			   SECKEYLowPrivateKey *privkey,			   SECItem *pubKeyData,			   char *nickname,			   SECKEYGetPasswordKey f, void *arg){    return SECKEY_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, nickname,					 f, arg, SECKEY_GetDefaultKeyDBAlg());}/* see if the public key for this cert is in the database filed * by modulus */SECStatusSECKEY_KeyForCertExists(SECKEYKeyDBHandle *handle, CERTCertificate *cert){    SECKEYPublicKey *pubkey = NULL;    DBT namekey;    DBT dummy;    int status;        /* get cert's public key */    pubkey = CERT_ExtractPublicKey(cert);    if ( pubkey == NULL ) {	return SECFailure;    }    /* TNH - make key from SECKEYPublicKey */    switch (pubkey->keyType) {      case rsaKey:	namekey.data = pubkey->u.rsa.modulus.data;	namekey.size = pubkey->u.rsa.modulus.len;	break;      case dsaKey:	namekey.data = pubkey->u.dsa.publicValue.data;	namekey.size = pubkey->u.dsa.publicValue.len;	break;      case dhKey:	namekey.data = pubkey->u.dh.publicValue.data;	namekey.size = pubkey->u.dh.publicValue.len;	break;      default:	/* XXX We don't do Fortezza or DH yet. */	return SECFailure;    }    status = (* handle->db->get)(handle->db, &namekey, &dummy, 0);    SECKEY_DestroyPublicKey(pubkey);    if ( status ) {	/* TNH - should this really set an error? */	PORT_SetError(SEC_ERROR_BAD_DATABASE);	return SECFailure;    }        return SECSuccess;}/* * find the private key for a cert */SECKEYLowPrivateKey *SECKEY_FindKeyByCert(SECKEYKeyDBHandle *handle, CERTCertificate *cert,		     SECKEYGetPasswordKey f, void *arg){    SECKEYPublicKey *pubkey = NULL;    SECItem *keyItem;    SECKEYLowPrivateKey *privKey = NULL;        /* get cert's public key */    pubkey = CERT_ExtractPublicKey(cert);    if ( !pubkey ) {	goto loser;    }    /* TNH - make record key from SECKEYPublicKey (again) */    switch (pubkey->keyType) {      case rsaKey:	keyItem = &pubkey->u.rsa.modulus;	break;      case dsaKey:	keyItem = &pubkey->u.dsa.publicValue;	break;      case dhKey:	keyItem = &pubkey->u.dh.publicValue;	break;	/* fortezza an NULL keys are not stored in the data base */      case fortezzaKey:      case nullKey:	goto loser;    }    privKey = SECKEY_FindKeyByPublicKey(handle, keyItem, f, arg);    /* success falls through */loser:    SECKEY_DestroyPublicKey(pubkey);    return(privKey);}/* * check to see if the user has a password */SECStatusSECKEY_HasKeyDBPassword(SECKEYKeyDBHandle *handle){    DBT checkkey, checkdata;    int rv;    if (handle == NULL) {	return(SECFailure);    }    checkkey.data = KEYDB_PW_CHECK_STRING;    checkkey.size = KEYDB_PW_CHECK_LEN;        rv = (* handle->db->get)(handle->db, &checkkey, &checkdata, 0 );    if ( rv ) {	return(SECFailure);    }    return(SECSuccess);}/* * Set up the password checker in the key database. * This is done by encrypting a known plaintext with the user's key. */SECStatusSECKEY_SetKeyDBPassword(SECKEYKeyDBHandle *handle, SECItem *pwitem){    return SECKEY_SetKeyDBPasswordAlg(handle, pwitem,				      SECKEY_GetDefaultKeyDBAlg());}/* * Re-encrypt the entire key database with a new password. * NOTE: This really should create a new database rather than doing it * in place in the original */SECStatusSECKEY_ChangeKeyDBPassword(SECKEYKeyDBHandle *handle,			   SECItem *oldpwitem, SECItem *newpwitem){    return SECKEY_ChangeKeyDBPasswordAlg(handle, oldpwitem, newpwitem,					 SECKEY_GetDefaultKeyDBAlg());}static SECStatusHashPassword(unsigned char *hashresult, char *pw, SECItem *salt){    SHA1Context *cx;    unsigned int outlen;    cx = SHA1_NewContext();    if ( cx == NULL ) {	return(SECFailure);    }        SHA1_Begin(cx);    if ( ( salt != NULL ) && ( salt->data != NULL ) ) {	SHA1_Update(cx, salt->data, salt->len);    }        SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw));    SHA1_End(cx, hashresult, &outlen, SHA1_LENGTH);        SHA1_DestroyContext(cx, PR_TRUE);        return(SECSuccess);}SECItem *SECKEY_HashPassword(char *pw, SECItem *salt){    SECItem *pwitem;    SECStatus rv;        pwitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if ( pwitem == NULL ) {	return(NULL);    }    pwitem->len = SHA1_LENGTH;    pwitem->data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);    if ( pwitem->data == NULL ) {	PORT_Free(pwitem);	return(NULL);    }    if ( pw ) {	rv = HashPassword(pwitem->data, pw, salt);	if ( rv != SECSuccess ) {	    SECITEM_ZfreeItem(pwitem, PR_TRUE);	    return(NULL);	}    }        return(pwitem);}/* Derive the actual password value for the database from a pw string */SECItem *SECKEY_DeriveKeyDBPassword(SECKEYKeyDBHandle *keydb, char *pw){    PORT_Assert(keydb != NULL);    PORT_Assert(pw != NULL);    if (keydb == NULL || pw == NULL) return(NULL);    return SECKEY_HashPassword(pw, keydb->global_salt);}#if 0/* Appears obsolete - TNH *//* get the algorithm with which a private key * is encrypted. */SECOidTag seckey_get_private_key_algorithm(SECKEYKeyDBHandle *keydb, DBT *index)   {    SECKEYDBKey *dbkey = NULL;    SECOidTag algorithm = SEC_OID_UNKNOWN;    SECKEYEncryptedPrivateKeyInfo *epki = NULL;    PLArenaPool *poolp = NULL;    SECStatus rv;    poolp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);    if(poolp == NULL)	return (SECOidTag)SECFailure;  /* TNH - this is bad */    dbkey = get_dbkey(keydb, index);    if(dbkey == NULL)	return (SECOidTag)SECFailure;    epki = (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp, 	sizeof(SECKEYEncryptedPrivateKeyInfo));    if(epki == NULL)	goto loser;    rv = SEC_ASN1DecodeItem(poolp, epki, 	SECKEY_EncryptedPrivateKeyInfoTemplate, &dbkey->derPK);    if(rv == SECFailure)	goto loser;    algorithm = SECOID_GetAlgorithmTag(&epki->algorithm);    /* let success fall through */loser:    if(poolp != NULL)	PORT_FreeArena(poolp, PR_TRUE);\    if(dbkey != NULL)	sec_destroy_dbkey(dbkey);    return algorithm;}#endif	/* * Derive an RC4 key from a password key and a salt.  This * was the method to used to encrypt keys in the version 2? * database */SECItem *seckey_create_rc4_key(SECItem *pwitem, SECItem *salt){    MD5Context *md5 = NULL;    unsigned int part;    SECStatus rv = SECFailure;    SECItem *key = NULL;    key = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if(key != NULL)    {	key->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *		MD5_LENGTH);	key->len = MD5_LENGTH;	if(key->data != NULL)	{	    md5 = MD5_NewContext();	    if ( md5 != NULL ) 	    {		MD5_Begin(md5);		MD5_Update(md5, salt->data, salt->len);		MD5_Update(md5, pwitem->data, pwitem->len);		MD5_End(md5, key->data, &part, MD5_LENGTH);		MD5_DestroyContext(md5, PR_TRUE);		rv = SECSuccess;	    }	}		if(rv != SECSuccess)	{	    SECITEM_FreeItem(key, PR_TRUE);	    key = NULL;	}    }    return key;}SECItem *seckey_create_rc4_salt(void){    SECItem *salt = NULL;    SECStatus rv = SECFailure;    salt = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if(salt == NULL)	return NULL;    salt->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *	SALT_LENGTH);    if(salt->data != NULL)    {	salt->len = SALT_LENGTH;	RNG_GenerateGlobalRandomBytes(salt->data, salt->len);	rv = SECSuccess;    }	    if(rv == SECFailure)    {	SECITEM_FreeItem(salt, PR_TRUE);	salt = NULL;    }    return salt;}SECItem *seckey_rc4_cipher(SECItem *key, SECItem *src, PRBool encrypt){    SECItem *dest = NULL;    RC4Context *ctxt = NULL;    SECStatus rv = SECFailure;    if((key == NULL) || (src == NULL))	return NULL;    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    if(dest == NULL)	return NULL;    dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *	(src->len + 64));  /* TNH - padding? */    if(dest->data != NULL)    {	ctxt = RC4_CreateContext(key->data, key->len);	if(ctxt != NULL)	{	    if(encrypt == PR_TRUE)	    rv = RC4_Encrypt(ctxt, dest->data, &dest->len,		src->len + 64, src->data, src->len);	    else		rv = RC4_Decrypt(ctxt, dest->data, &dest->len,		    src->len + 64, src->data, src->len);	    RC4_DestroyContext(ctxt, PR_TRUE);	}    }    if(rv == SECFailure)	if(dest != NULL)	{	    SECITEM_FreeItem(dest, PR_TRUE);	    dest = NULL;	}    return dest;}/* TNH - keydb is unused *//* TNH - the pwitem should be the derived key for RC4 */

⌨️ 快捷键说明

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