~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/softoken/keydb.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
3
 *
 
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/
 
8
 *
 
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
 
12
 * License.
 
13
 *
 
14
 * The Original Code is the Netscape security libraries.
 
15
 *
 
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.
 
20
 *
 
21
 * Contributor(s):
 
22
 *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
 
23
 *
 
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.
 
35
 *
 
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 $ */
 
38
 
 
39
#include "lowkeyi.h"
 
40
#include "seccomon.h"
 
41
#include "sechash.h"
 
42
#include "secder.h"
 
43
#include "secasn1.h"
 
44
#include "secoid.h"
 
45
#include "blapi.h"
 
46
#include "secitem.h"
 
47
#include "pcert.h"
 
48
#include "mcom_db.h"
 
49
#include "lowpbe.h"
 
50
#include "secerr.h"
 
51
#include "cdbhdl.h"
 
52
#include "nsslocks.h"
 
53
 
 
54
#include "keydbi.h"
 
55
#include "softoken.h"
 
56
 
 
57
 
 
58
/*
 
59
 * Record keys for keydb
 
60
 */
 
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
 
67
 
 
68
/* Size of the global salt for key database */
 
69
#define SALT_LENGTH     16
 
70
 
 
71
const SEC_ASN1Template nsslowkey_AttributeTemplate[] = {
 
72
    { SEC_ASN1_SEQUENCE, 
 
73
        0, NULL, sizeof(NSSLOWKEYAttribute) },
 
74
    { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) },
 
75
    { SEC_ASN1_SET_OF, offsetof(NSSLOWKEYAttribute, attrValue), 
 
76
        SEC_AnyTemplate },
 
77
    { 0 }
 
78
};
 
79
 
 
80
const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = {
 
81
    { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate },
 
82
};
 
83
/* ASN1 Templates for new decoder/encoder */
 
84
const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = {
 
85
    { SEC_ASN1_SEQUENCE,
 
86
        0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) },
 
87
    { SEC_ASN1_INTEGER,
 
88
        offsetof(NSSLOWKEYPrivateKeyInfo,version) },
 
89
    { SEC_ASN1_INLINE,
 
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 },
 
97
    { 0 }
 
98
};
 
99
 
 
100
const SEC_ASN1Template nsslowkey_PointerToPrivateKeyInfoTemplate[] = {
 
101
    { SEC_ASN1_POINTER, 0, nsslowkey_PrivateKeyInfoTemplate }
 
102
};
 
103
 
 
104
const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = {
 
105
    { SEC_ASN1_SEQUENCE,
 
106
        0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) },
 
107
    { SEC_ASN1_INLINE,
 
108
        offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,algorithm),
 
109
        SECOID_AlgorithmIDTemplate },
 
110
    { SEC_ASN1_OCTET_STRING,
 
111
        offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,encryptedData) },
 
112
    { 0 }
 
113
};
 
114
 
 
115
const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = {
 
116
        { SEC_ASN1_POINTER, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate }
 
117
};
 
118
 
 
119
 
 
120
/* ====== Default key databse encryption algorithm ====== */
 
121
 
 
122
static SECOidTag defaultKeyDBAlg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
 
123
 
 
124
/*
 
125
 * Default algorithm for encrypting data in the key database
 
126
 */
 
127
SECOidTag
 
128
nsslowkey_GetDefaultKeyDBAlg(void)
 
129
{
 
130
    return(defaultKeyDBAlg);
 
131
}
 
132
 
 
133
void
 
134
nsslowkey_SetDefaultKeyDBAlg(SECOidTag alg)
 
135
{
 
136
    defaultKeyDBAlg = alg;
 
137
 
 
138
    return;
 
139
}
 
140
 
 
141
static void
 
142
sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey)
 
143
{
 
144
    if ( dbkey && dbkey->arena ) {
 
145
        PORT_FreeArena(dbkey->arena, PR_FALSE);
 
146
    }
 
147
}
 
148
 
 
149
static void
 
150
free_dbt(DBT *dbt)
 
151
{
 
152
    if ( dbt ) {
 
153
        PORT_Free(dbt->data);
 
154
        PORT_Free(dbt);
 
155
    }
 
156
    
 
157
    return;
 
158
}
 
159
 
 
160
static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 
 
161
                     unsigned int flags);
 
162
static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 
 
163
                     unsigned int flags);
 
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, 
 
167
                     unsigned int flags);
 
168
static void keydb_Close(NSSLOWKEYDBHandle *db);
 
169
 
 
170
static void
 
171
keydb_InitLocks(NSSLOWKEYDBHandle *handle) 
 
172
{
 
173
    if (handle->lock == NULL) {
 
174
        nss_InitLock(&handle->lock, nssILockKeyDB);
 
175
    }
 
176
 
 
177
    return;
 
178
}
 
179
 
 
180
static void
 
181
keydb_DestroyLocks(NSSLOWKEYDBHandle *handle)
 
182
{
 
183
    if (handle->lock != NULL) {
 
184
        PZ_DestroyLock(handle->lock);
 
185
        handle->lock = NULL;
 
186
    }
 
187
 
 
188
    return;
 
189
}
 
190
 
 
191
/*
 
192
 * format of key database entries for version 3 of database:
 
193
 *      byte offset     field
 
194
 *      -----------     -----
 
195
 *      0               version
 
196
 *      1               salt-len
 
197
 *      2               nn-len
 
198
 *      3..             salt-data
 
199
 *      ...             nickname
 
200
 *      ...             encrypted-key-data
 
201
 */
 
202
static DBT *
 
203
encode_dbkey(NSSLOWKEYDBKey *dbkey,unsigned char version)
 
204
{
 
205
    DBT *bufitem = NULL;
 
206
    unsigned char *buf;
 
207
    int nnlen;
 
208
    char *nn;
 
209
    
 
210
    bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT));
 
211
    if ( bufitem == NULL ) {
 
212
        goto loser;
 
213
    }
 
214
    
 
215
    if ( dbkey->nickname ) {
 
216
        nn = dbkey->nickname;
 
217
        nnlen = PORT_Strlen(nn) + 1;
 
218
    } else {
 
219
        nn = "";
 
220
        nnlen = 1;
 
221
    }
 
222
    
 
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;
 
226
    
 
227
    bufitem->data = (void *)PORT_ZAlloc(bufitem->size);
 
228
    if ( bufitem->data == NULL ) {
 
229
        goto loser;
 
230
    }
 
231
 
 
232
    buf = (unsigned char *)bufitem->data;
 
233
    
 
234
    /* set version number */
 
235
    buf[0] = version;
 
236
 
 
237
    /* set length of salt */
 
238
    PORT_Assert(dbkey->salt.len < 256);
 
239
    buf[1] = dbkey->salt.len;
 
240
 
 
241
    /* set length of nickname */
 
242
    PORT_Assert(nnlen < 256);
 
243
    buf[2] = nnlen;
 
244
 
 
245
    /* copy salt */
 
246
    PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len);
 
247
 
 
248
    /* copy nickname */
 
249
    PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen);
 
250
 
 
251
    /* copy encrypted key */
 
252
    PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data,
 
253
              dbkey->derPK.len);
 
254
    
 
255
    return(bufitem);
 
256
    
 
257
loser:
 
258
    if ( bufitem ) {
 
259
        free_dbt(bufitem);
 
260
    }
 
261
    
 
262
    return(NULL);
 
263
}
 
264
 
 
265
static NSSLOWKEYDBKey *
 
266
decode_dbkey(DBT *bufitem, int expectedVersion)
 
267
{
 
268
    NSSLOWKEYDBKey *dbkey;
 
269
    PLArenaPool *arena = NULL;
 
270
    unsigned char *buf;
 
271
    int version;
 
272
    int keyoff;
 
273
    int nnlen;
 
274
    int saltoff;
 
275
    
 
276
    buf = (unsigned char *)bufitem->data;
 
277
 
 
278
    version = buf[0];
 
279
    
 
280
    if ( version != expectedVersion ) {
 
281
        goto loser;
 
282
    }
 
283
    
 
284
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
285
    if ( arena == NULL ) {
 
286
        goto loser;
 
287
    }
 
288
    
 
289
    dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
 
290
    if ( dbkey == NULL ) {
 
291
        goto loser;
 
292
    }
 
293
 
 
294
    dbkey->arena = arena;
 
295
    dbkey->salt.data = NULL;
 
296
    dbkey->derPK.data = NULL;
 
297
    
 
298
    dbkey->salt.len = buf[1];
 
299
    dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len);
 
300
    if ( dbkey->salt.data == NULL ) {
 
301
        goto loser;
 
302
    }
 
303
 
 
304
    saltoff = 2;
 
305
    keyoff = 2 + dbkey->salt.len;
 
306
    
 
307
    if ( expectedVersion >= 3 ) {
 
308
        nnlen = buf[2];
 
309
        if ( nnlen ) {
 
310
            dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1);
 
311
            if ( dbkey->nickname ) {
 
312
                PORT_Memcpy(dbkey->nickname, &buf[keyoff+1], nnlen);
 
313
            }
 
314
        }
 
315
        keyoff += ( nnlen + 1 );
 
316
        saltoff = 3;
 
317
    }
 
318
 
 
319
    PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len);
 
320
    
 
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 ) {
 
324
        goto loser;
 
325
    }
 
326
    
 
327
    PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len);
 
328
    
 
329
    return(dbkey);
 
330
    
 
331
loser:
 
332
 
 
333
    if ( arena ) {
 
334
        PORT_FreeArena(arena, PR_FALSE);
 
335
    }
 
336
    
 
337
    return(NULL);
 
338
}
 
339
 
 
340
static NSSLOWKEYDBKey *
 
341
get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index)
 
342
{
 
343
    NSSLOWKEYDBKey *dbkey;
 
344
    DBT entry;
 
345
    int ret;
 
346
    
 
347
    /* get it from the database */
 
348
    ret = keydb_Get(handle, index, &entry, 0);
 
349
    if ( ret ) {
 
350
        PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
351
        return NULL;
 
352
    }
 
353
 
 
354
    /* set up dbkey struct */
 
355
 
 
356
    dbkey = decode_dbkey(&entry, handle->version);
 
357
 
 
358
    return(dbkey);
 
359
}
 
360
 
 
361
static SECStatus
 
362
put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update)
 
363
{
 
364
    DBT *keydata = NULL;
 
365
    int status;
 
366
    
 
367
    keydata = encode_dbkey(dbkey, handle->version);
 
368
    if ( keydata == NULL ) {
 
369
        goto loser;
 
370
    }
 
371
    
 
372
    /* put it in the database */
 
373
    if ( update ) {
 
374
        status = keydb_Put(handle, index, keydata, 0);
 
375
    } else {
 
376
        status = keydb_Put(handle, index, keydata, R_NOOVERWRITE);
 
377
    }
 
378
    
 
379
    if ( status ) {
 
380
        goto loser;
 
381
    }
 
382
 
 
383
    /* sync the database */
 
384
    status = keydb_Sync(handle, 0);
 
385
    if ( status ) {
 
386
        goto loser;
 
387
    }
 
388
 
 
389
    free_dbt(keydata);
 
390
    return(SECSuccess);
 
391
 
 
392
loser:
 
393
    if ( keydata ) {
 
394
        free_dbt(keydata);
 
395
    }
 
396
    
 
397
    return(SECFailure);
 
398
}
 
