1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is the Netscape security libraries.
16
* The Initial Developer of the Original Code is
17
* Netscape Communications Corporation.
18
* Portions created by the Initial Developer are Copyright (C) 1994-2000
19
* the Initial Developer. All Rights Reserved.
22
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the MPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the MPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
37
/* $Id: keydb.c,v 1.40.2.6 2006/08/25 23:04:56 alexei.volkov.bugs%sun.com Exp $ */
59
* Record keys for keydb
61
#define SALT_STRING "global-salt"
62
#define VERSION_STRING "Version"
63
#define KEYDB_PW_CHECK_STRING "password-check"
64
#define KEYDB_PW_CHECK_LEN 14
65
#define KEYDB_FAKE_PW_CHECK_STRING "fake-password-check"
66
#define KEYDB_FAKE_PW_CHECK_LEN 19
68
/* Size of the global salt for key database */
69
#define SALT_LENGTH 16
71
const SEC_ASN1Template nsslowkey_AttributeTemplate[] = {
73
0, NULL, sizeof(NSSLOWKEYAttribute) },
74
{ SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) },
75
{ SEC_ASN1_SET_OF, offsetof(NSSLOWKEYAttribute, attrValue),
80
const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = {
81
{ SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate },
83
/* ASN1 Templates for new decoder/encoder */
84
const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = {
86
0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) },
88
offsetof(NSSLOWKEYPrivateKeyInfo,version) },
90
offsetof(NSSLOWKEYPrivateKeyInfo,algorithm),
91
SECOID_AlgorithmIDTemplate },
92
{ SEC_ASN1_OCTET_STRING,
93
offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) },
94
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
95
offsetof(NSSLOWKEYPrivateKeyInfo, attributes),
96
nsslowkey_SetOfAttributeTemplate },
100
const SEC_ASN1Template nsslowkey_PointerToPrivateKeyInfoTemplate[] = {
101
{ SEC_ASN1_POINTER, 0, nsslowkey_PrivateKeyInfoTemplate }
104
const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = {
106
0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) },
108
offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,algorithm),
109
SECOID_AlgorithmIDTemplate },
110
{ SEC_ASN1_OCTET_STRING,
111
offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,encryptedData) },
115
const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = {
116
{ SEC_ASN1_POINTER, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate }
120
/* ====== Default key databse encryption algorithm ====== */
122
static SECOidTag defaultKeyDBAlg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
125
* Default algorithm for encrypting data in the key database
128
nsslowkey_GetDefaultKeyDBAlg(void)
130
return(defaultKeyDBAlg);
134
nsslowkey_SetDefaultKeyDBAlg(SECOidTag alg)
136
defaultKeyDBAlg = alg;
142
sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey)
144
if ( dbkey && dbkey->arena ) {
145
PORT_FreeArena(dbkey->arena, PR_FALSE);
153
PORT_Free(dbt->data);
160
static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
162
static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
164
static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags);
165
static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags);
166
static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
168
static void keydb_Close(NSSLOWKEYDBHandle *db);
171
keydb_InitLocks(NSSLOWKEYDBHandle *handle)
173
if (handle->lock == NULL) {
174
nss_InitLock(&handle->lock, nssILockKeyDB);
181
keydb_DestroyLocks(NSSLOWKEYDBHandle *handle)
183
if (handle->lock != NULL) {
184
PZ_DestroyLock(handle->lock);
192
* format of key database entries for version 3 of database:
200
* ... encrypted-key-data
203
encode_dbkey(NSSLOWKEYDBKey *dbkey,unsigned char version)
210
bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT));
211
if ( bufitem == NULL ) {
215
if ( dbkey->nickname ) {
216
nn = dbkey->nickname;
217
nnlen = PORT_Strlen(nn) + 1;
223
/* compute the length of the record */
224
/* 1 + 1 + 1 == version number header + salt length + nn len */
225
bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1;
227
bufitem->data = (void *)PORT_ZAlloc(bufitem->size);
228
if ( bufitem->data == NULL ) {
232
buf = (unsigned char *)bufitem->data;
234
/* set version number */
237
/* set length of salt */
238
PORT_Assert(dbkey->salt.len < 256);
239
buf[1] = dbkey->salt.len;
241
/* set length of nickname */
242
PORT_Assert(nnlen < 256);
246
PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len);
249
PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen);
251
/* copy encrypted key */
252
PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data,
265
static NSSLOWKEYDBKey *
266
decode_dbkey(DBT *bufitem, int expectedVersion)
268
NSSLOWKEYDBKey *dbkey;
269
PLArenaPool *arena = NULL;
276
buf = (unsigned char *)bufitem->data;
280
if ( version != expectedVersion ) {
284
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
285
if ( arena == NULL ) {
289
dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
290
if ( dbkey == NULL ) {
294
dbkey->arena = arena;
295
dbkey->salt.data = NULL;
296
dbkey->derPK.data = NULL;
298
dbkey->salt.len = buf[1];
299
dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len);
300
if ( dbkey->salt.data == NULL ) {
305
keyoff = 2 + dbkey->salt.len;
307
if ( expectedVersion >= 3 ) {
310
dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1);
311
if ( dbkey->nickname ) {
312
PORT_Memcpy(dbkey->nickname, &buf[keyoff+1], nnlen);
315
keyoff += ( nnlen + 1 );
319
PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len);
321
dbkey->derPK.len = bufitem->size - keyoff;
322
dbkey->derPK.data = (unsigned char *)PORT_ArenaZAlloc(arena,dbkey->derPK.len);
323
if ( dbkey->derPK.data == NULL ) {
327
PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len);
334
PORT_FreeArena(arena, PR_FALSE);
340
static NSSLOWKEYDBKey *
341
get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index)
343
NSSLOWKEYDBKey *dbkey;
347
/* get it from the database */
348
ret = keydb_Get(handle, index, &entry, 0);
350
PORT_SetError(SEC_ERROR_BAD_DATABASE);
354
/* set up dbkey struct */
356
dbkey = decode_dbkey(&entry, handle->version);
362
put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update)
367
keydata = encode_dbkey(dbkey, handle->version);
368
if ( keydata == NULL ) {
372
/* put it in the database */
374
status = keydb_Put(handle, index, keydata, 0);
376
status = keydb_Put(handle, index, keydata, R_NOOVERWRITE);
383
/* sync the database */
384
status = keydb_Sync(handle, 0);
401
nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle,
402
SECStatus (* keyfunc)(DBT *k, DBT *d, void *pdata),
410
if (handle == NULL) {
414
ret = keydb_Seq(handle, &key, &data, R_FIRST);
420
/* skip version record */
421
if ( data.size > 1 ) {
422
if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
423
if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
428
/* skip password check */
429
if ( key.size == KEYDB_PW_CHECK_LEN ) {
430
if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,
431
KEYDB_PW_CHECK_LEN) == 0 ) {
436
status = (* keyfunc)(&key, &data, udata);
437
if (status != SECSuccess) {
441
} while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
446
typedef struct keyNode {
447
struct keyNode *next;
457
sec_add_key_to_list(DBT *key, DBT *data, void *arg)
463
keylist = (keyList *)arg;
465
/* allocate the node struct */
466
node = (keyNode*)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode));
467
if ( node == NULL ) {
471
/* allocate room for key data */
472
keydata = PORT_ArenaZAlloc(keylist->arena, key->size);
473
if ( keydata == NULL ) {
477
/* link node into list */
478
node->next = keylist->head;
479
keylist->head = node;
481
/* copy key into node */
482
PORT_Memcpy(keydata, key->data, key->size);
483
node->key.size = key->size;
484
node->key.data = keydata;
490
decodeKeyDBGlobalSalt(DBT *saltData)
494
saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
495
if ( saltitem == NULL ) {
499
saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size);
500
if ( saltitem->data == NULL ) {
505
saltitem->len = saltData->size;
506
PORT_Memcpy(saltitem->data, saltData->data, saltitem->len);
512
GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
518
saltKey.data = SALT_STRING;
519
saltKey.size = sizeof(SALT_STRING) - 1;
521
ret = keydb_Get(handle, &saltKey, &saltData, 0);
526
return(decodeKeyDBGlobalSalt(&saltData));
530
StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
536
saltKey.data = SALT_STRING;
537
saltKey.size = sizeof(SALT_STRING) - 1;
539
saltData.data = (void *)handle->global_salt->data;
540
saltData.size = handle->global_salt->len;
542
/* put global salt into the database now */
543
status = keydb_Put(handle, &saltKey, &saltData, 0);
552
makeGlobalVersion(NSSLOWKEYDBHandle *handle)
554
unsigned char version;
559
version = NSSLOWKEY_DB_FILE_VERSION;
560
versionData.data = &version;
561
versionData.size = 1;
562
versionKey.data = VERSION_STRING;
563
versionKey.size = sizeof(VERSION_STRING)-1;
565
/* put version string into the database now */
566
status = keydb_Put(handle, &versionKey, &versionData, 0);
570
handle->version = version;
577
makeGlobalSalt(NSSLOWKEYDBHandle *handle)
581
unsigned char saltbuf[16];
585
saltKey.data = SALT_STRING;
586
saltKey.size = sizeof(SALT_STRING) - 1;
588
saltData.data = (void *)saltbuf;
589
saltData.size = sizeof(saltbuf);
590
rv = RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf));
591
if ( rv != SECSuccess ) {
592
sftk_fatalError = PR_TRUE;
596
/* put global salt into the database now */
597
status = keydb_Put(handle, &saltKey, &saltData, 0);
606
ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle,
607
SECItem *oldpwitem, SECItem *newpwitem,
608
SECOidTag new_algorithm);
610
* Second pass of updating the key db. This time we have a password.
613
nsslowkey_UpdateKeyDBPass2(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
617
rv = ChangeKeyDBPasswordAlg(handle, pwitem, pwitem,
618
nsslowkey_GetDefaultKeyDBAlg());
624
encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
628
nsslowkey_version(NSSLOWKEYDBHandle *handle)
633
versionKey.data = VERSION_STRING;
634
versionKey.size = sizeof(VERSION_STRING)-1;
636
if (handle->db == NULL) {
640
/* lookup version string in database */
641
ret = keydb_Get( handle, &versionKey, &versionData, 0 );
643
/* error accessing the database */
651
return *( (unsigned char *)versionData.data);
655
seckey_HasAServerKey(NSSLOWKEYDBHandle *handle)
660
PRBool found = PR_FALSE;
662
ret = keydb_Seq(handle, &key, &data, R_FIRST);
668
/* skip version record */
669
if ( data.size > 1 ) {
671
if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
672
if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
676
/* skip pw check entry */
677
if ( key.size == KEYDB_PW_CHECK_LEN ) {
678
if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,
679
KEYDB_PW_CHECK_LEN) == 0 ) {
684
/* keys stored by nickname will have 0 as the last byte of the
685
* db key. Other keys must be stored by modulus. We will not
686
* update those because they are left over from a keygen that
687
* never resulted in a cert.
689
if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
693
if (PORT_Strcmp(key.data,"Server-Key") == 0) {
699
} while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
704
/* forward declare local create function */
705
static NSSLOWKEYDBHandle * nsslowkey_NewHandle(DB *dbHandle);
708
* currently updates key database from v2 to v3
711
nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle)
720
unsigned char version;
721
NSSLOWKEYDBKey *dbkey = NULL;
722
NSSLOWKEYDBHandle *update = NULL;
723
SECItem *oldSalt = NULL;
727
if ( handle->updatedb == NULL ) {
731
/* create a full DB Handle for our update so we
732
* can use the correct locks for the db primatives */
733
update = nsslowkey_NewHandle(handle->updatedb);
734
if ( update == NULL) {
738
/* update has now inherited the database handle */
739
handle->updatedb = NULL;
742
* check the version record
744
version = nsslowkey_version(update);
749
saltKey.data = SALT_STRING;
750
saltKey.size = sizeof(SALT_STRING) - 1;
752
ret = keydb_Get(update, &saltKey, &saltData, 0);
754
/* no salt in old db, so it is corrupted */
758
oldSalt = decodeKeyDBGlobalSalt(&saltData);
759
if ( oldSalt == NULL ) {
760
/* bad salt in old db, so it is corrupted */
765
* look for a pw check entry
767
checkKey.data = KEYDB_PW_CHECK_STRING;
768
checkKey.size = KEYDB_PW_CHECK_LEN;
770
ret = keydb_Get(update, &checkKey, &checkData, 0 );
773
* if we have a key, but no KEYDB_PW_CHECK_STRING, then this must
774
* be an old server database, and it does have a password associated
775
* with it. Put a fake entry in so we can identify this db when we do
776
* get the password for it.
778
if (seckey_HasAServerKey(update)) {
783
* include a fake string
785
fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING;
786
fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN;
787
fcheckData.data = "1";
789
/* put global salt into the new database now */
790
ret = keydb_Put( handle, &saltKey, &saltData, 0);
794
ret = keydb_Put( handle, &fcheckKey, &fcheckData, 0);
802
/* put global salt into the new database now */
803
ret = keydb_Put( handle, &saltKey, &saltData, 0);
808
dbkey = decode_dbkey(&checkData, 2);
809
if ( dbkey == NULL ) {
812
checkitem = dbkey->derPK;
813
dbkey->derPK.data = NULL;
815
/* format the new pw check entry */
816
rv = encodePWCheckEntry(NULL, &dbkey->derPK, SEC_OID_RC4, &checkitem);
817
if ( rv != SECSuccess ) {
821
rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE);
822
if ( rv != SECSuccess ) {
827
sec_destroy_dbkey(dbkey);
832
/* now traverse the database */
833
ret = keydb_Seq(update, &key, &data, R_FIRST);
839
/* skip version record */
840
if ( data.size > 1 ) {
842
if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
843
if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
847
/* skip pw check entry */
848
if ( key.size == checkKey.size ) {
849
if ( PORT_Memcmp(key.data, checkKey.data, key.size) == 0 ) {
854
/* keys stored by nickname will have 0 as the last byte of the
855
* db key. Other keys must be stored by modulus. We will not
856
* update those because they are left over from a keygen that
857
* never resulted in a cert.
859
if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
863
dbkey = decode_dbkey(&data, 2);
864
if ( dbkey == NULL ) {
868
/* This puts the key into the new database with the same
869
* index (nickname) that it had before. The second pass
870
* of the update will have the password. It will decrypt
871
* and re-encrypt the entries using a new algorithm.
873
dbkey->nickname = (char *)key.data;
874
rv = put_dbkey(handle, &key, dbkey, PR_FALSE);
875
dbkey->nickname = NULL;
877
sec_destroy_dbkey(dbkey);
879
} while ( keydb_Seq(update, &key, &data, R_NEXT) == 0 );
884
/* sync the database */
885
ret = keydb_Sync(handle, 0);
887
nsslowkey_CloseKeyDB(update);
890
SECITEM_FreeItem(oldSalt, PR_TRUE);
894
sec_destroy_dbkey(dbkey);
901
openNewDB(const char *appName, const char *prefix, const char *dbname,
902
NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg)
904
SECStatus rv = SECFailure;
905
int status = RDB_FAIL;
906
char *updname = NULL;
908
PRBool updated = PR_FALSE;
912
handle->db = rdbopen( appName, prefix, "key", NO_CREATE, &status);
914
handle->db = dbopen( dbname, NO_CREATE, 0600, DB_HASH, 0 );
916
/* if create fails then we lose */
917
if ( handle->db == NULL ) {
918
return (status == RDB_RETRY) ? SECWouldBlock: SECFailure;
921
rv = db_BeginTransaction(handle->db);
922
if (rv != SECSuccess) {
923
db_InitComplete(handle->db);
927
/* force a transactional read, which will verify that one and only one
928
* process attempts the update. */
929
if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION) {
930
/* someone else has already updated the database for us */
931
db_FinishTransaction(handle->db, PR_FALSE);
932
db_InitComplete(handle->db);
937
* if we are creating a multiaccess database, see if there is a
938
* local database we can update from.
941
NSSLOWKEYDBHandle *updateHandle;
942
updatedb = dbopen( dbname, NO_RDONLY, 0600, DB_HASH, 0 );
947
/* nsslowkey_version needs a full handle because it calls
948
* the kdb_Get() function, which needs to lock.
950
updateHandle = nsslowkey_NewHandle(updatedb);
952
updatedb->close(updatedb);
956
handle->version = nsslowkey_version(updateHandle);
957
if (handle->version != NSSLOWKEY_DB_FILE_VERSION) {
958
nsslowkey_CloseKeyDB(updateHandle);
962
/* copy the new DB from the old one */
963
db_Copy(handle->db, updatedb);
964
nsslowkey_CloseKeyDB(updateHandle);
965
db_FinishTransaction(handle->db,PR_FALSE);
966
db_InitComplete(handle->db);
971
/* update the version number */
972
rv = makeGlobalVersion(handle);
973
if ( rv != SECSuccess ) {
978
* try to update from v2 db
980
updname = (*namecb)(cbarg, 2);
981
if ( updname != NULL ) {
982
handle->updatedb = dbopen( updname, NO_RDONLY, 0600, DB_HASH, 0 );
983
PORT_Free( updname );
985
if ( handle->updatedb ) {
987
* Try to update the db using a null password. If the db
988
* doesn't have a password, then this will work. If it does
989
* have a password, then this will fail and we will do the
992
rv = nsslowkey_UpdateKeyDBPass1(handle);
993
if ( rv == SECSuccess ) {
1000
/* we are using the old salt if we updated from an old db */
1002
rv = makeGlobalSalt(handle);
1003
if ( rv != SECSuccess ) {
1008
/* sync the database */
1009
ret = keydb_Sync(handle, 0);
1017
db_FinishTransaction(handle->db, rv != SECSuccess);
1018
db_InitComplete(handle->db);
1024
openOldDB(const char *appName, const char *prefix, const char *dbname,
1029
db = rdbopen( appName, prefix, "key", openflags, NULL);
1031
db = dbopen( dbname, openflags, 0600, DB_HASH, 0 );
1037
/* check for correct version number */
1039
verifyVersion(NSSLOWKEYDBHandle *handle)
1041
int version = nsslowkey_version(handle);
1043
handle->version = version;
1044
if (version != NSSLOWKEY_DB_FILE_VERSION ) {
1046
keydb_Close(handle);
1050
return handle->db != NULL;
1053
static NSSLOWKEYDBHandle *
1054
nsslowkey_NewHandle(DB *dbHandle)
1056
NSSLOWKEYDBHandle *handle;
1057
handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc (sizeof(NSSLOWKEYDBHandle));
1058
if (handle == NULL) {
1059
PORT_SetError (SEC_ERROR_NO_MEMORY);
1063
handle->appname = NULL;
1064
handle->dbname = NULL;
1065
handle->global_salt = NULL;
1066
handle->updatedb = NULL;
1067
handle->db = dbHandle;
1070
keydb_InitLocks(handle);
1075
nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix,
1076
NSSLOWKEYDBNameFunc namecb, void *cbarg)
1078
NSSLOWKEYDBHandle *handle = NULL;
1081
char *dbname = NULL;
1084
handle = nsslowkey_NewHandle(NULL);
1086
openflags = readOnly ? NO_RDONLY : NO_RDWR;
1089
dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION);
1090
if ( dbname == NULL ) {
1093
handle->appname = appName ? PORT_Strdup(appName) : NULL ;
1094
handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) :
1095
(prefix ? PORT_Strdup(prefix) : NULL);
1096
handle->readOnly = readOnly;
1100
handle->db = openOldDB(appName, prefix, dbname, openflags);
1102
verifyVersion(handle);
1103
if (handle->version == 255) {
1108
/* if first open fails, try to create a new DB */
1109
if ( handle->db == NULL ) {
1114
rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg);
1115
/* two processes started to initialize the database at the same time.
1116
* The multiprocess code blocked the second one, then had it retry to
1117
* see if it can just open the database normally */
1118
if (rv == SECWouldBlock) {
1119
handle->db = openOldDB(appName,prefix,dbname, openflags);
1120
verifyVersion(handle);
1121
if (handle->db == NULL) {
1124
} else if (rv != SECSuccess) {
1129
handle->global_salt = GetKeyDBGlobalSalt(handle);
1131
PORT_Free( dbname );
1137
PORT_Free( dbname );
1138
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1139
nsslowkey_CloseKeyDB(handle);
1144
* Close the database
1147
nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle)
1149
if (handle != NULL) {
1150
if (handle->db != NULL) {
1151
keydb_Close(handle);
1153
if (handle->updatedb) {
1154
handle->updatedb->close(handle->updatedb);
1156
if (handle->dbname) PORT_Free(handle->dbname);
1157
if (handle->appname) PORT_Free(handle->appname);
1158
if (handle->global_salt) {
1159
SECITEM_FreeItem(handle->global_salt,PR_TRUE);
1161
keydb_DestroyLocks(handle);
1167
/* Get the key database version */
1169
nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle)
1171
PORT_Assert(handle != NULL);
1173
return handle->version;
1177
* Delete a private key that was stored in the database
1180
nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, SECItem *pubkey)
1185
if (handle == NULL) {
1186
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1190
/* set up db key and data */
1191
namekey.data = pubkey->data;
1192
namekey.size = pubkey->len;
1194
/* delete it from the database */
1195
ret = keydb_Del(handle, &namekey, 0);
1197
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1201
/* sync the database */
1202
ret = keydb_Sync(handle, 0);
1204
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1212
* Store a key in the database, indexed by its public key modulus.(value!)
1215
nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle,
1216
NSSLOWKEYPrivateKey *privkey,
1217
SECItem *pubKeyData,
1221
return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData,
1222
nickname, arg, nsslowkey_GetDefaultKeyDBAlg(),PR_FALSE);
1226
nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle,
1227
NSSLOWKEYPrivateKey *privkey,
1228
SECItem *pubKeyData,
1232
return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData,
1233
nickname, arg, nsslowkey_GetDefaultKeyDBAlg(),PR_TRUE);
1236
/* see if the symetric CKA_ID already Exists.
1239
nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id)
1245
namekey.data = (char *)id->data;
1246
namekey.size = id->len;
1247
status = keydb_Get(handle, &namekey, &dummy, 0);
1255
/* see if the public key for this cert is in the database filed
1259
nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert)
1261
NSSLOWKEYPublicKey *pubkey = NULL;
1266
/* get cert's public key */
1267
pubkey = nsslowcert_ExtractPublicKey(cert);
1268
if ( pubkey == NULL ) {
1272
/* TNH - make key from NSSLOWKEYPublicKey */
1273
switch (pubkey->keyType) {
1274
case NSSLOWKEYRSAKey:
1275
namekey.data = pubkey->u.rsa.modulus.data;
1276
namekey.size = pubkey->u.rsa.modulus.len;
1278
case NSSLOWKEYDSAKey:
1279
namekey.data = pubkey->u.dsa.publicValue.data;
1280
namekey.size = pubkey->u.dsa.publicValue.len;
1282
case NSSLOWKEYDHKey:
1283
namekey.data = pubkey->u.dh.publicValue.data;
1284
namekey.size = pubkey->u.dh.publicValue.len;
1286
#ifdef NSS_ENABLE_ECC
1287
case NSSLOWKEYECKey:
1288
namekey.data = pubkey->u.ec.publicValue.data;
1289
namekey.size = pubkey->u.ec.publicValue.len;
1291
#endif /* NSS_ENABLE_ECC */
1293
/* XXX We don't do Fortezza or DH yet. */
1297
if (handle->version != 3) {
1298
unsigned char buf[SHA1_LENGTH];
1299
SHA1_HashBuf(buf,namekey.data,namekey.size);
1300
/* NOTE: don't use pubkey after this! it's now thrashed */
1301
PORT_Memcpy(namekey.data,buf,sizeof(buf));
1302
namekey.size = sizeof(buf);
1305
status = keydb_Get(handle, &namekey, &dummy, 0);
1306
/* some databases have the key stored as a signed value */
1308
unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size+1);
1310
PORT_Memcpy(&buf[1], namekey.data, namekey.size);
1314
status = keydb_Get(handle, &namekey, &dummy, 0);
1318
nsslowkey_DestroyPublicKey(pubkey);
1327
* check to see if the user has a password
1330
nsslowkey_HasKeyDBPassword(NSSLOWKEYDBHandle *handle)
1332
DBT checkkey, checkdata;
1335
if (handle == NULL) {
1339
checkkey.data = KEYDB_PW_CHECK_STRING;
1340
checkkey.size = KEYDB_PW_CHECK_LEN;
1342
ret = keydb_Get(handle, &checkkey, &checkdata, 0 );
1344
/* see if this was an updated DB first */
1345
checkkey.data = KEYDB_FAKE_PW_CHECK_STRING;
1346
checkkey.size = KEYDB_FAKE_PW_CHECK_LEN;
1347
ret = keydb_Get(handle, &checkkey, &checkdata, 0 );
1357
* Set up the password checker in the key database.
1358
* This is done by encrypting a known plaintext with the user's key.
1361
nsslowkey_SetKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
1363
return nsslowkey_SetKeyDBPasswordAlg(handle, pwitem,
1364
nsslowkey_GetDefaultKeyDBAlg());
1368
HashPassword(unsigned char *hashresult, char *pw, SECItem *salt)
1371
unsigned int outlen;
1372
cx = SHA1_NewContext();
1378
if ( ( salt != NULL ) && ( salt->data != NULL ) ) {
1379
SHA1_Update(cx, salt->data, salt->len);
1382
SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw));
1383
SHA1_End(cx, hashresult, &outlen, SHA1_LENGTH);
1385
SHA1_DestroyContext(cx, PR_TRUE);
1391
nsslowkey_HashPassword(char *pw, SECItem *salt)
1396
pwitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1397
if ( pwitem == NULL ) {
1400
pwitem->len = SHA1_LENGTH;
1401
pwitem->data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);
1402
if ( pwitem->data == NULL ) {
1407
rv = HashPassword(pwitem->data, pw, salt);
1408
if ( rv != SECSuccess ) {
1409
SECITEM_ZfreeItem(pwitem, PR_TRUE);
1417
/* Derive the actual password value for the database from a pw string */
1419
nsslowkey_DeriveKeyDBPassword(NSSLOWKEYDBHandle *keydb, char *pw)
1421
PORT_Assert(keydb != NULL);
1422
PORT_Assert(pw != NULL);
1423
if (keydb == NULL || pw == NULL) return(NULL);
1425
return nsslowkey_HashPassword(pw, keydb->global_salt);
1429
* Derive an RC4 key from a password key and a salt. This
1430
* was the method to used to encrypt keys in the version 2?
1434
seckey_create_rc4_key(SECItem *pwitem, SECItem *salt)
1436
MD5Context *md5 = NULL;
1438
SECStatus rv = SECFailure;
1439
SECItem *key = NULL;
1441
key = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1444
key->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
1446
key->len = MD5_LENGTH;
1447
if(key->data != NULL)
1449
md5 = MD5_NewContext();
1453
MD5_Update(md5, salt->data, salt->len);
1454
MD5_Update(md5, pwitem->data, pwitem->len);
1455
MD5_End(md5, key->data, &part, MD5_LENGTH);
1456
MD5_DestroyContext(md5, PR_TRUE);
1461
if(rv != SECSuccess)
1463
SECITEM_FreeItem(key, PR_TRUE);
1472
seckey_create_rc4_salt(void)
1474
SECItem *salt = NULL;
1475
SECStatus rv = SECFailure;
1477
salt = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1481
salt->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
1483
if(salt->data != NULL)
1485
salt->len = SALT_LENGTH;
1486
rv = RNG_GenerateGlobalRandomBytes(salt->data, salt->len);
1487
if(rv != SECSuccess)
1488
sftk_fatalError = PR_TRUE;
1491
if(rv != SECSuccess)
1493
SECITEM_FreeItem(salt, PR_TRUE);
1501
seckey_rc4_decode(SECItem *key, SECItem *src)
1503
SECItem *dest = NULL;
1504
RC4Context *ctxt = NULL;
1505
SECStatus rv = SECFailure;
1507
if((key == NULL) || (src == NULL))
1510
dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1514
dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
1515
(src->len + 64)); /* TNH - padding? */
1516
if(dest->data != NULL)
1518
ctxt = RC4_CreateContext(key->data, key->len);
1521
rv = RC4_Decrypt(ctxt, dest->data, &dest->len,
1522
src->len + 64, src->data, src->len);
1523
RC4_DestroyContext(ctxt, PR_TRUE);
1527
if(rv == SECFailure)
1530
SECITEM_FreeItem(dest, PR_TRUE);
1539
#define SEC_PRINT(str1, str2, num, sitem) \
1540
printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
1541
str1, str2, num, sitem->len); \
1542
for (i = 0; i < sitem->len; i++) { \
1543
printf("%02x:", sitem->data[i]); \
1547
#define SEC_PRINT(a, b, c, d)
1548
#endif /* EC_DEBUG */
1550
/* TNH - keydb is unused */
1551
/* TNH - the pwitem should be the derived key for RC4 */
1552
NSSLOWKEYEncryptedPrivateKeyInfo *
1553
seckey_encrypt_private_key(
1554
NSSLOWKEYPrivateKey *pk, SECItem *pwitem, NSSLOWKEYDBHandle *keydb,
1555
SECOidTag algorithm, SECItem **salt)
1557
NSSLOWKEYEncryptedPrivateKeyInfo *epki = NULL;
1558
NSSLOWKEYPrivateKeyInfo *pki = NULL;
1559
SECStatus rv = SECFailure;
1560
PLArenaPool *temparena = NULL, *permarena = NULL;
1561
SECItem *der_item = NULL;
1562
NSSPKCS5PBEParameter *param = NULL;
1563
SECItem *dummy = NULL, *dest = NULL;
1564
SECAlgorithmID *algid;
1565
#ifdef NSS_ENABLE_ECC
1566
SECItem *fordebug = NULL;
1572
permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1573
if(permarena == NULL)
1576
temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1577
if(temparena == NULL)
1580
/* allocate structures */
1581
epki = (NSSLOWKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(permarena,
1582
sizeof(NSSLOWKEYEncryptedPrivateKeyInfo));
1583
pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena,
1584
sizeof(NSSLOWKEYPrivateKeyInfo));
1585
der_item = (SECItem *)PORT_ArenaZAlloc(temparena, sizeof(SECItem));
1586
if((epki == NULL) || (pki == NULL) || (der_item == NULL))
1589
epki->arena = permarena;
1591
/* setup private key info */
1592
dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version),
1593
NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
1597
/* Encode the key, and set the algorithm (with params) */
1598
switch (pk->keyType) {
1599
case NSSLOWKEYRSAKey:
1600
prepare_low_rsa_priv_key_for_asn1(pk);
1601
dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
1602
nsslowkey_RSAPrivateKeyTemplate);
1603
if (dummy == NULL) {
1608
rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
1609
SEC_OID_PKCS1_RSA_ENCRYPTION, 0);
1610
if (rv == SECFailure) {
1615
case NSSLOWKEYDSAKey:
1616
prepare_low_dsa_priv_key_for_asn1(pk);
1617
dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
1618
nsslowkey_DSAPrivateKeyTemplate);
1619
if (dummy == NULL) {
1624
prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
1625
dummy = SEC_ASN1EncodeItem(temparena, NULL, &pk->u.dsa.params,
1626
nsslowkey_PQGParamsTemplate);
1627
if (dummy == NULL) {
1632
rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
1633
SEC_OID_ANSIX9_DSA_SIGNATURE, dummy);
1634
if (rv == SECFailure) {
1639
case NSSLOWKEYDHKey:
1640
prepare_low_dh_priv_key_for_asn1(pk);
1641
dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
1642
nsslowkey_DHPrivateKeyTemplate);
1643
if (dummy == NULL) {
1648
rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
1649
SEC_OID_X942_DIFFIE_HELMAN_KEY, dummy);
1650
if (rv == SECFailure) {
1654
#ifdef NSS_ENABLE_ECC
1655
case NSSLOWKEYECKey:
1656
prepare_low_ec_priv_key_for_asn1(pk);
1657
/* Public value is encoded as a bit string so adjust length
1658
* to be in bits before ASN encoding and readjust
1659
* immediately after.
1661
* Since the SECG specification recommends not including the
1662
* parameters as part of ECPrivateKey, we zero out the curveOID
1663
* length before encoding and restore it later.
1665
pk->u.ec.publicValue.len <<= 3;
1666
savelen = pk->u.ec.ecParams.curveOID.len;
1667
pk->u.ec.ecParams.curveOID.len = 0;
1668
dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
1669
nsslowkey_ECPrivateKeyTemplate);
1670
pk->u.ec.ecParams.curveOID.len = savelen;
1671
pk->u.ec.publicValue.len >>= 3;
1673
if (dummy == NULL) {
1678
dummy = &pk->u.ec.ecParams.DEREncoding;
1680
/* At this point dummy should contain the encoded params */
1681
rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
1682
SEC_OID_ANSIX962_EC_PUBLIC_KEY, dummy);
1684
if (rv == SECFailure) {
1688
fordebug = &(pki->privateKey);
1689
SEC_PRINT("seckey_encrypt_private_key()", "PrivateKey",
1690
pk->keyType, fordebug);
1693
#endif /* NSS_ENABLE_ECC */
1695
/* We don't support DH or Fortezza private keys yet */
1696
PORT_Assert(PR_FALSE);
1700
/* setup encrypted private key info */
1701
dummy = SEC_ASN1EncodeItem(temparena, der_item, pki,
1702
nsslowkey_PrivateKeyInfoTemplate);
1704
SEC_PRINT("seckey_encrypt_private_key()", "PrivateKeyInfo",
1705
pk->keyType, der_item);
1712
rv = SECFailure; /* assume failure */
1713
*salt = seckey_create_rc4_salt();
1714
if (*salt == NULL) {
1718
param = nsspkcs5_NewParam(algorithm,*salt,1);
1719
if (param == NULL) {
1723
dest = nsspkcs5_CipherData(param, pwitem, der_item, PR_TRUE, NULL);
1728
rv = SECITEM_CopyItem(permarena, &epki->encryptedData, dest);
1729
if (rv != SECSuccess) {
1733
algid = nsspkcs5_CreateAlgorithmID(permarena, algorithm, param);
1734
if (algid == NULL) {
1739
rv = SECOID_CopyAlgorithmID(permarena, &epki->algorithm, algid);
1740
SECOID_DestroyAlgorithmID(algid, PR_TRUE);
1744
SECITEM_FreeItem(dest, PR_TRUE);
1747
nsspkcs5_DestroyPBEParameter(param);
1749
/* let success fall through */
1751
if(rv == SECFailure)
1753
PORT_FreeArena(permarena, PR_TRUE);
1756
SECITEM_FreeItem(*salt, PR_TRUE);
1759
if(temparena != NULL)
1760
PORT_FreeArena(temparena, PR_TRUE);
1766
seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SECItem *pwitem,
1767
NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update,
1768
SECOidTag algorithm)
1770
NSSLOWKEYDBKey *dbkey = NULL;
1771
NSSLOWKEYEncryptedPrivateKeyInfo *epki = NULL;
1772
PLArenaPool *arena = NULL;
1773
SECItem *dummy = NULL;
1774
SECItem *salt = NULL;
1775
SECStatus rv = SECFailure;
1777
if((keydb == NULL) || (index == NULL) || (pwitem == NULL) ||
1781
arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1785
dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
1788
dbkey->arena = arena;
1789
dbkey->nickname = nickname;
1791
/* TNH - for RC4, the salt should be created here */
1793
epki = seckey_encrypt_private_key(pk, pwitem, keydb, algorithm, &salt);
1799
rv = SECITEM_CopyItem(arena, &(dbkey->salt), salt);
1800
SECITEM_ZfreeItem(salt, PR_TRUE);
1803
dummy = SEC_ASN1EncodeItem(arena, &(dbkey->derPK), epki,
1804
nsslowkey_EncryptedPrivateKeyInfoTemplate);
1808
rv = put_dbkey(keydb, index, dbkey, update);
1810
/* let success fall through */
1813
PORT_FreeArena(arena, PR_TRUE);
1815
PORT_FreeArena(epki->arena, PR_TRUE);
1821
* Store a key in the database, indexed by its public key modulus.
1822
* Note that the nickname is optional. It was only used by keyutil.
1825
nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle,
1826
NSSLOWKEYPrivateKey *privkey,
1827
SECItem *pubKeyData,
1830
SECOidTag algorithm,
1836
if (handle == NULL) {
1837
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1841
/* set up db key and data */
1842
namekey.data = pubKeyData->data;
1843
namekey.size = pubKeyData->len;
1845
/* encrypt the private key */
1846
rv = seckey_put_private_key(handle, &namekey, pwitem, privkey, nickname,
1852
NSSLOWKEYPrivateKey *
1853
seckey_decrypt_private_key(NSSLOWKEYEncryptedPrivateKeyInfo *epki,
1856
NSSLOWKEYPrivateKey *pk = NULL;
1857
NSSLOWKEYPrivateKeyInfo *pki = NULL;
1858
SECStatus rv = SECFailure;
1859
SECOidTag algorithm;
1860
PLArenaPool *temparena = NULL, *permarena = NULL;
1861
SECItem *salt = NULL, *dest = NULL, *key = NULL;
1862
NSSPKCS5PBEParameter *param;
1863
#ifdef NSS_ENABLE_ECC
1864
ECPrivateKey *ecpriv;
1865
SECItem *fordebug = NULL;
1869
if((epki == NULL) || (pwitem == NULL))
1872
temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1873
permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1874
if((temparena == NULL) || (permarena == NULL))
1877
/* allocate temporary items */
1878
pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena,
1879
sizeof(NSSLOWKEYPrivateKeyInfo));
1881
/* allocate permanent arena items */
1882
pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(permarena,
1883
sizeof(NSSLOWKEYPrivateKey));
1885
if((pk == NULL) || (pki == NULL))
1888
pk->arena = permarena;
1890
algorithm = SECOID_GetAlgorithmTag(&(epki->algorithm));
1894
salt = SECITEM_DupItem(&epki->algorithm.parameters);
1897
key = seckey_create_rc4_key(pwitem, salt);
1900
dest = seckey_rc4_decode(key, &epki->encryptedData);
1904
SECITEM_ZfreeItem(salt, PR_TRUE);
1906
SECITEM_ZfreeItem(key, PR_TRUE);
1909
/* we depend on the fact that if this key was encoded with
1910
* DES, that the pw was also encoded with DES, so we don't have
1911
* to do the update here, the password code will handle it. */
1912
param = nsspkcs5_AlgidToParam(&epki->algorithm);
1913
if (param == NULL) {
1916
dest = nsspkcs5_CipherData(param, pwitem, &epki->encryptedData,
1918
nsspkcs5_DestroyPBEParameter(param);
1924
SECItem newPrivateKey;
1925
SECItem newAlgParms;
1927
SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1,
1930
rv = SEC_QuickDERDecodeItem(temparena, pki,
1931
nsslowkey_PrivateKeyInfoTemplate, dest);
1932
if(rv == SECSuccess)
1934
switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
1935
case SEC_OID_X500_RSA_ENCRYPTION:
1936
case SEC_OID_PKCS1_RSA_ENCRYPTION:
1937
pk->keyType = NSSLOWKEYRSAKey;
1938
prepare_low_rsa_priv_key_for_asn1(pk);
1939
if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
1940
&pki->privateKey) ) break;
1941
rv = SEC_QuickDERDecodeItem(permarena, pk,
1942
nsslowkey_RSAPrivateKeyTemplate,
1945
case SEC_OID_ANSIX9_DSA_SIGNATURE:
1946
pk->keyType = NSSLOWKEYDSAKey;
1947
prepare_low_dsa_priv_key_for_asn1(pk);
1948
if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
1949
&pki->privateKey) ) break;
1950
rv = SEC_QuickDERDecodeItem(permarena, pk,
1951
nsslowkey_DSAPrivateKeyTemplate,
1953
if (rv != SECSuccess)
1955
prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
1956
if (SECSuccess != SECITEM_CopyItem(permarena, &newAlgParms,
1957
&pki->algorithm.parameters) ) break;
1958
rv = SEC_QuickDERDecodeItem(permarena, &pk->u.dsa.params,
1959
nsslowkey_PQGParamsTemplate,
1962
case SEC_OID_X942_DIFFIE_HELMAN_KEY:
1963
pk->keyType = NSSLOWKEYDHKey;
1964
prepare_low_dh_priv_key_for_asn1(pk);
1965
if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
1966
&pki->privateKey) ) break;
1967
rv = SEC_QuickDERDecodeItem(permarena, pk,
1968
nsslowkey_DHPrivateKeyTemplate,
1971
#ifdef NSS_ENABLE_ECC
1972
case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
1973
pk->keyType = NSSLOWKEYECKey;
1974
prepare_low_ec_priv_key_for_asn1(pk);
1976
fordebug = &pki->privateKey;
1977
SEC_PRINT("seckey_decrypt_private_key()", "PrivateKey",
1978
pk->keyType, fordebug);
1979
if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
1980
&pki->privateKey) ) break;
1981
rv = SEC_QuickDERDecodeItem(permarena, pk,
1982
nsslowkey_ECPrivateKeyTemplate,
1984
if (rv != SECSuccess)
1987
prepare_low_ecparams_for_asn1(&pk->u.ec.ecParams);
1989
rv = SECITEM_CopyItem(permarena,
1990
&pk->u.ec.ecParams.DEREncoding,
1991
&pki->algorithm.parameters);
1993
if (rv != SECSuccess)
1996
/* Fill out the rest of EC params */
1997
rv = EC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding,
1998
&pk->u.ec.ecParams);
2000
if (rv != SECSuccess)
2004
* NOTE: Encoding of the publicValue is optional
2005
* so we need to be able to regenerate the publicValue
2006
* from the base point and the private key.
2008
* XXX This part of the code needs more testing.
2010
if (pk->u.ec.publicValue.len == 0) {
2011
rv = EC_NewKeyFromSeed(&pk->u.ec.ecParams,
2012
&ecpriv, pk->u.ec.privateValue.data,
2013
pk->u.ec.privateValue.len);
2014
if (rv == SECSuccess) {
2015
SECITEM_CopyItem(permarena, &pk->u.ec.publicValue,
2016
&(ecpriv->publicValue));
2017
PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
2020
/* If publicValue was filled as part of DER decoding,
2021
* change length in bits to length in bytes.
2023
pk->u.ec.publicValue.len >>= 3;
2027
#endif /* NSS_ENABLE_ECC */
2033
else if(PORT_GetError() == SEC_ERROR_BAD_DER)
2035
PORT_SetError(SEC_ERROR_BAD_PASSWORD);
2040
/* let success fall through */
2042
if(temparena != NULL)
2043
PORT_FreeArena(temparena, PR_TRUE);
2045
SECITEM_ZfreeItem(dest, PR_TRUE);
2047
if(rv != SECSuccess)
2049
if(permarena != NULL)
2050
PORT_FreeArena(permarena, PR_TRUE);
2057
static NSSLOWKEYPrivateKey *
2058
seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SECItem *pwitem)
2060
NSSLOWKEYPrivateKey *pk = NULL;
2061
NSSLOWKEYEncryptedPrivateKeyInfo *epki;
2062
PLArenaPool *temparena = NULL;
2064
SECOidTag algorithm;
2066
if( ( dbkey == NULL ) || ( pwitem == NULL ) ) {
2070
temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2071
if(temparena == NULL) {
2075
epki = (NSSLOWKEYEncryptedPrivateKeyInfo *)
2076
PORT_ArenaZAlloc(temparena, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo));
2082
rv = SEC_QuickDERDecodeItem(temparena, epki,
2083
nsslowkey_EncryptedPrivateKeyInfoTemplate,
2085
if(rv != SECSuccess) {
2089
algorithm = SECOID_GetAlgorithmTag(&(epki->algorithm));
2093
/* TNH - this code should derive the actual RC4 key from salt and
2095
rv = SECITEM_CopyItem(temparena, &(epki->algorithm.parameters),
2102
pk = seckey_decrypt_private_key(epki, pwitem);
2104
/* let success fall through */
2107
PORT_FreeArena(temparena, PR_TRUE);
2111
NSSLOWKEYPrivateKey *
2112
seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname,
2115
NSSLOWKEYDBKey *dbkey = NULL;
2116
NSSLOWKEYPrivateKey *pk = NULL;
2118
if( ( keydb == NULL ) || ( index == NULL ) || ( pwitem == NULL ) ) {
2122
dbkey = get_dbkey(keydb, index);
2128
if ( dbkey->nickname && ( dbkey->nickname[0] != 0 ) ) {
2129
*nickname = PORT_Strdup(dbkey->nickname);
2135
pk = seckey_decode_encrypted_private_key(dbkey, pwitem);
2137
/* let success fall through */
2140
if ( dbkey != NULL ) {
2141
sec_destroy_dbkey(dbkey);
2148
* used by pkcs11 to import keys into it's object format... In the future
2149
* we really need a better way to tie in...
2151
NSSLOWKEYPrivateKey *
2152
nsslowkey_DecryptKey(DBT *key, SECItem *pwitem,
2153
NSSLOWKEYDBHandle *handle) {
2154
return seckey_get_private_key(handle,key,NULL,pwitem);
2158
* Find a key in the database, indexed by its public key modulus
2159
* This is used to find keys that have been stored before their
2160
* certificate arrives. Once the certificate arrives the key
2161
* is looked up by the public modulus in the certificate, and the
2162
* re-stored by its nickname.
2164
NSSLOWKEYPrivateKey *
2165
nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus,
2169
NSSLOWKEYPrivateKey *pk = NULL;
2171
if (handle == NULL) {
2172
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2177
namekey.data = modulus->data;
2178
namekey.size = modulus->len;
2180
pk = seckey_get_private_key(handle, &namekey, NULL, pwitem);
2182
/* no need to free dbkey, since its on the stack, and the data it
2183
* points to is owned by the database
2189
nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle,
2190
SECItem *modulus, SECItem *pwitem)
2193
NSSLOWKEYPrivateKey *pk = NULL;
2194
char *nickname = NULL;
2196
if (handle == NULL) {
2197
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2202
namekey.data = modulus->data;
2203
namekey.size = modulus->len;
2205
pk = seckey_get_private_key(handle, &namekey, &nickname, pwitem);
2207
nsslowkey_DestroyPrivateKey(pk);
2210
/* no need to free dbkey, since its on the stack, and the data it
2211
* points to is owned by the database
2215
/* ===== ENCODING ROUTINES ===== */
2218
encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
2221
SECOidData *oidData;
2224
oidData = SECOID_FindOIDByTag(alg);
2225
if ( oidData == NULL ) {
2230
entry->len = 1 + oidData->oid.len + encCheck->len;
2232
entry->data = (unsigned char *)PORT_ArenaAlloc(arena, entry->len);
2234
entry->data = (unsigned char *)PORT_Alloc(entry->len);
2237
if ( entry->data == NULL ) {
2241
/* first length of oid */
2242
entry->data[0] = (unsigned char)oidData->oid.len;
2243
/* next oid itself */
2244
PORT_Memcpy(&entry->data[1], oidData->oid.data, oidData->oid.len);
2245
/* finally the encrypted check string */
2246
PORT_Memcpy(&entry->data[1+oidData->oid.len], encCheck->data,
2256
* Set up the password checker in the key database.
2257
* This is done by encrypting a known plaintext with the user's key.
2260
nsslowkey_SetKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle,
2261
SECItem *pwitem, SECOidTag algorithm)
2264
NSSPKCS5PBEParameter *param = NULL;
2265
SECStatus rv = SECFailure;
2266
NSSLOWKEYDBKey *dbkey = NULL;
2268
SECItem *salt = NULL;
2269
SECItem *dest = NULL, test_key;
2271
if (handle == NULL) {
2275
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2276
if ( arena == NULL ) {
2281
dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
2282
if ( dbkey == NULL ) {
2287
dbkey->arena = arena;
2290
checkkey.data = test_key.data = (unsigned char *)KEYDB_PW_CHECK_STRING;
2291
checkkey.size = test_key.len = KEYDB_PW_CHECK_LEN;
2293
salt = seckey_create_rc4_salt();
2299
param = nsspkcs5_NewParam(algorithm, salt, 1);
2300
if (param == NULL) {
2305
dest = nsspkcs5_CipherData(param, pwitem, &test_key, PR_TRUE, NULL);
2312
rv = SECITEM_CopyItem(arena, &dbkey->salt, salt);
2313
if (rv == SECFailure) {
2317
rv = encodePWCheckEntry(arena, &dbkey->derPK, algorithm, dest);
2319
if ( rv != SECSuccess ) {
2323
rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE);
2325
/* let success fall through */
2327
if ( arena != NULL ) {
2328
PORT_FreeArena(arena, PR_TRUE);
2331
if ( dest != NULL ) {
2332
SECITEM_ZfreeItem(dest, PR_TRUE);
2335
if ( salt != NULL ) {
2336
SECITEM_ZfreeItem(salt, PR_TRUE);
2339
if (param != NULL) {
2340
nsspkcs5_DestroyPBEParameter(param);
2347
seckey_CheckKeyDB1Password(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
2349
SECStatus rv = SECFailure;
2351
keyNode *node = NULL;
2352
NSSLOWKEYPrivateKey *privkey = NULL;
2359
/* traverse the database, collecting the keys of all records */
2360
keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2361
if ( keylist.arena == NULL )
2363
PORT_SetError(SEC_ERROR_NO_MEMORY);
2366
keylist.head = NULL;
2368
/* TNH - TraverseKeys should not be public, since it exposes
2369
the underlying DBT data type. */
2370
rv = nsslowkey_TraverseKeys(handle, sec_add_key_to_list, (void *)&keylist);
2371
if ( rv != SECSuccess )
2374
/* just get the first key from the list */
2375
node = keylist.head;
2377
/* no private keys, accept any password */
2382
privkey = seckey_get_private_key(handle, &node->key, NULL, pwitem);
2383
if (privkey == NULL) {
2388
/* if we can decrypt the private key, then we had the correct password */
2390
nsslowkey_DestroyPrivateKey(privkey);
2394
/* free the arena */
2395
if ( keylist.arena ) {
2396
PORT_FreeArena(keylist.arena, PR_FALSE);
2403
* check to see if the user has typed the right password
2406
nsslowkey_CheckKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
2410
NSSPKCS5PBEParameter *param = NULL;
2411
SECStatus rv = SECFailure;
2412
NSSLOWKEYDBKey *dbkey = NULL;
2413
SECItem *key = NULL;
2414
SECItem *dest = NULL;
2415
SECOidTag algorithm;
2418
PRBool update = PR_FALSE;
2421
if (handle == NULL) {
2425
checkkey.data = KEYDB_PW_CHECK_STRING;
2426
checkkey.size = KEYDB_PW_CHECK_LEN;
2428
dbkey = get_dbkey(handle, &checkkey);
2430
if ( dbkey == NULL ) {
2431
checkkey.data = KEYDB_FAKE_PW_CHECK_STRING;
2432
checkkey.size = KEYDB_FAKE_PW_CHECK_LEN;
2433
ret = keydb_Get(handle, &checkkey, &checkdata, 0 );
2437
/* if we have the fake PW_CHECK, then try to decode the key
2438
* rather than the pwcheck item.
2440
rv = seckey_CheckKeyDB1Password(handle,pwitem);
2441
if (rv == SECSuccess) {
2442
/* OK we have enough to complete our conversion */
2443
nsslowkey_UpdateKeyDBPass2(handle,pwitem);
2448
/* build the oid item */
2449
oid.len = dbkey->derPK.data[0];
2450
oid.data = &dbkey->derPK.data[1];
2452
/* make sure entry is the correct length
2453
* since we are probably using a block cipher, the block will be
2454
* padded, so we may get a bit more than the exact size we need.
2456
if ( dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 + oid.len ) ) {
2460
/* find the algorithm tag */
2461
algorithm = SECOID_FindOIDTag(&oid);
2463
/* make a secitem of the encrypted check string */
2464
encstring.len = dbkey->derPK.len - ( oid.len + 1 );
2465
encstring.data = &dbkey->derPK.data[oid.len+1];
2471
key = seckey_create_rc4_key(pwitem, &dbkey->salt);
2473
dest = seckey_rc4_decode(key, &encstring);
2474
SECITEM_FreeItem(key, PR_TRUE);
2478
param = nsspkcs5_NewParam(algorithm, &dbkey->salt, 1);
2479
if (param != NULL) {
2480
/* Decrypt - this function implements a workaround for
2481
* a previous coding error. It will decrypt values using
2482
* DES rather than 3DES, if the initial try at 3DES
2483
* decryption fails. In this case, the update flag is
2484
* set to TRUE. This indication is used later to force
2485
* an update of the database to "real" 3DES encryption.
2487
dest = nsspkcs5_CipherData(param, pwitem,
2488
&encstring, PR_FALSE, &update);
2489
nsspkcs5_DestroyPBEParameter(param);
2498
if ((dest->len == KEYDB_PW_CHECK_LEN) &&
2499
(PORT_Memcmp(dest->data,
2500
KEYDB_PW_CHECK_STRING, KEYDB_PW_CHECK_LEN) == 0)) {
2503
if ( algorithm == SEC_OID_RC4 ) {
2504
/* partially updated database */
2505
nsslowkey_UpdateKeyDBPass2(handle, pwitem);
2507
/* Force an update of the password to remove the incorrect DES
2508
* encryption (see the note above)
2511
(algorithm == SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC)) {
2512
/* data base was encoded with DES not triple des, fix it */
2513
nsslowkey_UpdateKeyDBPass2(handle,pwitem);
2518
sec_destroy_dbkey(dbkey);
2520
SECITEM_ZfreeItem(dest, PR_TRUE);
2527
* Change the database password and/or algorithm. This internal
2528
* routine does not check the old password. That must be done by
2532
ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle,
2533
SECItem *oldpwitem, SECItem *newpwitem,
2534
SECOidTag new_algorithm)
2538
keyNode *node = NULL;
2539
NSSLOWKEYPrivateKey *privkey = NULL;
2544
/* traverse the database, collecting the keys of all records */
2545
keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2546
if ( keylist.arena == NULL )
2548
PORT_SetError(SEC_ERROR_NO_MEMORY);
2551
keylist.head = NULL;
2553
rv = db_BeginTransaction(handle->db);
2554
if (rv != SECSuccess) {
2558
/* TNH - TraverseKeys should not be public, since it exposes
2559
the underlying DBT data type. */
2560
rv = nsslowkey_TraverseKeys(handle, sec_add_key_to_list, (void *)&keylist);
2561
if ( rv != SECSuccess )
2564
/* walk the list, re-encrypting each entry */
2565
node = keylist.head;
2566
while ( node != NULL )
2568
privkey = seckey_get_private_key(handle, &node->key, &nickname,
2571
if (privkey == NULL) {
2572
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2577
/* delete the old record */
2578
ret = keydb_Del(handle, &node->key, 0);
2580
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2585
/* get the public key, which we use as the database index */
2587
switch (privkey->keyType) {
2588
case NSSLOWKEYRSAKey:
2589
newkey.data = privkey->u.rsa.modulus.data;
2590
newkey.size = privkey->u.rsa.modulus.len;
2592
case NSSLOWKEYDSAKey:
2593
newkey.data = privkey->u.dsa.publicValue.data;
2594
newkey.size = privkey->u.dsa.publicValue.len;
2596
case NSSLOWKEYDHKey:
2597
newkey.data = privkey->u.dh.publicValue.data;
2598
newkey.size = privkey->u.dh.publicValue.len;
2600
#ifdef NSS_ENABLE_ECC
2601
case NSSLOWKEYECKey:
2602
newkey.data = privkey->u.ec.publicValue.data;
2603
newkey.size = privkey->u.ec.publicValue.len;
2605
#endif /* NSS_ENABLE_ECC */
2607
/* should we continue here and loose the key? */
2608
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2613
rv = seckey_put_private_key(handle, &newkey, newpwitem, privkey,
2614
nickname, PR_TRUE, new_algorithm);
2616
if ( rv != SECSuccess )
2618
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2627
rv = nsslowkey_SetKeyDBPasswordAlg(handle, newpwitem, new_algorithm);
2631
db_FinishTransaction(handle->db,rv != SECSuccess);
2633
/* free the arena */
2634
if ( keylist.arena ) {
2635
PORT_FreeArena(keylist.arena, PR_FALSE);
2642
* Re-encrypt the entire key database with a new password.
2643
* NOTE: The really should create a new database rather than doing it
2644
* in place in the original
2647
nsslowkey_ChangeKeyDBPassword(NSSLOWKEYDBHandle *handle,
2648
SECItem *oldpwitem, SECItem *newpwitem)
2652
if (handle == NULL) {
2653
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2658
rv = nsslowkey_CheckKeyDBPassword(handle, oldpwitem);
2659
if ( rv != SECSuccess ) {
2660
return(SECFailure); /* return rv? */
2663
rv = ChangeKeyDBPasswordAlg(handle, oldpwitem, newpwitem,
2664
nsslowkey_GetDefaultKeyDBAlg());
2671
#define MAX_DB_SIZE 0xffff
2673
* Clear out all the keys in the existing database
2676
nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle)
2682
if ( handle->db == NULL ) {
2686
if (handle->readOnly) {
2687
/* set an error code */
2691
if (handle->appname == NULL && handle->dbname == NULL) {
2695
keydb_Close(handle);
2696
if (handle->appname) {
2698
rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL);
2700
handle->db = dbopen( handle->dbname, NO_CREATE, 0600, DB_HASH, 0 );
2702
if (handle->db == NULL) {
2703
/* set an error code */
2707
rv = makeGlobalVersion(handle);
2708
if ( rv != SECSuccess ) {
2713
if (handle->global_salt) {
2714
rv = StoreKeyDBGlobalSalt(handle);
2716
rv = makeGlobalSalt(handle);
2717
if ( rv == SECSuccess ) {
2718
handle->global_salt = GetKeyDBGlobalSalt(handle);
2721
if ( rv != SECSuccess ) {
2726
/* sync the database */
2727
ret = keydb_Sync(handle, 0);
2728
db_InitComplete(handle->db);
2730
return (errors == 0 ? SECSuccess : SECFailure);
2734
keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
2738
PRLock *kdbLock = kdb->lock;
2741
PORT_Assert(kdbLock != NULL);
2744
ret = (* db->get)(db, key, data, flags);
2746
prstat = PZ_Unlock(kdbLock);
2752
keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
2756
PRLock *kdbLock = kdb->lock;
2759
PORT_Assert(kdbLock != NULL);
2762
ret = (* db->put)(db, key, data, flags);
2764
prstat = PZ_Unlock(kdbLock);
2770
keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags)
2774
PRLock *kdbLock = kdb->lock;
2777
PORT_Assert(kdbLock != NULL);
2780
ret = (* db->sync)(db, flags);
2782
prstat = PZ_Unlock(kdbLock);
2788
keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags)
2792
PRLock *kdbLock = kdb->lock;
2795
PORT_Assert(kdbLock != NULL);
2798
ret = (* db->del)(db, key, flags);
2800
prstat = PZ_Unlock(kdbLock);
2806
keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
2810
PRLock *kdbLock = kdb->lock;
2813
PORT_Assert(kdbLock != NULL);
2816
ret = (* db->seq)(db, key, data, flags);
2818
prstat = PZ_Unlock(kdbLock);
2824
keydb_Close(NSSLOWKEYDBHandle *kdb)
2827
PRLock *kdbLock = kdb->lock;
2830
PORT_Assert(kdbLock != NULL);
2835
prstat = PZ_Unlock(kdbLock);