399
 
 
400
SECStatus
 
401
nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle, 
 
402
                 SECStatus (* keyfunc)(DBT *k, DBT *d, void *pdata),
 
403
                 void *udata )
 
404
{
 
405
    DBT data;
 
406
    DBT key;
 
407
    SECStatus status;
 
408
    int ret;
 
409
 
 
410
    if (handle == NULL) {
 
411
        return(SECFailure);
 
412
    }
 
413
 
 
414
    ret = keydb_Seq(handle, &key, &data, R_FIRST);
 
415
    if ( ret ) {
 
416
        return(SECFailure);
 
417
    }
 
418
    
 
419
    do {
 
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 ) {
 
424
                    continue;
 
425
                }
 
426
            }
 
427
 
 
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 ) {
 
432
                    continue;
 
433
                }
 
434
            }
 
435
            
 
436
            status = (* keyfunc)(&key, &data, udata);
 
437
            if (status != SECSuccess) {
 
438
                return(status);
 
439
            }
 
440
        }
 
441
    } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
 
442
 
 
443
    return(SECSuccess);
 
444
}
 
445
 
 
446
typedef struct keyNode {
 
447
    struct keyNode *next;
 
448
    DBT key;
 
449
} keyNode;
 
450
 
 
451
typedef struct {
 
452
    PLArenaPool *arena;
 
453
    keyNode *head;
 
454
} keyList;
 
455
 
 
456
static SECStatus
 
457
sec_add_key_to_list(DBT *key, DBT *data, void *arg)
 
458
{
 
459
    keyList *keylist;
 
460
    keyNode *node;
 
461
    void *keydata;
 
462
    
 
463
    keylist = (keyList *)arg;
 
464
 
 
465
    /* allocate the node struct */
 
466
    node = (keyNode*)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode));
 
467
    if ( node == NULL ) {
 
468
        return(SECFailure);
 
469
    }
 
470
    
 
471
    /* allocate room for key data */
 
472
    keydata = PORT_ArenaZAlloc(keylist->arena, key->size);
 
473
    if ( keydata == NULL ) {
 
474
        return(SECFailure);
 
475
    }
 
476
 
 
477
    /* link node into list */
 
478
    node->next = keylist->head;
 
479
    keylist->head = node;
 
480
 
 
481
    /* copy key into node */
 
482
    PORT_Memcpy(keydata, key->data, key->size);
 
483
    node->key.size = key->size;
 
484
    node->key.data = keydata;
 
485
    
 
486
    return(SECSuccess);
 
487
}
 
488
 
 
489
static SECItem *
 
490
decodeKeyDBGlobalSalt(DBT *saltData)
 
491
{
 
492
    SECItem *saltitem;
 
493
    
 
494
    saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
 
495
    if ( saltitem == NULL ) {
 
496
        return(NULL);
 
497
    }
 
498
    
 
499
    saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size);
 
500
    if ( saltitem->data == NULL ) {
 
501
        PORT_Free(saltitem);
 
502
        return(NULL);
 
503
    }
 
504
    
 
505
    saltitem->len = saltData->size;
 
506
    PORT_Memcpy(saltitem->data, saltData->data, saltitem->len);
 
507
    
 
508
    return(saltitem);
 
509
}
 
510
 
 
511
static SECItem *
 
512
GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
 
513
{
 
514
    DBT saltKey;
 
515
    DBT saltData;
 
516
    int ret;
 
517
    
 
518
    saltKey.data = SALT_STRING;
 
519
    saltKey.size = sizeof(SALT_STRING) - 1;
 
520
 
 
521
    ret = keydb_Get(handle, &saltKey, &saltData, 0);
 
522
    if ( ret ) {
 
523
        return(NULL);
 
524
    }
 
525
 
 
526
    return(decodeKeyDBGlobalSalt(&saltData));
 
527
}
 
528
 
 
529
static SECStatus
 
530
StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
 
531
{
 
532
    DBT saltKey;
 
533
    DBT saltData;
 
534
    int status;
 
535
    
 
536
    saltKey.data = SALT_STRING;
 
537
    saltKey.size = sizeof(SALT_STRING) - 1;
 
538
 
 
539
    saltData.data = (void *)handle->global_salt->data;
 
540
    saltData.size = handle->global_salt->len;
 
541
 
 
542
    /* put global salt into the database now */
 
543
    status = keydb_Put(handle, &saltKey, &saltData, 0);
 
544
    if ( status ) {
 
545
        return(SECFailure);
 
546
    }
 
547
 
 
548
    return(SECSuccess);
 
549
}
 
550
 
 
551
static SECStatus
 
552
makeGlobalVersion(NSSLOWKEYDBHandle *handle)
 
553
{
 
554
    unsigned char version;
 
555
    DBT versionData;
 
556
    DBT versionKey;
 
557
    int status;
 
558
    
 
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;
 
564
                
 
565
    /* put version string into the database now */
 
566
    status = keydb_Put(handle, &versionKey, &versionData, 0);
 
567
    if ( status ) {
 
568
        return(SECFailure);
 
569
    }
 
570
    handle->version = version;
 
571
 
 
572
    return(SECSuccess);
 
573
}
 
574
 
 
575
 
 
576
static SECStatus
 
577
makeGlobalSalt(NSSLOWKEYDBHandle *handle)
 
578
{
 
579
    DBT saltKey;
 
580
    DBT saltData;
 
581
    unsigned char saltbuf[16];
 
582
    int status;
 
583
    SECStatus rv;
 
584
    
 
585
    saltKey.data = SALT_STRING;
 
586
    saltKey.size = sizeof(SALT_STRING) - 1;
 
587
 
 
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;
 
593
        return(rv);
 
594
    }
 
595
 
 
596
    /* put global salt into the database now */
 
597
    status = keydb_Put(handle, &saltKey, &saltData, 0);
 
598
    if ( status ) {
 
599
        return(SECFailure);
 
600
    }
 
601
 
 
602
    return(SECSuccess);
 
603
}
 
604
 
 
605
static SECStatus
 
606
ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle,
 
607
                       SECItem *oldpwitem, SECItem *newpwitem,
 
608
                       SECOidTag new_algorithm);
 
609
/*
 
610
 * Second pass of updating the key db.  This time we have a password.
 
611
 */
 
612
static SECStatus
 
613
nsslowkey_UpdateKeyDBPass2(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
 
614
{
 
615
    SECStatus rv;
 
616
    
 
617
    rv = ChangeKeyDBPasswordAlg(handle, pwitem, pwitem,
 
618
                             nsslowkey_GetDefaultKeyDBAlg());
 
619
    
 
620
    return(rv);
 
621
}
 
622
 
 
623
static SECStatus
 
624
encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
 
625
                   SECItem *encCheck);
 
626
 
 
627
static unsigned char
 
628
nsslowkey_version(NSSLOWKEYDBHandle *handle)
 
629
{
 
630
    DBT versionKey;
 
631
    DBT versionData;
 
632
    int ret;
 
633
    versionKey.data = VERSION_STRING;
 
634
    versionKey.size = sizeof(VERSION_STRING)-1;
 
635
 
 
636
    if (handle->db == NULL) {
 
637
        return 255;
 
638
    }
 
639
 
 
640
    /* lookup version string in database */
 
641
    ret = keydb_Get( handle, &versionKey, &versionData, 0 );
 
642
 
 
643
    /* error accessing the database */
 
644
    if ( ret < 0 ) {
 
645
        return 255;
 
646
    }
 
647
 
 
648
    if ( ret >= 1 ) {
 
649
        return 0;
 
650
    }
 
651
    return *( (unsigned char *)versionData.data);
 
652
}
 
653
 
 
654
static PRBool
 
655
seckey_HasAServerKey(NSSLOWKEYDBHandle *handle)
 
656
{
 
657
    DBT key;
 
658
    DBT data;
 
659
    int ret;
 
660
    PRBool found = PR_FALSE;
 
661
 
 
662
    ret = keydb_Seq(handle, &key, &data, R_FIRST);
 
663
    if ( ret ) {
 
664
        return PR_FALSE;
 
665
    }
 
666
    
 
667
    do {
 
668
        /* skip version record */
 
669
        if ( data.size > 1 ) {
 
670
            /* skip salt */
 
671
            if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
 
672
                if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
 
673
                    continue;
 
674
                }
 
675
            }
 
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 ) {
 
680
                    continue;
 
681
                }
 
682
            }
 
683
 
 
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.
 
688
             */
 
689
            if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
 
690
                continue;
 
691
            }
 
692
 
 
693
            if (PORT_Strcmp(key.data,"Server-Key") == 0) {
 
694
                found = PR_TRUE;
 
695
                break;
 
696
            }
 
697
            
 
698
        }
 
699
    } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
 
700
 
 
701
    return found;
 
702
}
 
703
 
 
704
/* forward declare local create function */
 
705
static NSSLOWKEYDBHandle * nsslowkey_NewHandle(DB *dbHandle);
 
706
 
 
707
/*
 
708
 * currently updates key database from v2 to v3
 
709
 */
 
710
static SECStatus
 
711
nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle)
 
712
{
 
713
    SECStatus rv;
 
714
    DBT checkKey;
 
715
    DBT checkData;
 
716
    DBT saltKey;
 
717
    DBT saltData;
 
718
    DBT key;
 
719
    DBT data;
 
720
    unsigned char version;
 
721
    NSSLOWKEYDBKey *dbkey = NULL;
 
722
    NSSLOWKEYDBHandle *update = NULL;
 
723
    SECItem *oldSalt = NULL;
 
724
    int ret;
 
725
    SECItem checkitem;
 
726
 
 
727
    if ( handle->updatedb == NULL ) {
 
728
        return SECSuccess;
 
729
    }
 
730
 
 
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) {
 
735
        return SECSuccess;
 
736
    }
 
737
 
 
738
    /* update has now inherited the database handle */
 
739
    handle->updatedb = NULL;
 
740
 
 
741
    /*
 
742
     * check the version record
 
743
     */
 
744
    version = nsslowkey_version(update);
 
745
    if (version != 2) {
 
746
        goto done;
 
747
    }
 
748
 
 
749
    saltKey.data = SALT_STRING;
 
750
    saltKey.size = sizeof(SALT_STRING) - 1;
 
751
 
 
752
    ret = keydb_Get(update, &saltKey, &saltData, 0);
 
753
    if ( ret ) {
 
754
        /* no salt in old db, so it is corrupted */
 
755
        goto done;
 
756
    }
 
757
 
 
758
    oldSalt = decodeKeyDBGlobalSalt(&saltData);
 
759
    if ( oldSalt == NULL ) {
 
760
        /* bad salt in old db, so it is corrupted */
 
761
        goto done;
 
762
    }
 
763
 
 
764
    /*
 
765
     * look for a pw check entry
 
766
     */
 
767
    checkKey.data = KEYDB_PW_CHECK_STRING;
 
768
    checkKey.size = KEYDB_PW_CHECK_LEN;
 
769
    
 
770
    ret = keydb_Get(update, &checkKey, &checkData, 0 );
 
771
    if (ret) {
 
772
        /*
 
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.
 
777
         */
 
778
        if (seckey_HasAServerKey(update)) {
 
779
            DBT fcheckKey;
 
780
            DBT fcheckData;
 
781
 
 
782
            /*
 
783
             * include a fake string
 
784
             */
 
785
            fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING;
 
786
            fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN;
 
787
            fcheckData.data = "1";
 
788
            fcheckData.size = 1;
 
789
            /* put global salt into the new database now */
 
790
            ret = keydb_Put( handle, &saltKey, &saltData, 0);
 
791
            if ( ret ) {
 
792
                goto done;
 
793
            }
 
794
            ret = keydb_Put( handle, &fcheckKey, &fcheckData, 0);
 
795
            if ( ret ) {
 
796
                goto done;
 
797
            }
 
798
        } else {
 
799
            goto done;
 
800
        }
 
801
    } else {
 
802
        /* put global salt into the new database now */
 
803
        ret = keydb_Put( handle, &saltKey, &saltData, 0);
 
804
        if ( ret ) {
 
805
            goto done;
 
806
        }
 
807
 
 
808
        dbkey = decode_dbkey(&checkData, 2);
 
809
        if ( dbkey == NULL ) {
 
810
            goto done;
 
811
        }
 
812
        checkitem = dbkey->derPK;
 
813
        dbkey->derPK.data = NULL;
 
814
    
 
815
        /* format the new pw check entry */
 
816
        rv = encodePWCheckEntry(NULL, &dbkey->derPK, SEC_OID_RC4, &checkitem);
 
817
        if ( rv != SECSuccess ) {
 
818
            goto done;
 
819
        }
 
820
 
 
821
        rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE);
 
822
        if ( rv != SECSuccess ) {
 
823
            goto done;
 
824
        }
 
825
 
 
826
        /* free the dbkey */
 
827
        sec_destroy_dbkey(dbkey);
 
828
        dbkey = NULL;
 
829
    }
 
830
    
 
831
    
 
832
    /* now traverse the database */
 
833
    ret = keydb_Seq(update, &key, &data, R_FIRST);
 
834
    if ( ret ) {
 
835
        goto done;
 
836
    }
 
837
    
 
838
    do {
 
839
        /* skip version record */
 
840
        if ( data.size > 1 ) {
 
841
            /* skip salt */
 
842
            if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
 
843
                if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
 
844
                    continue;
 
845
                }
 
846
            }
 
847
            /* skip pw check entry */
 
848
            if ( key.size == checkKey.size ) {
 
849
                if ( PORT_Memcmp(key.data, checkKey.data, key.size) == 0 ) {
 
850
                    continue;
 
851
                }
 
852
            }
 
853
 
 
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.
 
858
             */
 
859
            if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
 
860
                continue;
 
861
            }
 
862
            
 
863
            dbkey = decode_dbkey(&data, 2);
 
864
            if ( dbkey == NULL ) {
 
865
                continue;
 
866
            }
 
867
 
 
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.
 
872
             */
 
873
            dbkey->nickname = (char *)key.data;
 
874
            rv = put_dbkey(handle, &key, dbkey, PR_FALSE);
 
875
            dbkey->nickname = NULL;
 
876
 
 
877
            sec_destroy_dbkey(dbkey);
 
878
        }
 
879
    } while ( keydb_Seq(update, &key, &data, R_NEXT) == 0 );
 
880
 
 
881
    dbkey = NULL;
 
882
 
 
883
done:
 
884
    /* sync the database */
 
885
    ret = keydb_Sync(handle, 0);
 
886
 
 
887
    nsslowkey_CloseKeyDB(update);
 
888
    
 
889
    if ( oldSalt ) {
 
890
        SECITEM_FreeItem(oldSalt, PR_TRUE);
 
891
    }
 
892
    
 
893
    if ( dbkey ) {
 
894
        sec_destroy_dbkey(dbkey);
 
895
    }
 
896
 
 
897
    return(SECSuccess);
 
898
}
 
899
 
 
900
static SECStatus
 
901
openNewDB(const char *appName, const char *prefix, const char *dbname, 
 
902
        NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg)
 
903
{
 
904
    SECStatus rv = SECFailure;
 
905
    int status = RDB_FAIL;
 
906
    char *updname = NULL;
 
907
    DB *updatedb = NULL;
 
908
    PRBool updated = PR_FALSE;
 
909
    int ret;
 
910
 
 
911
    if (appName) {
 
912
        handle->db = rdbopen( appName, prefix, "key", NO_CREATE, &status);
 
913
    } else {
 
914
        handle->db = dbopen( dbname, NO_CREATE, 0600, DB_HASH, 0 );
 
915
    }
 
916
    /* if create fails then we lose */
 
917
    if ( handle->db == NULL ) {
 
918
        return (status == RDB_RETRY) ? SECWouldBlock: SECFailure;
 
919
    }
 
920
 
 
921
    rv = db_BeginTransaction(handle->db);
 
922
    if (rv != SECSuccess) {
 
923
        db_InitComplete(handle->db);
 
924
        return rv;
 
925
    }
 
926
 
 
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);
 
933
        return SECSuccess;
 
934
    }
 
935
 
 
936
    /*
 
937
     * if we are creating a multiaccess database, see if there is a
 
938
     * local database we can update from.
 
939
     */
 
940
    if (appName) {
 
941
        NSSLOWKEYDBHandle *updateHandle;
 
942
        updatedb = dbopen( dbname, NO_RDONLY, 0600, DB_HASH, 0 );
 
943
        if (!updatedb) {
 
944
            goto noupdate;
 
945
        }
 
946
 
 
947
        /* nsslowkey_version needs a full handle because it calls
 
948
         * the kdb_Get() function, which needs to lock.
 
949
         */
 
950
        updateHandle = nsslowkey_NewHandle(updatedb);
 
951
        if (!updateHandle) {
 
952
            updatedb->close(updatedb);
 
953
            goto noupdate;
 
954
        }
 
955
 
 
956
        handle->version = nsslowkey_version(updateHandle);
 
957
        if (handle->version != NSSLOWKEY_DB_FILE_VERSION) {
 
958
            nsslowkey_CloseKeyDB(updateHandle);
 
959
            goto noupdate;
 
960
        }
 
961
 
 
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);
 
967
        return SECSuccess;
 
968
    }
 
969
noupdate:
 
970
 
 
971
    /* update the version number */
 
972
    rv = makeGlobalVersion(handle);
 
973
    if ( rv != SECSuccess ) {
 
974
        goto loser;
 
975
    }
 
976
 
 
977
    /*
 
978
     * try to update from v2 db
 
979
     */
 
980
    updname = (*namecb)(cbarg, 2);
 
981
    if ( updname != NULL ) {
 
982
        handle->updatedb = dbopen( updname, NO_RDONLY, 0600, DB_HASH, 0 );
 
983
        PORT_Free( updname );
 
984
 
 
985
        if ( handle->updatedb ) {
 
986
            /*
 
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
 
990
             * update later
 
991
             */
 
992
            rv = nsslowkey_UpdateKeyDBPass1(handle);
 
993
            if ( rv == SECSuccess ) {
 
994
                updated = PR_TRUE;
 
995
            }
 
996
        }
 
997
            
 
998
    }
 
999
 
 
1000
    /* we are using the old salt if we updated from an old db */
 
1001
    if ( ! updated ) {
 
1002
        rv = makeGlobalSalt(handle);
 
1003
        if ( rv != SECSuccess ) {
 
1004
           goto loser;
 
1005
        }
 
1006
    }
 
1007
        
 
1008
    /* sync the database */
 
1009
    ret = keydb_Sync(handle, 0);
 
1010
    if ( ret ) {
 
1011
        rv = SECFailure;
 
1012
        goto loser;
 
1013
    }
 
1014
    rv = SECSuccess;
 
1015
 
 
1016
loser:
 
1017
    db_FinishTransaction(handle->db, rv != SECSuccess);
 
1018
    db_InitComplete(handle->db);
 
1019
    return rv;
 
1020
}
 
1021
 
 
1022
 
 
1023
static DB *
 
1024
openOldDB(const char *appName, const char *prefix, const char *dbname, 
 
1025
                                        PRBool openflags) {
 
1026
    DB *db = NULL;
 
1027
 
 
1028
    if (appName) {
 
1029
        db = rdbopen( appName, prefix, "key", openflags, NULL);
 
1030
    } else {
 
1031
        db = dbopen( dbname, openflags, 0600, DB_HASH, 0 );
 
1032
    }
 
1033
 
 
1034
    return db;
 
1035
}
 
1036
 
 
1037
/* check for correct version number */
 
1038
static PRBool
 
1039
verifyVersion(NSSLOWKEYDBHandle *handle)
 
1040
{
 
1041
    int version = nsslowkey_version(handle);
 
1042
 
 
1043
    handle->version = version;
 
1044
    if (version != NSSLOWKEY_DB_FILE_VERSION ) {
 
1045
        if (handle->db) {
 
1046
            keydb_Close(handle);
 
1047
            handle->db = NULL;
 
1048
        }
 
1049
    }
 
1050
    return handle->db != NULL;
 
1051
}
 
1052
 
 
1053
static NSSLOWKEYDBHandle *
 
1054
nsslowkey_NewHandle(DB *dbHandle)
 
1055
{
 
1056
    NSSLOWKEYDBHandle *handle;
 
1057
    handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc (sizeof(NSSLOWKEYDBHandle));
 
1058
    if (handle == NULL) {
 
1059
        PORT_SetError (SEC_ERROR_NO_MEMORY);
 
1060
        return NULL;
 
1061
    }
 
1062
 
 
1063
    handle->appname = NULL;
 
1064
    handle->dbname = NULL;
 
1065
    handle->global_salt = NULL;
 
1066
    handle->updatedb = NULL;
 
1067
    handle->db = dbHandle;
 
1068
    handle->ref = 1;
 
1069
 
 
1070
    keydb_InitLocks(handle);
 
1071
    return handle;
 
1072
}
 
1073
 
 
1074
NSSLOWKEYDBHandle *
 
1075
nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix,
 
1076
                                NSSLOWKEYDBNameFunc namecb, void *cbarg)
 
1077
{
 
1078
    NSSLOWKEYDBHandle *handle = NULL;
 
1079
    SECStatus rv;
 
1080
    int openflags;
 
1081
    char *dbname = NULL;
 
1082
 
 
1083
 
 
1084
    handle = nsslowkey_NewHandle(NULL);
 
1085
 
 
1086
    openflags = readOnly ? NO_RDONLY : NO_RDWR;
 
1087
 
 
1088
 
 
1089
    dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION);
 
1090
    if ( dbname == NULL ) {
 
1091
        goto loser;
 
1092
    }
 
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;
 
1097
 
 
1098
 
 
1099
 
 
1100
    handle->db = openOldDB(appName, prefix, dbname, openflags);
 
1101
    if (handle->db) {
 
1102
        verifyVersion(handle);
 
1103
        if (handle->version == 255) {
 
1104
            goto loser;
 
1105
        }
 
1106
    }
 
1107
 
 
1108
    /* if first open fails, try to create a new DB */
 
1109
    if ( handle->db == NULL ) {
 
1110
        if ( readOnly ) {
 
1111
            goto loser;
 
1112
        }
 
1113
 
 
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) {
 
1122
                goto loser;
 
1123
            }
 
1124
        } else if (rv != SECSuccess) {
 
1125
            goto loser;
 
1126
        }
 
1127
    }
 
1128
 
 
1129
    handle->global_salt = GetKeyDBGlobalSalt(handle);
 
1130
    if ( dbname )
 
1131
        PORT_Free( dbname );
 
1132
    return handle;
 
1133
 
 
1134
loser:
 
1135
 
 
1136
    if ( dbname )
 
1137
        PORT_Free( dbname );
 
1138
    PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
1139
    nsslowkey_CloseKeyDB(handle);
 
1140
    return NULL;
 
1141
}
 
1142
 
 
1143
/*
 
1144
 * Close the database
 
1145
 */
 
1146
void
 
1147
nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle)
 
1148
{
 
1149
    if (handle != NULL) {
 
1150
        if (handle->db != NULL) {
 
1151
            keydb_Close(handle);
 
1152
        }
 
1153
        if (handle->updatedb) {
 
1154
            handle->updatedb->close(handle->updatedb);
 
1155
        }
 
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);
 
1160
        }
 
1161
        keydb_DestroyLocks(handle);
 
1162
            
 
1163
        PORT_Free(handle);
 
1164
    }
 
1165
}
 
1166
 
 
1167
/* Get the key database version */
 
1168
int
 
1169
nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle)
 
1170
{
 
1171
    PORT_Assert(handle != NULL);
 
1172
 
 
1173
    return handle->version;
 
1174
}
 
1175
 
 
1176
/*
 
1177
 * Delete a private key that was stored in the database
 
1178
 */
 
1179
SECStatus
 
1180
nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, SECItem *pubkey)
 
1181
{
 
1182
    DBT namekey;
 
1183
    int ret;
 
1184
 
 
1185
    if (handle == NULL) {
 
1186
        PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
1187
        return(SECFailure);
 
1188
    }
 
1189
 
 
1190
    /* set up db key and data */
 
1191
    namekey.data = pubkey->data;
 
1192
    namekey.size = pubkey->len;
 
1193
 
 
1194
    /* delete it from the database */
 
1195
    ret = keydb_Del(handle, &namekey, 0);
 
1196
    if ( ret ) {
 
1197
        PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
1198
        return(SECFailure);
 
1199
    }
 
1200
 
 
1201
    /* sync the database */
 
1202
    ret = keydb_Sync(handle, 0);
 
1203
    if ( ret ) {
 
1204
        PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
1205
        return(SECFailure);
 
1206
    }
 
1207
 
 
1208
    return(SECSuccess);
 
1209
}
 
1210
 
 
1211
/*
 
1212
 * Store a key in the database, indexed by its public key modulus.(value!)
 
1213
 */
 
1214
SECStatus
 
1215
nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle, 
 
1216
                           NSSLOWKEYPrivateKey *privkey,
 
1217
                           SECItem *pubKeyData,
 
1218
                           char *nickname,
 
1219
                           SECItem *arg)
 
1220
{
 
1221
    return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 
 
1222
             nickname, arg, nsslowkey_GetDefaultKeyDBAlg(),PR_FALSE);
 
1223
}
 
1224
 
 
1225
SECStatus
 
1226
nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle, 
 
1227
                           NSSLOWKEYPrivateKey *privkey,
 
1228
                           SECItem *pubKeyData,
 
1229
                           char *nickname,
 
1230
                           SECItem *arg)
 
1231
{
 
1232
    return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 
 
1233
             nickname, arg, nsslowkey_GetDefaultKeyDBAlg(),PR_TRUE);
 
1234
}
 
1235
 
 
1236
/* see if the symetric CKA_ID already Exists.
 
1237
 */
 
1238
PRBool
 
1239
nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id)
 
1240
{
 
1241
    DBT namekey;
 
1242
    DBT dummy;
 
1243
    int status;
 
1244
 
 
1245
    namekey.data = (char *)id->data;
 
1246
    namekey.size = id->len;
 
1247
    status = keydb_Get(handle, &namekey, &dummy, 0);
 
1248
    if ( status ) {
 
1249
        return PR_FALSE;
 
1250
    }
 
1251
    
 
1252
    return PR_TRUE;
 
1253
}
 
1254
 
 
1255
/* see if the public key for this cert is in the database filed
 
1256
 * by modulus
 
1257
 */
 
1258
PRBool
 
1259
nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert)
 
1260
{
 
1261
    NSSLOWKEYPublicKey *pubkey = NULL;
 
1262
    DBT namekey;
 
1263
    DBT dummy;
 
1264
    int status;
 
1265
    
 
1266
    /* get cert's public key */
 
1267
    pubkey = nsslowcert_ExtractPublicKey(cert);
 
1268
    if ( pubkey == NULL ) {
 
1269
        return PR_FALSE;
 
1270
    }
 
1271
 
 
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;
 
1277
        break;
 
1278
      case NSSLOWKEYDSAKey:
 
1279
        namekey.data = pubkey->u.dsa.publicValue.data;
 
1280
        namekey.size = pubkey->u.dsa.publicValue.len;
 
1281
        break;
 
1282
      case NSSLOWKEYDHKey:
 
1283
        namekey.data = pubkey->u.dh.publicValue.data;
 
1284
        namekey.size = pubkey->u.dh.publicValue.len;
 
1285
        break;
 
1286
#ifdef NSS_ENABLE_ECC
 
1287
      case NSSLOWKEYECKey:
 
1288
        namekey.data = pubkey->u.ec.publicValue.data;
 
1289
        namekey.size = pubkey->u.ec.publicValue.len;
 
1290
        break;
 
1291
#endif /* NSS_ENABLE_ECC */
 
1292
      default:
 
1293
        /* XXX We don't do Fortezza or DH yet. */
 
1294
        return PR_FALSE;
 
1295
    }
 
1296
 
 
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);
 
1303
    }
 
1304
 
 
1305
    status = keydb_Get(handle, &namekey, &dummy, 0);
 
1306
    /* some databases have the key stored as a signed value */
 
1307
    if (status) {
 
1308
        unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size+1);
 
1309
        if (buf) {
 
1310
            PORT_Memcpy(&buf[1], namekey.data, namekey.size);
 
1311
            buf[0] = 0;
 
1312
            namekey.data = buf;
 
1313
            namekey.size ++;
 
1314
            status = keydb_Get(handle, &namekey, &dummy, 0);
 
1315
            PORT_Free(buf);
 
1316
        }
 
1317
    }
 
1318
    nsslowkey_DestroyPublicKey(pubkey);
 
1319
    if ( status ) {
 
1320
        return PR_FALSE;
 
1321
    }
 
1322
    
 
1323
    return PR_TRUE;
 
1324
}
 
1325
 
 
1326
/*
 
1327
 * check to see if the user has a password
 
1328
 */
 
1329
SECStatus
 
1330
nsslowkey_HasKeyDBPassword(NSSLOWKEYDBHandle *handle)
 
1331
{
 
1332
    DBT checkkey, checkdata;
 
1333
    int ret;
 
1334
 
 
1335
    if (handle == NULL) {
 
1336
        return(SECFailure);
 
1337
    }
 
1338
 
 
1339
    checkkey.data = KEYDB_PW_CHECK_STRING;
 
1340
    checkkey.size = KEYDB_PW_CHECK_LEN;
 
1341
    
 
1342
    ret = keydb_Get(handle, &checkkey, &checkdata, 0 );
 
1343
    if ( ret ) {
 
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 );
 
1348
        if ( ret ) {
 
1349
            return(SECFailure);
 
1350
        }
 
1351
    }
 
1352
 
 
1353
    return(SECSuccess);
 
1354
}
 
1355
 
 
1356
/*
 
1357
 * Set up the password checker in the key database.
 
1358
 * This is done by encrypting a known plaintext with the user's key.
 
1359
 */
 
1360
SECStatus
 
1361
nsslowkey_SetKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
 
1362
{
 
1363
    return nsslowkey_SetKeyDBPasswordAlg(handle, pwitem,
 
1364
                                      nsslowkey_GetDefaultKeyDBAlg());
 
1365
}
 
1366
 
 
1367
static SECStatus
 
1368
HashPassword(unsigned char *hashresult, char *pw, SECItem *salt)
 
1369
{
 
1370
    SHA1Context *cx;
 
1371
    unsigned int outlen;
 
1372
    cx = SHA1_NewContext();
 
1373
    if ( cx == NULL ) {
 
1374
        return(SECFailure);
 
1375
    }
 
1376
    
 
1377
    SHA1_Begin(cx);
 
1378
    if ( ( salt != NULL ) && ( salt->data != NULL ) ) {
 
1379
        SHA1_Update(cx, salt->data, salt->len);
 
1380
    }
 
1381
    
 
1382
    SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw));
 
1383
    SHA1_End(cx, hashresult, &outlen, SHA1_LENGTH);
 
1384
    
 
1385
    SHA1_DestroyContext(cx, PR_TRUE);
 
1386
    
 
1387
    return(SECSuccess);
 
1388
}
 
1389
 
 
1390
SECItem *
 
1391
nsslowkey_HashPassword(char *pw, SECItem *salt)
 
1392
{
 
1393
    SECItem *pwitem;
 
1394
    SECStatus rv;
 
1395
    
 
1396
    pwitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
 
1397
    if ( pwitem == NULL ) {
 
1398
        return(NULL);
 
1399
    }
 
1400
    pwitem->len = SHA1_LENGTH;
 
1401
    pwitem->data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);
 
1402
    if ( pwitem->data == NULL ) {
 
1403
        PORT_Free(pwitem);
 
1404
        return(NULL);
 
1405
    }
 
1406
    if ( pw ) {
 
1407
        rv = HashPassword(pwitem->data, pw, salt);
 
1408
        if ( rv != SECSuccess ) {
 
1409
            SECITEM_ZfreeItem(pwitem, PR_TRUE);
 
1410
            return(NULL);
 
1411
        }
 
1412
    }
 
1413
    
 
1414
    return(pwitem);
 
1415
}
 
1416
 
 
1417
/* Derive the actual password value for the database from a pw string */
 
1418
SECItem *
 
1419
nsslowkey_DeriveKeyDBPassword(NSSLOWKEYDBHandle *keydb, char *pw)
 
1420
{
 
1421
    PORT_Assert(keydb != NULL);
 
1422
    PORT_Assert(pw != NULL);
 
1423
    if (keydb == NULL || pw == NULL) return(NULL);
 
1424
 
 
1425
    return nsslowkey_HashPassword(pw, keydb->global_salt);
 
1426
}
 
1427
 
 
1428
/*
 
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?
 
1431
 * database
 
1432
 */
 
1433
SECItem *
 
1434
seckey_create_rc4_key(SECItem *pwitem, SECItem *salt)
 
1435
{
 
1436
    MD5Context *md5 = NULL;
 
1437
    unsigned int part;
 
1438
    SECStatus rv = SECFailure;
 
1439
    SECItem *key = NULL;
 
1440
 
 
1441
    key = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
 
1442
    if(key != NULL)
 
1443
    {
 
1444
        key->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
 
1445
                MD5_LENGTH);
 
1446
        key->len = MD5_LENGTH;
 
1447
        if(key->data != NULL)
 
1448
        {
 
1449
            md5 = MD5_NewContext();
 
1450
            if ( md5 != NULL ) 
 
1451
            {
 
1452
                MD5_Begin(md5);
 
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);
 
1457
                rv = SECSuccess;
 
1458
            }
 
1459
        }
 
1460
        
 
1461
        if(rv != SECSuccess)
 
1462
        {
 
1463
            SECITEM_FreeItem(key, PR_TRUE);
 
1464
            key = NULL;
 
1465
        }
 
1466
    }
 
1467
 
 
1468
    return key;
 
1469
}
 
1470
 
 
1471
SECItem *
 
1472
seckey_create_rc4_salt(void)
 
1473
{
 
1474
    SECItem *salt = NULL;
 
1475
    SECStatus rv = SECFailure;
 
1476
 
 
1477
    salt = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
 
1478
    if(salt == NULL)
 
1479
        return NULL;
 
1480
 
 
1481
    salt->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
 
1482
        SALT_LENGTH);
 
1483
    if(salt->data != NULL)
 
1484
    {
 
1485
        salt->len = SALT_LENGTH;
 
1486
        rv = RNG_GenerateGlobalRandomBytes(salt->data, salt->len);
 
1487
        if(rv != SECSuccess)
 
1488
            sftk_fatalError = PR_TRUE;
 
1489
    }
 
1490
        
 
1491
    if(rv != SECSuccess)
 
1492
    {
 
1493
        SECITEM_FreeItem(salt, PR_TRUE);
 
1494
        salt = NULL;
 
1495
    }
 
1496
 
 
1497
    return salt;
 
1498
}
 
1499
 
 
1500
SECItem *
 
1501
seckey_rc4_decode(SECItem *key, SECItem *src)
 
1502
{
 
1503
    SECItem *dest = NULL;
 
1504
    RC4Context *ctxt = NULL;
 
1505
    SECStatus rv = SECFailure;
 
1506
 
 
1507
    if((key == NULL) || (src == NULL))
 
1508
        return NULL;
 
1509
 
 
1510
    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
 
1511
    if(dest == NULL)
 
1512
        return NULL;
 
1513
 
 
1514
    dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
 
1515
        (src->len + 64));  /* TNH - padding? */
 
1516
    if(dest->data != NULL)
 
1517
    {
 
1518
        ctxt = RC4_CreateContext(key->data, key->len);
 
1519
        if(ctxt != NULL)
 
1520
        {
 
1521
            rv = RC4_Decrypt(ctxt, dest->data, &dest->len,
 
1522
                    src->len + 64, src->data, src->len);
 
1523
            RC4_DestroyContext(ctxt, PR_TRUE);
 
1524
        }
 
1525
    }
 
1526
 
 
1527
    if(rv == SECFailure)
 
1528
        if(dest != NULL)
 
1529
        {
 
1530
            SECITEM_FreeItem(dest, PR_TRUE);
 
1531
            dest = NULL;
 
1532
        }
 
1533
 
 
1534
    return dest;
 
1535
}
 
1536
 
 
1537
 
 
1538
#ifdef EC_DEBUG
 
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]); \
 
1544
    } \
 
1545
    printf("\n") 
 
1546
#else
 
1547
#define SEC_PRINT(a, b, c, d) 
 
1548
#endif /* EC_DEBUG */
 
1549
 
 
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)
 
1556
{
 
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;
 
1567
    int savelen;
 
1568
    int i;
 
1569
#endif
 
1570
 
 
1571
    *salt = NULL;
 
1572
    permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
 
1573
    if(permarena == NULL)
 
1574
        return NULL;
 
1575
 
 
1576
    temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
 
1577
    if(temparena == NULL)
 
1578
        goto loser;
 
1579
 
 
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))
 
1587
        goto loser;
 
1588
 
 
1589
    epki->arena = permarena;
 
1590
 
 
1591
    /* setup private key info */
 
1592
    dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version), 
 
1593
        NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
 
1594
    if(dummy == NULL)
 
1595
        goto loser;
 
1596
 
 
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) {
 
1604
            rv = SECFailure;
 
1605
            goto loser;
 
1606
        }
 
1607
        
 
1608
        rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 
 
1609
                                   SEC_OID_PKCS1_RSA_ENCRYPTION, 0);
 
1610
        if (rv == SECFailure) {
 
1611
            goto loser;
 
1612
        }
 
1613
        
 
1614
        break;
 
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) {
 
1620
            rv = SECFailure;
 
1621
            goto loser;
 
1622
        }
 
1623
        
 
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) {
 
1628
            rv = SECFailure;
 
1629
            goto loser;
 
1630
        }
 
1631
        
 
1632
        rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
 
1633
                                   SEC_OID_ANSIX9_DSA_SIGNATURE, dummy);
 
1634
        if (rv == SECFailure) {
 
1635
            goto loser;
 
1636
        }
 
1637
        
 
1638
        break;
 
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) {
 
1644
            rv = SECFailure;
 
1645
            goto loser;
 
1646
        }
 
1647
 
 
1648
        rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
 
1649
                                   SEC_OID_X942_DIFFIE_HELMAN_KEY, dummy);
 
1650
        if (rv == SECFailure) {
 
1651
            goto loser;
 
1652
        }
 
1653
        break;
 
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.
 
1660
         *
 
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.
 
1664
         */
 
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;
 
1672
 
 
1673
        if (dummy == NULL) {
 
1674
            rv = SECFailure;
 
1675
            goto loser;
 
1676
        }
 
1677
 
 
1678
        dummy = &pk->u.ec.ecParams.DEREncoding;
 
1679
 
 
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);
 
1683
 
 
1684
        if (rv == SECFailure) {
 
1685
            goto loser;
 
1686
        }
 
1687
        
 
1688
        fordebug = &(pki->privateKey);
 
1689
        SEC_PRINT("seckey_encrypt_private_key()", "PrivateKey", 
 
1690
                  pk->keyType, fordebug);
 
1691
 
 
1692
        break;
 
1693
#endif /* NSS_ENABLE_ECC */
 
1694
      default:
 
1695
        /* We don't support DH or Fortezza private keys yet */
 
1696
        PORT_Assert(PR_FALSE);
 
1697
        break;
 
1698
    }
 
1699
 
 
1700
    /* setup encrypted private key info */
 
1701
    dummy = SEC_ASN1EncodeItem(temparena, der_item, pki, 
 
1702
        nsslowkey_PrivateKeyInfoTemplate);
 
1703
 
 
1704
    SEC_PRINT("seckey_encrypt_private_key()", "PrivateKeyInfo", 
 
1705
              pk->keyType, der_item);
 
1706
 
 
1707
    if(dummy == NULL) {
 
1708
        rv = SECFailure;
 
1709
        goto loser;
 
1710
    }
 
1711
 
 
1712
    rv = SECFailure; /* assume failure */
 
1713
    *salt = seckey_create_rc4_salt();
 
1714
    if (*salt == NULL) {
 
1715
        goto loser;
 
1716
    }
 
1717
 
 
1718
    param = nsspkcs5_NewParam(algorithm,*salt,1);
 
1719
    if (param == NULL) {
 
1720
        goto loser;
 
1721
    }
 
1722
 
 
1723
    dest = nsspkcs5_CipherData(param, pwitem, der_item, PR_TRUE, NULL);
 
1724
    if (dest == NULL) {
 
1725
        goto loser;
 
1726
    }
 
1727
 
 
1728
    rv = SECITEM_CopyItem(permarena, &epki->encryptedData, dest);
 
1729
    if (rv != SECSuccess) {
 
1730
        goto loser;
 
1731
    }
 
1732
 
 
1733
    algid = nsspkcs5_CreateAlgorithmID(permarena, algorithm, param);
 
1734
    if (algid == NULL) {
 
1735
        rv = SECFailure;
 
1736
        goto loser;
 
1737
    }
 
1738
 
 
1739
    rv = SECOID_CopyAlgorithmID(permarena, &epki->algorithm, algid);
 
1740
    SECOID_DestroyAlgorithmID(algid, PR_TRUE);
 
1741
 
 
1742
loser:
 
1743
    if(dest != NULL)
 
1744
        SECITEM_FreeItem(dest, PR_TRUE);
 
1745
 
 
1746
    if(param != NULL)
 
1747
       nsspkcs5_DestroyPBEParameter(param);
 
1748
 
 
1749
    /* let success fall through */
 
1750
 
 
1751
    if(rv == SECFailure)
 
1752
    {
 
1753
        PORT_FreeArena(permarena, PR_TRUE);
 
1754
        epki = NULL;
 
1755
        if(*salt != NULL)
 
1756
            SECITEM_FreeItem(*salt, PR_TRUE);
 
1757
    }
 
1758
 
 
1759
    if(temparena != NULL)
 
1760
        PORT_FreeArena(temparena, PR_TRUE);
 
1761
 
 
1762
    return epki;
 
1763
}
 
1764
 
 
1765
static SECStatus 
 
1766
seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SECItem *pwitem,
 
1767
                       NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update,
 
1768
                       SECOidTag algorithm)
 
1769
{
 
1770
    NSSLOWKEYDBKey *dbkey = NULL;
 
1771
    NSSLOWKEYEncryptedPrivateKeyInfo *epki = NULL;
 
1772
    PLArenaPool  *arena = NULL;
 
1773
    SECItem *dummy = NULL;
 
1774
    SECItem *salt = NULL;
 
1775
    SECStatus rv = SECFailure;
 
1776
 
 
1777
    if((keydb == NULL) || (index == NULL) || (pwitem == NULL) ||
 
1778
        (pk == NULL))
 
1779
        return SECFailure;
 
1780
        
 
1781
    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
 
1782
    if(arena == NULL)
 
1783
        return SECFailure;
 
1784
 
 
1785
    dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
 
1786
    if(dbkey == NULL)
 
1787
        goto loser;
 
1788
    dbkey->arena = arena;
 
1789
    dbkey->nickname = nickname;
 
1790
 
 
1791
    /* TNH - for RC4, the salt should be created here */
 
1792
        
 
1793
    epki = seckey_encrypt_private_key(pk, pwitem, keydb, algorithm, &salt);
 
1794
    if(epki == NULL)
 
1795
        goto loser;
 
1796
 
 
1797
    if(salt != NULL)
 
1798
    {
 
1799
        rv = SECITEM_CopyItem(arena, &(dbkey->salt), salt);
 
1800
        SECITEM_ZfreeItem(salt, PR_TRUE);
 
1801
    }
 
1802
 
 
1803
    dummy = SEC_ASN1EncodeItem(arena, &(dbkey->derPK), epki, 
 
1804
        nsslowkey_EncryptedPrivateKeyInfoTemplate);
 
1805
    if(dummy == NULL)
 
1806
        rv = SECFailure;
 
1807
    else
 
1808
        rv = put_dbkey(keydb, index, dbkey, update);
 
1809
 
 
1810
    /* let success fall through */
 
1811
loser:
 
1812
    if(arena != NULL)
 
1813
        PORT_FreeArena(arena, PR_TRUE);
 
1814
    if(epki != NULL)
 
1815
        PORT_FreeArena(epki->arena, PR_TRUE);
 
1816
 
 
1817
    return rv;
 
1818
}
 
1819
 
 
1820
/*
 
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.
 
1823
 */
 
1824
SECStatus
 
1825
nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, 
 
1826
                              NSSLOWKEYPrivateKey *privkey,
 
1827
                              SECItem *pubKeyData,
 
1828
                              char *nickname,
 
1829
                              SECItem *pwitem,
 
1830
                              SECOidTag algorithm,
 
1831
                              PRBool update)
 
1832
{
 
1833
    DBT namekey;
 
1834
    SECStatus rv;
 
1835
 
 
1836
    if (handle == NULL) {
 
1837
        PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
1838
        return(SECFailure);
 
1839
    }
 
1840
 
 
1841
    /* set up db key and data */
 
1842
    namekey.data = pubKeyData->data;
 
1843
    namekey.size = pubKeyData->len;
 
1844
 
 
1845
    /* encrypt the private key */
 
1846
    rv = seckey_put_private_key(handle, &namekey, pwitem, privkey, nickname,
 
1847
                                update, algorithm);
 
1848
    
 
1849
    return(rv);
 
1850
}
 
1851
 
 
1852
NSSLOWKEYPrivateKey *
 
1853
seckey_decrypt_private_key(NSSLOWKEYEncryptedPrivateKeyInfo *epki,
 
1854
                           SECItem *pwitem)
 
1855
{
 
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;
 
1866
    int i;
 
1867
#endif
 
1868
 
 
1869
    if((epki == NULL) || (pwitem == NULL))
 
1870
        goto loser;
 
1871
 
 
1872
    temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
 
1873
    permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
 
1874
    if((temparena == NULL) || (permarena == NULL))
 
1875
        goto loser;
 
1876
 
 
1877
    /* allocate temporary items */
 
1878
    pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 
 
1879
        sizeof(NSSLOWKEYPrivateKeyInfo));
 
1880
 
 
1881
    /* allocate permanent arena items */
 
1882
    pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(permarena,
 
1883
        sizeof(NSSLOWKEYPrivateKey));
 
1884
 
 
1885
    if((pk == NULL) || (pki == NULL))
 
1886
        goto loser;
 
1887
 
 
1888
    pk->arena = permarena;
 
1889
        
 
1890
    algorithm = SECOID_GetAlgorithmTag(&(epki->algorithm));
 
1891
    switch(algorithm)
 
1892
    {
 
1893
        case SEC_OID_RC4:
 
1894
            salt = SECITEM_DupItem(&epki->algorithm.parameters);
 
1895
            if(salt != NULL)
 
1896
            {
 
1897
                key = seckey_create_rc4_key(pwitem, salt);
 
1898
                if(key != NULL)
 
1899
                {
 
1900
                    dest = seckey_rc4_decode(key, &epki->encryptedData);
 
1901
                }
 
1902
            }   
 
1903
            if(salt != NULL)
 
1904
                SECITEM_ZfreeItem(salt, PR_TRUE);
 
1905
            if(key != NULL)
 
1906
                SECITEM_ZfreeItem(key, PR_TRUE);
 
1907
            break;
 
1908
        default:
 
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) {
 
1914
                break;
 
1915
            }
 
1916
            dest = nsspkcs5_CipherData(param, pwitem, &epki->encryptedData, 
 
1917
                                                        PR_FALSE, NULL);
 
1918
            nsspkcs5_DestroyPBEParameter(param);
 
1919
            break;
 
1920
    }
 
1921
 
 
1922
    if(dest != NULL)
 
1923
    {
 
1924
        SECItem newPrivateKey;
 
1925
        SECItem newAlgParms;
 
1926
 
 
1927
        SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1,
 
1928
                  dest);
 
1929
 
 
1930
        rv = SEC_QuickDERDecodeItem(temparena, pki, 
 
1931
            nsslowkey_PrivateKeyInfoTemplate, dest);
 
1932
        if(rv == SECSuccess)
 
1933
        {
 
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,
 
1943
                                        &newPrivateKey);
 
1944
                break;
 
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,
 
1952
                                        &newPrivateKey);
 
1953
                if (rv != SECSuccess)
 
1954
                    goto loser;
 
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,
 
1960
                                        &newAlgParms);
 
1961
                break;
 
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,
 
1969
                                        &newPrivateKey);
 
1970
                break;
 
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);
 
1975
 
 
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,
 
1983
                                        &newPrivateKey);
 
1984
                if (rv != SECSuccess)
 
1985
                    goto loser;
 
1986
 
 
1987
                prepare_low_ecparams_for_asn1(&pk->u.ec.ecParams);
 
1988
 
 
1989
                rv = SECITEM_CopyItem(permarena, 
 
1990
                    &pk->u.ec.ecParams.DEREncoding, 
 
1991
                    &pki->algorithm.parameters);
 
1992
 
 
1993
                if (rv != SECSuccess)
 
1994
                    goto loser;
 
1995
 
 
1996
                /* Fill out the rest of EC params */
 
1997
                rv = EC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding,
 
1998
                                   &pk->u.ec.ecParams);
 
1999
 
 
2000
                if (rv != SECSuccess)
 
2001
                    goto loser;
 
2002
 
 
2003
                /* 
 
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.
 
2007
                 *
 
2008
                 * XXX This part of the code needs more testing.
 
2009
                 */
 
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);
 
2018
                    }
 
2019
                } else {
 
2020
                    /* If publicValue was filled as part of DER decoding,
 
2021
                     * change length in bits to length in bytes.
 
2022
                     */
 
2023
                    pk->u.ec.publicValue.len >>= 3;
 
2024
                }
 
2025
 
 
2026
                break;
 
2027
#endif /* NSS_ENABLE_ECC */
 
2028
              default:
 
2029
                rv = SECFailure;
 
2030
                break;
 
2031
            }
 
2032
        }
 
2033
        else if(PORT_GetError() == SEC_ERROR_BAD_DER)
 
2034
        {
 
2035
            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
 
2036
            goto loser;
 
2037
        }
 
2038
    }
 
2039
 
 
2040
    /* let success fall through */
 
2041
loser:
 
2042
    if(temparena != NULL)
 
2043
        PORT_FreeArena(temparena, PR_TRUE);
 
2044
    if(dest != NULL)
 
2045
        SECITEM_ZfreeItem(dest, PR_TRUE);
 
2046
 
 
2047
    if(rv != SECSuccess)
 
2048
    {
 
2049
        if(permarena != NULL)
 
2050
            PORT_FreeArena(permarena, PR_TRUE);
 
2051
        pk = NULL;
 
2052
    }
 
2053
 
 
2054
    return pk;
 
2055
}
 
2056
 
 
2057
static NSSLOWKEYPrivateKey *
 
2058
seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SECItem *pwitem)
 
2059
{
 
2060
    NSSLOWKEYPrivateKey *pk = NULL;
 
2061
    NSSLOWKEYEncryptedPrivateKeyInfo *epki;
 
2062
    PLArenaPool *temparena = NULL;
 
2063
    SECStatus rv;
 
2064
    SECOidTag algorithm;
 
2065
 
 
2066
    if( ( dbkey == NULL ) || ( pwitem == NULL ) ) {
 
2067
        return NULL;
 
2068
    }
 
2069
 
 
2070
    temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
2071
    if(temparena == NULL) {
 
2072
        return NULL;
 
2073
    }
 
2074
 
 
2075
    epki = (NSSLOWKEYEncryptedPrivateKeyInfo *)
 
2076
        PORT_ArenaZAlloc(temparena, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo));
 
2077
 
 
2078
    if(epki == NULL) {
 
2079
        goto loser;
 
2080
    }
 
2081
 
 
2082
    rv = SEC_QuickDERDecodeItem(temparena, epki,
 
2083
                            nsslowkey_EncryptedPrivateKeyInfoTemplate,
 
2084
                            &(dbkey->derPK)); 
 
2085
    if(rv != SECSuccess) {
 
2086
        goto loser;
 
2087
    }
 
2088
 
 
2089
    algorithm = SECOID_GetAlgorithmTag(&(epki->algorithm));
 
2090
    switch(algorithm)
 
2091
    {
 
2092
      case SEC_OID_RC4:
 
2093
        /* TNH - this code should derive the actual RC4 key from salt and
 
2094
           pwitem */
 
2095
        rv = SECITEM_CopyItem(temparena, &(epki->algorithm.parameters),
 
2096
                              &(dbkey->salt));
 
2097
        break;
 
2098
      default:
 
2099
        break;
 
2100
    }
 
2101
 
 
2102
    pk = seckey_decrypt_private_key(epki, pwitem);
 
2103
 
 
2104
    /* let success fall through */
 
2105
loser:
 
2106
 
 
2107
    PORT_FreeArena(temparena, PR_TRUE);
 
2108
    return pk;
 
2109
}
 
2110
 
 
2111
NSSLOWKEYPrivateKey *
 
2112
seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname,
 
2113
                       SECItem *pwitem)
 
2114
{
 
2115
    NSSLOWKEYDBKey *dbkey = NULL;
 
2116
    NSSLOWKEYPrivateKey *pk = NULL;
 
2117
 
 
2118
    if( ( keydb == NULL ) || ( index == NULL ) || ( pwitem == NULL ) ) {
 
2119
        return NULL;
 
2120
    }
 
2121
 
 
2122
    dbkey = get_dbkey(keydb, index);
 
2123
    if(dbkey == NULL) {
 
2124
        goto loser;
 
2125
    }
 
2126
    
 
2127
    if ( nickname ) {
 
2128
        if ( dbkey->nickname && ( dbkey->nickname[0] != 0 ) ) {
 
2129
            *nickname = PORT_Strdup(dbkey->nickname);
 
2130
        } else {
 
2131
            *nickname = NULL;
 
2132
        }
 
2133
    }
 
2134
    
 
2135
    pk = seckey_decode_encrypted_private_key(dbkey, pwitem);
 
2136
    
 
2137
    /* let success fall through */
 
2138
loser:
 
2139
 
 
2140
    if ( dbkey != NULL ) {
 
2141
        sec_destroy_dbkey(dbkey);
 
2142
    }
 
2143
 
 
2144
    return pk;
 
2145
}
 
2146
 
 
2147
/*
 
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...
 
2150
 */
 
2151
NSSLOWKEYPrivateKey *
 
2152
nsslowkey_DecryptKey(DBT *key, SECItem *pwitem,
 
2153
                                         NSSLOWKEYDBHandle *handle) {
 
2154
    return seckey_get_private_key(handle,key,NULL,pwitem);
 
2155
}
 
2156
 
 
2157
/*
 
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.
 
2163
 */
 
2164
NSSLOWKEYPrivateKey *
 
2165
nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus,
 
2166
                                                         SECItem *pwitem)
 
2167
{
 
2168
    DBT namekey;
 
2169
    NSSLOWKEYPrivateKey *pk = NULL;
 
2170
 
 
2171
    if (handle == NULL) {
 
2172
        PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
2173
        return NULL;
 
2174
    }
 
2175
 
 
2176
    /* set up db key */
 
2177
    namekey.data = modulus->data;
 
2178
    namekey.size = modulus->len;
 
2179
 
 
2180
    pk = seckey_get_private_key(handle, &namekey, NULL, pwitem);
 
2181
    
 
2182
    /* no need to free dbkey, since its on the stack, and the data it
 
2183
     * points to is owned by the database
 
2184
     */
 
2185
    return(pk);
 
2186
}
 
2187
 
 
2188
char *
 
2189
nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, 
 
2190
                                        SECItem *modulus, SECItem *pwitem)
 
2191
{
 
2192
    DBT namekey;
 
2193
    NSSLOWKEYPrivateKey *pk = NULL;
 
2194
    char *nickname = NULL;
 
2195
 
 
2196
    if (handle == NULL) {
 
2197
        PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
2198
        return NULL;
 
2199
    }
 
2200
 
 
2201
    /* set up db key */
 
2202
    namekey.data = modulus->data;
 
2203
    namekey.size = modulus->len;
 
2204
 
 
2205
    pk = seckey_get_private_key(handle, &namekey, &nickname, pwitem);
 
2206
    if (pk) {
 
2207
        nsslowkey_DestroyPrivateKey(pk);
 
2208
    }
 
2209
    
 
2210
    /* no need to free dbkey, since its on the stack, and the data it
 
2211
     * points to is owned by the database
 
2212
     */
 
2213
    return(nickname);
 
2214
}
 
2215
/* ===== ENCODING ROUTINES ===== */
 
2216
 
 
2217
static SECStatus
 
2218
encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
 
2219
                   SECItem *encCheck)
 
2220
{
 
2221
    SECOidData *oidData;
 
2222
    SECStatus rv;
 
2223
    
 
2224
    oidData = SECOID_FindOIDByTag(alg);
 
2225
    if ( oidData == NULL ) {
 
2226
        rv = SECFailure;
 
2227
        goto loser;
 
2228
    }
 
2229
 
 
2230
    entry->len = 1 + oidData->oid.len + encCheck->len;
 
2231
    if ( arena ) {
 
2232
        entry->data = (unsigned char *)PORT_ArenaAlloc(arena, entry->len);
 
2233
    } else {
 
2234
        entry->data = (unsigned char *)PORT_Alloc(entry->len);
 
2235
    }
 
2236
    
 
2237
    if ( entry->data == NULL ) {
 
2238
        goto loser;
 
2239
    }
 
2240
        
 
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,
 
2247
                encCheck->len);
 
2248
 
 
2249
    return(SECSuccess);
 
2250
 
 
2251
loser:
 
2252
    return(SECFailure);
 
2253
}
 
2254
 
 
2255
/*
 
2256
 * Set up the password checker in the key database.
 
2257
 * This is done by encrypting a known plaintext with the user's key.
 
2258
 */
 
2259
SECStatus
 
2260
nsslowkey_SetKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, 
 
2261
                           SECItem *pwitem, SECOidTag algorithm)
 
2262
{
 
2263
    DBT checkkey;
 
2264
    NSSPKCS5PBEParameter *param = NULL;
 
2265
    SECStatus rv = SECFailure;
 
2266
    NSSLOWKEYDBKey *dbkey = NULL;
 
2267
    PLArenaPool *arena;
 
2268
    SECItem *salt = NULL;
 
2269
    SECItem *dest = NULL, test_key;
 
2270
    
 
2271
    if (handle == NULL) {
 
2272
        return(SECFailure);
 
2273
    }
 
2274
 
 
2275
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
2276
    if ( arena == NULL ) {
 
2277
        rv = SECFailure;
 
2278
        goto loser;
 
2279
    }
 
2280
    
 
2281
    dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
 
2282
    if ( dbkey == NULL ) {
 
2283
        rv = SECFailure;
 
2284
        goto loser;
 
2285
    }
 
2286
    
 
2287
    dbkey->arena = arena;
 
2288
 
 
2289
    /* encrypt key */
 
2290
    checkkey.data = test_key.data = (unsigned char *)KEYDB_PW_CHECK_STRING;
 
2291
    checkkey.size = test_key.len = KEYDB_PW_CHECK_LEN;
 
2292
 
 
2293
    salt = seckey_create_rc4_salt();
 
2294
    if(salt == NULL) {
 
2295
        rv = SECFailure;
 
2296
        goto loser;
 
2297
    }
 
2298
 
 
2299
    param = nsspkcs5_NewParam(algorithm, salt, 1);
 
2300
    if (param == NULL) {
 
2301
        rv = SECFailure;
 
2302
        goto loser;
 
2303
    }
 
2304
 
 
2305
    dest = nsspkcs5_CipherData(param, pwitem, &test_key, PR_TRUE, NULL);
 
2306
    if (dest == NULL)
 
2307
    {
 
2308
        rv = SECFailure;
 
2309
        goto loser;
 
2310
    }
 
2311
 
 
2312
    rv = SECITEM_CopyItem(arena, &dbkey->salt, salt);
 
2313
    if (rv == SECFailure) {
 
2314
        goto loser;
 
2315
    }
 
2316
   
 
2317
    rv = encodePWCheckEntry(arena, &dbkey->derPK, algorithm, dest);
 
2318
        
 
2319
    if ( rv != SECSuccess ) {
 
2320
        goto loser;
 
2321
    }
 
2322
        
 
2323
    rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE);
 
2324
    
 
2325
    /* let success fall through */
 
2326
loser: 
 
2327
    if ( arena != NULL ) {
 
2328
        PORT_FreeArena(arena, PR_TRUE);
 
2329
    }
 
2330
    
 
2331
    if ( dest != NULL ) {
 
2332
        SECITEM_ZfreeItem(dest, PR_TRUE);
 
2333
    }
 
2334
    
 
2335
    if ( salt != NULL ) {
 
2336
        SECITEM_ZfreeItem(salt, PR_TRUE);
 
2337
    }
 
2338
 
 
2339
    if (param != NULL) {
 
2340
        nsspkcs5_DestroyPBEParameter(param);
 
2341
    }
 
2342
        
 
2343
    return(rv);
 
2344
}
 
2345
 
 
2346
static SECStatus
 
2347
seckey_CheckKeyDB1Password(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
 
2348
{
 
2349
    SECStatus rv = SECFailure;
 
2350
    keyList keylist;
 
2351
    keyNode *node = NULL;
 
2352
    NSSLOWKEYPrivateKey *privkey = NULL;
 
2353
 
 
2354
 
 
2355
    /*
 
2356
     * first find a key
 
2357
     */
 
2358
 
 
2359
    /* traverse the database, collecting the keys of all records */
 
2360
    keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
2361
    if ( keylist.arena == NULL ) 
 
2362
    {
 
2363
        PORT_SetError(SEC_ERROR_NO_MEMORY);
 
2364
        return(SECFailure);
 
2365
    }
 
2366
    keylist.head = NULL;
 
2367
    
 
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 ) 
 
2372
        goto done;
 
2373
 
 
2374
    /* just get the first key from the list */
 
2375
    node = keylist.head;
 
2376
 
 
2377
    /* no private keys, accept any password */
 
2378
    if (node == NULL) {
 
2379
        rv = SECSuccess;
 
2380
        goto done;
 
2381
    }
 
2382
    privkey = seckey_get_private_key(handle, &node->key, NULL, pwitem);
 
2383
    if (privkey == NULL) {
 
2384
         rv = SECFailure;
 
2385
         goto done;
 
2386
    }
 
2387
 
 
2388
    /* if we can decrypt the private key, then we had the correct password */
 
2389
    rv = SECSuccess;
 
2390
    nsslowkey_DestroyPrivateKey(privkey);
 
2391
 
 
2392
done:
 
2393
 
 
2394
    /* free the arena */
 
2395
    if ( keylist.arena ) {
 
2396
        PORT_FreeArena(keylist.arena, PR_FALSE);
 
2397
    }
 
2398
    
 
2399
    return(rv);
 
2400
}
 
2401
 
 
2402
/*
 
2403
 * check to see if the user has typed the right password
 
2404
 */
 
2405
SECStatus
 
2406
nsslowkey_CheckKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
 
2407
{
 
2408
    DBT checkkey;
 
2409
    DBT checkdata;
 
2410
    NSSPKCS5PBEParameter *param = NULL;
 
2411
    SECStatus rv = SECFailure;
 
2412
    NSSLOWKEYDBKey *dbkey = NULL;
 
2413
    SECItem *key = NULL;
 
2414
    SECItem *dest = NULL;
 
2415
    SECOidTag algorithm;
 
2416
    SECItem oid;
 
2417
    SECItem encstring;
 
2418
    PRBool update = PR_FALSE;
 
2419
    int ret;
 
2420
    
 
2421
    if (handle == NULL) {
 
2422
        goto loser;
 
2423
    }
 
2424
 
 
2425
    checkkey.data = KEYDB_PW_CHECK_STRING;
 
2426
    checkkey.size = KEYDB_PW_CHECK_LEN;
 
2427
    
 
2428
    dbkey = get_dbkey(handle, &checkkey);
 
2429
    
 
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 );
 
2434
        if (ret) {
 
2435
            goto loser;
 
2436
        }
 
2437
        /* if we have the fake PW_CHECK, then try to decode the key
 
2438
         * rather than the pwcheck item.
 
2439
         */
 
2440
        rv = seckey_CheckKeyDB1Password(handle,pwitem);
 
2441
        if (rv == SECSuccess) {
 
2442
            /* OK we have enough to complete our conversion */
 
2443
            nsslowkey_UpdateKeyDBPass2(handle,pwitem);
 
2444
        }
 
2445
        return rv;
 
2446
    }
 
2447
 
 
2448
    /* build the oid item */
 
2449
    oid.len = dbkey->derPK.data[0];
 
2450
    oid.data = &dbkey->derPK.data[1];
 
2451
    
 
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.
 
2455
     */
 
2456
    if ( dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 + oid.len ) ) {
 
2457
        goto loser;
 
2458
    }
 
2459
 
 
2460
    /* find the algorithm tag */
 
2461
    algorithm = SECOID_FindOIDTag(&oid);
 
2462
 
 
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];
 
2466
    encstring.type = 0;
 
2467
    
 
2468
    switch(algorithm)
 
2469
    {
 
2470
        case SEC_OID_RC4:
 
2471
            key = seckey_create_rc4_key(pwitem, &dbkey->salt);
 
2472
            if(key != NULL) {
 
2473
                dest = seckey_rc4_decode(key, &encstring);
 
2474
                SECITEM_FreeItem(key, PR_TRUE);
 
2475
            }
 
2476
            break;
 
2477
        default:
 
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.
 
2486
                 */
 
2487
                dest = nsspkcs5_CipherData(param, pwitem, 
 
2488
                                           &encstring, PR_FALSE, &update);
 
2489
                nsspkcs5_DestroyPBEParameter(param);
 
2490
            }   
 
2491
            break;
 
2492
    }
 
2493
 
 
2494
    if(dest == NULL) {
 
2495
        goto loser;
 
2496
    }
 
2497
 
 
2498
    if ((dest->len == KEYDB_PW_CHECK_LEN) &&
 
2499
        (PORT_Memcmp(dest->data, 
 
2500
                     KEYDB_PW_CHECK_STRING, KEYDB_PW_CHECK_LEN) == 0)) {
 
2501
        rv = SECSuccess;
 
2502
        /* we succeeded */
 
2503
        if ( algorithm == SEC_OID_RC4 ) {
 
2504
            /* partially updated database */
 
2505
            nsslowkey_UpdateKeyDBPass2(handle, pwitem);
 
2506
        }
 
2507
        /* Force an update of the password to remove the incorrect DES
 
2508
         * encryption (see the note above)
 
2509
         */
 
2510
        if (update && 
 
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);
 
2514
        }
 
2515
    }
 
2516
                        
 
2517
loser:
 
2518
    sec_destroy_dbkey(dbkey);
 
2519
    if(dest != NULL) {
 
2520
        SECITEM_ZfreeItem(dest, PR_TRUE);
 
2521
    }
 
2522
 
 
2523
    return(rv);
 
2524
}
 
2525
 
 
2526
/*
 
2527
 *  Change the database password and/or algorithm.  This internal
 
2528
 *  routine does not check the old password.  That must be done by 
 
2529
 *  the caller.
 
2530
 */
 
2531
static SECStatus
 
2532
ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle,
 
2533
                       SECItem *oldpwitem, SECItem *newpwitem,
 
2534
                       SECOidTag new_algorithm)
 
2535
{
 
2536
    SECStatus rv;
 
2537
    keyList keylist;
 
2538
    keyNode *node = NULL;
 
2539
    NSSLOWKEYPrivateKey *privkey = NULL;
 
2540
    char *nickname;
 
2541
    DBT newkey;
 
2542
    int ret;
 
2543
 
 
2544
    /* traverse the database, collecting the keys of all records */
 
2545
    keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
2546
    if ( keylist.arena == NULL ) 
 
2547
    {
 
2548
        PORT_SetError(SEC_ERROR_NO_MEMORY);
 
2549
        return(SECFailure);
 
2550
    }
 
2551
    keylist.head = NULL;
 
2552
 
 
2553
    rv = db_BeginTransaction(handle->db);
 
2554
    if (rv != SECSuccess) {
 
2555
        goto loser;
 
2556
    }
 
2557
    
 
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 ) 
 
2562
        goto loser;
 
2563
 
 
2564
    /* walk the list, re-encrypting each entry */
 
2565
    node = keylist.head;
 
2566
    while ( node != NULL ) 
 
2567
    {
 
2568
        privkey = seckey_get_private_key(handle, &node->key, &nickname,
 
2569
                                         oldpwitem);
 
2570
        
 
2571
        if (privkey == NULL) {
 
2572
            PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
2573
            rv = SECFailure;
 
2574
            goto loser;
 
2575
        }
 
2576
 
 
2577
        /* delete the old record */
 
2578
        ret = keydb_Del(handle, &node->key, 0);
 
2579
        if ( ret ) {
 
2580
            PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
2581
            rv = SECFailure;
 
2582
            goto loser;
 
2583
        }
 
2584
        
 
2585
        /* get the public key, which we use as the database index */
 
2586
 
 
2587
        switch (privkey->keyType) {
 
2588
          case NSSLOWKEYRSAKey:
 
2589
            newkey.data = privkey->u.rsa.modulus.data;
 
2590
            newkey.size = privkey->u.rsa.modulus.len;
 
2591
            break;
 
2592
          case NSSLOWKEYDSAKey:
 
2593
            newkey.data = privkey->u.dsa.publicValue.data;
 
2594
            newkey.size = privkey->u.dsa.publicValue.len;
 
2595
            break;
 
2596
          case NSSLOWKEYDHKey:
 
2597
            newkey.data = privkey->u.dh.publicValue.data;
 
2598
            newkey.size = privkey->u.dh.publicValue.len;
 
2599
            break;
 
2600
#ifdef NSS_ENABLE_ECC
 
2601
          case NSSLOWKEYECKey:
 
2602
            newkey.data = privkey->u.ec.publicValue.data;
 
2603
            newkey.size = privkey->u.ec.publicValue.len;
 
2604
            break;
 
2605
#endif /* NSS_ENABLE_ECC */
 
2606
          default:
 
2607
            /* should we continue here and loose the key? */
 
2608
            PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
2609
            rv = SECFailure;
 
2610
            goto loser;
 
2611
        }
 
2612
 
 
2613
        rv = seckey_put_private_key(handle, &newkey, newpwitem, privkey,
 
2614
                                    nickname, PR_TRUE, new_algorithm);
 
2615
        
 
2616
        if ( rv != SECSuccess ) 
 
2617
        {
 
2618
            PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
2619
            rv = SECFailure;
 
2620
            goto loser;
 
2621
        }
 
2622
 
 
2623
        /* next node */
 
2624
        node = node->next;
 
2625
    }
 
2626
 
 
2627
    rv = nsslowkey_SetKeyDBPasswordAlg(handle, newpwitem, new_algorithm);
 
2628
 
 
2629
loser:
 
2630
 
 
2631
    db_FinishTransaction(handle->db,rv != SECSuccess);
 
2632
 
 
2633
    /* free the arena */
 
2634
    if ( keylist.arena ) {
 
2635
        PORT_FreeArena(keylist.arena, PR_FALSE);
 
2636
    }
 
2637
    
 
2638
    return(rv);
 
2639
}
 
2640
 
 
2641
/*
 
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
 
2645
 */
 
2646
SECStatus
 
2647
nsslowkey_ChangeKeyDBPassword(NSSLOWKEYDBHandle *handle,
 
2648
                              SECItem *oldpwitem, SECItem *newpwitem)
 
2649
{
 
2650
    SECStatus rv;
 
2651
    
 
2652
    if (handle == NULL) {
 
2653
        PORT_SetError(SEC_ERROR_BAD_DATABASE);
 
2654
        rv = SECFailure;
 
2655
        goto loser;
 
2656
    }
 
2657
 
 
2658
    rv = nsslowkey_CheckKeyDBPassword(handle, oldpwitem);
 
2659
    if ( rv != SECSuccess ) {
 
2660
        return(SECFailure);  /* return rv? */
 
2661
    }
 
2662
 
 
2663
    rv = ChangeKeyDBPasswordAlg(handle, oldpwitem, newpwitem, 
 
2664
                                nsslowkey_GetDefaultKeyDBAlg());
 
2665
 
 
2666
loser:
 
2667
    return(rv);
 
2668
}
 
2669
    
 
2670
 
 
2671
#define MAX_DB_SIZE 0xffff 
 
2672
/*
 
2673
 * Clear out all the keys in the existing database
 
2674
 */
 
2675
SECStatus
 
2676
nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle)
 
2677
{
 
2678
    SECStatus rv;
 
2679
    int ret;
 
2680
    int errors = 0;
 
2681
 
 
2682
    if ( handle->db == NULL ) {
 
2683
        return(SECSuccess);
 
2684
    }
 
2685
 
 
2686
    if (handle->readOnly) {
 
2687
        /* set an error code */
 
2688
        return SECFailure;
 
2689
     }
 
2690
 
 
2691
    if (handle->appname == NULL && handle->dbname == NULL) {
 
2692
        return SECFailure;
 
2693
    }
 
2694
 
 
2695
    keydb_Close(handle);
 
2696
    if (handle->appname) {
 
2697
        handle->db= 
 
2698
            rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL);
 
2699
    } else {
 
2700
        handle->db = dbopen( handle->dbname, NO_CREATE, 0600, DB_HASH, 0 );
 
2701
    }
 
2702
    if (handle->db == NULL) {
 
2703
        /* set an error code */
 
2704
        return SECFailure;
 
2705
    }
 
2706
    
 
2707
    rv = makeGlobalVersion(handle);
 
2708
    if ( rv != SECSuccess ) {
 
2709
        errors++;
 
2710
        goto done;
 
2711
    }
 
2712
 
 
2713
    if (handle->global_salt) {
 
2714
        rv = StoreKeyDBGlobalSalt(handle);
 
2715
    } else {
 
2716
        rv = makeGlobalSalt(handle);
 
2717
        if ( rv == SECSuccess ) {
 
2718
            handle->global_salt = GetKeyDBGlobalSalt(handle);
 
2719
        }
 
2720
    }
 
2721
    if ( rv != SECSuccess ) {
 
2722
        errors++;
 
2723
    }
 
2724
 
 
2725
done:
 
2726
    /* sync the database */
 
2727
    ret = keydb_Sync(handle, 0);
 
2728
    db_InitComplete(handle->db);
 
2729
 
 
2730
    return (errors == 0 ? SECSuccess : SECFailure);
 
2731
}
 
2732
 
 
2733
static int
 
2734
keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
 
2735
{
 
2736
    PRStatus prstat;
 
2737
    int ret;
 
2738
    PRLock *kdbLock = kdb->lock;
 
2739
    DB *db = kdb->db;
 
2740
    
 
2741
    PORT_Assert(kdbLock != NULL);
 
2742
    PZ_Lock(kdbLock);
 
2743
 
 
2744
    ret = (* db->get)(db, key, data, flags);
 
2745
 
 
2746
    prstat = PZ_Unlock(kdbLock);
 
2747
 
 
2748
    return(ret);
 
2749
}
 
2750
 
 
2751
static int
 
2752
keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
 
2753
{
 
2754
    PRStatus prstat;
 
2755
    int ret = 0;
 
2756
    PRLock *kdbLock = kdb->lock;
 
2757
    DB *db = kdb->db;
 
2758
 
 
2759
    PORT_Assert(kdbLock != NULL);
 
2760
    PZ_Lock(kdbLock);
 
2761
 
 
2762
    ret = (* db->put)(db, key, data, flags);
 
2763
    
 
2764
    prstat = PZ_Unlock(kdbLock);
 
2765
 
 
2766
    return(ret);
 
2767
}
 
2768
 
 
2769
static int
 
2770
keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags)
 
2771
{
 
2772
    PRStatus prstat;
 
2773
    int ret;
 
2774
    PRLock *kdbLock = kdb->lock;
 
2775
    DB *db = kdb->db;
 
2776
 
 
2777
    PORT_Assert(kdbLock != NULL);
 
2778
    PZ_Lock(kdbLock);
 
2779
 
 
2780
    ret = (* db->sync)(db, flags);
 
2781
    
 
2782
    prstat = PZ_Unlock(kdbLock);
 
2783
 
 
2784
    return(ret);
 
2785
}
 
2786
 
 
2787
static int
 
2788
keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags)
 
2789
{
 
2790
    PRStatus prstat;
 
2791
    int ret;
 
2792
    PRLock *kdbLock = kdb->lock;
 
2793
    DB *db = kdb->db;
 
2794
 
 
2795
    PORT_Assert(kdbLock != NULL);
 
2796
    PZ_Lock(kdbLock);
 
2797
 
 
2798
    ret = (* db->del)(db, key, flags);
 
2799
    
 
2800
    prstat = PZ_Unlock(kdbLock);
 
2801
 
 
2802
    return(ret);
 
2803
}
 
2804
 
 
2805
static int
 
2806
keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
 
2807
{
 
2808
    PRStatus prstat;
 
2809
    int ret;
 
2810
    PRLock *kdbLock = kdb->lock;
 
2811
    DB *db = kdb->db;
 
2812
    
 
2813
    PORT_Assert(kdbLock != NULL);
 
2814
    PZ_Lock(kdbLock);
 
2815
    
 
2816
    ret = (* db->seq)(db, key, data, flags);
 
2817
 
 
2818
    prstat = PZ_Unlock(kdbLock);
 
2819
 
 
2820
    return(ret);
 
2821
}
 
2822
 
 
2823
static void
 
2824
keydb_Close(NSSLOWKEYDBHandle *kdb)
 
2825
{
 
2826
    PRStatus prstat;
 
2827
    PRLock *kdbLock = kdb->lock;
 
2828
    DB *db = kdb->db;
 
2829
 
 
2830
    PORT_Assert(kdbLock != NULL);
 
2831
    PZ_Lock(kdbLock);
 
2832
 
 
2833
    (* db->close)(db);
 
2834
    
 
2835
    prstat = PZ_Unlock(kdbLock);
 
2836
 
 
2837
    return;
 
2838
}
 
2839