Bug Summary

File:s/lib/softoken/legacydb/keydb.c
Warning:line 750, column 5
Value stored to 'ret' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name keydb.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/softoken/legacydb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/softoken/legacydb -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D SHLIB_SUFFIX="so" -D SHLIB_PREFIX="lib" -D LG_LIB_NAME="libnssdbm3.so" -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../../dist/public/nss -I ../../../../dist/private/nss -I ../../../../dist/public/dbm -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c keydb.c
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "lowkeyi.h"
6#include "secasn1.h"
7#include "secder.h"
8#include "secoid.h"
9#include "blapi.h"
10#include "secitem.h"
11#include "pcert.h"
12#include "mcom_db.h"
13#include "secerr.h"
14
15#include "keydbi.h"
16#include "lgdb.h"
17
18/*
19 * Record keys for keydb
20 */
21#define SALT_STRING"global-salt" "global-salt"
22#define VERSION_STRING"Version" "Version"
23#define KEYDB_PW_CHECK_STRING"password-check" "password-check"
24#define KEYDB_PW_CHECK_LEN14 14
25#define KEYDB_FAKE_PW_CHECK_STRING"fake-password-check" "fake-password-check"
26#define KEYDB_FAKE_PW_CHECK_LEN19 19
27
28/* Size of the global salt for key database */
29#define SALT_LENGTH16 16
30
31SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
32
33const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = {
34 { SEC_ASN1_SEQUENCE0x10,
35 0, NULL((void*)0), sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) },
36 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0,
37 offsetof(NSSLOWKEYEncryptedPrivateKeyInfo, algorithm)__builtin_offsetof(NSSLOWKEYEncryptedPrivateKeyInfo, algorithm
)
,
38 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util },
39 { SEC_ASN1_OCTET_STRING0x04,
40 offsetof(NSSLOWKEYEncryptedPrivateKeyInfo, encryptedData)__builtin_offsetof(NSSLOWKEYEncryptedPrivateKeyInfo, encryptedData
)
},
41 { 0 }
42};
43
44const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = {
45 { SEC_ASN1_POINTER0x01000, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate }
46};
47
48/* ====== Default key databse encryption algorithm ====== */
49static void
50sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey)
51{
52 if (dbkey && dbkey->arena) {
53 PORT_FreeArenaPORT_FreeArena_Util(dbkey->arena, PR_FALSE0);
54 }
55}
56
57static void
58free_dbt(DBT *dbt)
59{
60 if (dbt) {
61 PORT_FreePORT_Free_Util(dbt->data);
62 PORT_FreePORT_Free_Util(dbt);
63 }
64
65 return;
66}
67
68static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
69 unsigned int flags);
70static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
71 unsigned int flags);
72static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags);
73static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags);
74static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
75 unsigned int flags);
76static void keydb_Close(NSSLOWKEYDBHandle *db);
77
78/*
79 * format of key database entries for version 3 of database:
80 * byte offset field
81 * ----------- -----
82 * 0 version
83 * 1 salt-len
84 * 2 nn-len
85 * 3.. salt-data
86 * ... nickname
87 * ... encrypted-key-data
88 */
89static DBT *
90encode_dbkey(NSSLOWKEYDBKey *dbkey, unsigned char version)
91{
92 DBT *bufitem = NULL((void*)0);
93 unsigned char *buf;
94 int nnlen;
95 char *nn;
96
97 bufitem = (DBT *)PORT_ZAllocPORT_ZAlloc_Util(sizeof(DBT));
98 if (bufitem == NULL((void*)0)) {
99 goto loser;
100 }
101
102 if (dbkey->nickname) {
103 nn = dbkey->nickname;
104 nnlen = PORT_Strlen(nn)strlen(nn) + 1;
105 } else {
106 nn = "";
107 nnlen = 1;
108 }
109
110 /* compute the length of the record */
111 /* 1 + 1 + 1 == version number header + salt length + nn len */
112 bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1;
113
114 bufitem->data = (void *)PORT_ZAllocPORT_ZAlloc_Util(bufitem->size);
115 if (bufitem->data == NULL((void*)0)) {
116 goto loser;
117 }
118
119 buf = (unsigned char *)bufitem->data;
120
121 /* set version number */
122 buf[0] = version;
123
124 /* set length of salt */
125 PORT_Assert(dbkey->salt.len < 256)((dbkey->salt.len < 256)?((void)0):PR_Assert("dbkey->salt.len < 256"
,"keydb.c",125))
;
126 buf[1] = dbkey->salt.len;
127
128 /* set length of nickname */
129 PORT_Assert(nnlen < 256)((nnlen < 256)?((void)0):PR_Assert("nnlen < 256","keydb.c"
,129))
;
130 buf[2] = nnlen;
131
132 /* copy salt */
133 if (dbkey->salt.len > 0) {
134 PORT_Memcpymemcpy(&buf[3], dbkey->salt.data, dbkey->salt.len);
135 }
136
137 /* copy nickname */
138 PORT_Memcpymemcpy(&buf[3 + dbkey->salt.len], nn, nnlen);
139
140 /* copy encrypted key */
141 PORT_Memcpymemcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data,
142 dbkey->derPK.len);
143
144 return (bufitem);
145
146loser:
147 if (bufitem) {
148 free_dbt(bufitem);
149 }
150
151 return (NULL((void*)0));
152}
153
154static NSSLOWKEYDBKey *
155decode_dbkey(DBT *bufitem, int expectedVersion)
156{
157 NSSLOWKEYDBKey *dbkey;
158 PLArenaPool *arena = NULL((void*)0);
159 unsigned char *buf;
160 int version;
161 int keyoff;
162 int nnlen;
163 int saltoff;
164
165 buf = (unsigned char *)bufitem->data;
166
167 version = buf[0];
168
169 if (version != expectedVersion) {
170 goto loser;
171 }
172
173 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
174 if (arena == NULL((void*)0)) {
175 goto loser;
176 }
177
178 dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, sizeof(NSSLOWKEYDBKey));
179 if (dbkey == NULL((void*)0)) {
180 goto loser;
181 }
182
183 dbkey->arena = arena;
184 dbkey->salt.data = NULL((void*)0);
185 dbkey->derPK.data = NULL((void*)0);
186
187 dbkey->salt.len = buf[1];
188 dbkey->salt.data = (unsigned char *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, dbkey->salt.len);
189 if (dbkey->salt.data == NULL((void*)0)) {
190 goto loser;
191 }
192
193 saltoff = 2;
194 keyoff = 2 + dbkey->salt.len;
195
196 if (expectedVersion >= 3) {
197 nnlen = buf[2];
198 if (nnlen) {
199 dbkey->nickname = (char *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, nnlen + 1);
200 if (dbkey->nickname) {
201 PORT_Memcpymemcpy(dbkey->nickname, &buf[keyoff + 1], nnlen);
202 }
203 }
204 keyoff += (nnlen + 1);
205 saltoff = 3;
206 }
207
208 PORT_Memcpymemcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len);
209
210 dbkey->derPK.len = bufitem->size - keyoff;
211 dbkey->derPK.data = (unsigned char *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, dbkey->derPK.len);
212 if (dbkey->derPK.data == NULL((void*)0)) {
213 goto loser;
214 }
215
216 PORT_Memcpymemcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len);
217
218 return (dbkey);
219
220loser:
221
222 if (arena) {
223 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
224 }
225
226 return (NULL((void*)0));
227}
228
229static NSSLOWKEYDBKey *
230get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index)
231{
232 NSSLOWKEYDBKey *dbkey;
233 DBT entry;
234 int ret;
235
236 /* get it from the database */
237 ret = keydb_Get(handle, index, &entry, 0);
238 if (ret) {
239 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
240 return NULL((void*)0);
241 }
242
243 /* set up dbkey struct */
244
245 dbkey = decode_dbkey(&entry, handle->version);
246
247 return (dbkey);
248}
249
250static SECStatus
251put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update)
252{
253 DBT *keydata = NULL((void*)0);
254 int status;
255
256 keydata = encode_dbkey(dbkey, handle->version);
257 if (keydata == NULL((void*)0)) {
258 goto loser;
259 }
260
261 /* put it in the database */
262 if (update) {
263 status = keydb_Put(handle, index, keydata, 0);
264 } else {
265 status = keydb_Put(handle, index, keydata, R_NOOVERWRITE8);
266 }
267
268 if (status) {
269 goto loser;
270 }
271
272 /* sync the database */
273 status = keydb_Sync(handle, 0);
274 if (status) {
275 goto loser;
276 }
277
278 free_dbt(keydata);
279 return (SECSuccess);
280
281loser:
282 if (keydata) {
283 free_dbt(keydata);
284 }
285
286 return (SECFailure);
287}
288
289SECStatus
290nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle,
291 SECStatus (*keyfunc)(DBT *k, DBT *d, void *pdata),
292 void *udata)
293{
294 DBT data;
295 DBT key;
296 SECStatus status;
297 int ret;
298
299 if (handle == NULL((void*)0)) {
300 return (SECFailure);
301 }
302
303 ret = keydb_Seq(handle, &key, &data, R_FIRST3);
304 if (ret) {
305 return (SECFailure);
306 }
307
308 do {
309 /* skip version record */
310 if (data.size > 1) {
311 if (key.size == (sizeof(SALT_STRING"global-salt") - 1)) {
312 if (PORT_Memcmpmemcmp(key.data, SALT_STRING"global-salt", key.size) == 0) {
313 continue;
314 }
315 }
316
317 /* skip password check */
318 if (key.size == KEYDB_PW_CHECK_LEN14) {
319 if (PORT_Memcmpmemcmp(key.data, KEYDB_PW_CHECK_STRING"password-check",
320 KEYDB_PW_CHECK_LEN14) == 0) {
321 continue;
322 }
323 }
324
325 status = (*keyfunc)(&key, &data, udata);
326 if (status != SECSuccess) {
327 return (status);
328 }
329 }
330 } while (keydb_Seq(handle, &key, &data, R_NEXT7) == 0);
331
332 return (SECSuccess);
333}
334
335#ifdef notdef
336typedef struct keyNode {
337 struct keyNode *next;
338 DBT key;
339} keyNode;
340
341typedef struct {
342 PLArenaPool *arena;
343 keyNode *head;
344} keyList;
345
346static SECStatus
347sec_add_key_to_list(DBT *key, DBT *data, void *arg)
348{
349 keyList *keylist;
350 keyNode *node;
351 void *keydata;
352
353 keylist = (keyList *)arg;
354
355 /* allocate the node struct */
356 node = (keyNode *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(keylist->arena, sizeof(keyNode));
357 if (node == NULL((void*)0)) {
358 return (SECFailure);
359 }
360
361 /* allocate room for key data */
362 keydata = PORT_ArenaZAllocPORT_ArenaZAlloc_Util(keylist->arena, key->size);
363 if (keydata == NULL((void*)0)) {
364 return (SECFailure);
365 }
366
367 /* link node into list */
368 node->next = keylist->head;
369 keylist->head = node;
370
371 /* copy key into node */
372 PORT_Memcpymemcpy(keydata, key->data, key->size);
373 node->key.size = key->size;
374 node->key.data = keydata;
375
376 return (SECSuccess);
377}
378#endif
379
380static SECItem *
381decodeKeyDBGlobalSalt(DBT *saltData)
382{
383 SECItem *saltitem;
384
385 saltitem = (SECItem *)PORT_ZAllocPORT_ZAlloc_Util(sizeof(SECItem));
386 if (saltitem == NULL((void*)0)) {
387 return (NULL((void*)0));
388 }
389
390 saltitem->data = (unsigned char *)PORT_ZAllocPORT_ZAlloc_Util(saltData->size);
391 if (saltitem->data == NULL((void*)0)) {
392 PORT_FreePORT_Free_Util(saltitem);
393 return (NULL((void*)0));
394 }
395
396 saltitem->len = saltData->size;
397 PORT_Memcpymemcpy(saltitem->data, saltData->data, saltitem->len);
398
399 return (saltitem);
400}
401
402static SECItem *
403GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
404{
405 DBT saltKey;
406 DBT saltData;
407 int ret;
408
409 saltKey.data = SALT_STRING"global-salt";
410 saltKey.size = sizeof(SALT_STRING"global-salt") - 1;
411
412 ret = keydb_Get(handle, &saltKey, &saltData, 0);
413 if (ret) {
414 return (NULL((void*)0));
415 }
416
417 return (decodeKeyDBGlobalSalt(&saltData));
418}
419
420static SECStatus
421StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle, SECItem *salt)
422{
423 DBT saltKey;
424 DBT saltData;
425 int status;
426
427 saltKey.data = SALT_STRING"global-salt";
428 saltKey.size = sizeof(SALT_STRING"global-salt") - 1;
429
430 saltData.data = (void *)salt->data;
431 saltData.size = salt->len;
432
433 /* put global salt into the database now */
434 status = keydb_Put(handle, &saltKey, &saltData, 0);
435 if (status) {
436 return (SECFailure);
437 }
438
439 return (SECSuccess);
440}
441
442static SECStatus
443makeGlobalVersion(NSSLOWKEYDBHandle *handle)
444{
445 unsigned char version;
446 DBT versionData;
447 DBT versionKey;
448 int status;
449
450 version = NSSLOWKEY_DB_FILE_VERSION3;
451 versionData.data = &version;
452 versionData.size = 1;
453 versionKey.data = VERSION_STRING"Version";
454 versionKey.size = sizeof(VERSION_STRING"Version") - 1;
455
456 /* put version string into the database now */
457 status = keydb_Put(handle, &versionKey, &versionData, 0);
458 if (status) {
459 return (SECFailure);
460 }
461 handle->version = version;
462
463 return (SECSuccess);
464}
465
466static SECStatus
467makeGlobalSalt(NSSLOWKEYDBHandle *handle)
468{
469 DBT saltKey;
470 DBT saltData;
471 unsigned char saltbuf[16];
472 int status;
473
474 saltKey.data = SALT_STRING"global-salt";
475 saltKey.size = sizeof(SALT_STRING"global-salt") - 1;
476
477 saltData.data = (void *)saltbuf;
478 saltData.size = sizeof(saltbuf);
479 RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf));
480
481 /* put global salt into the database now */
482 status = keydb_Put(handle, &saltKey, &saltData, 0);
483 if (status) {
484 return (SECFailure);
485 }
486
487 return (SECSuccess);
488}
489
490static SECStatus
491encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
492 SECItem *encCheck);
493
494static unsigned char
495nsslowkey_version(NSSLOWKEYDBHandle *handle)
496{
497 DBT versionKey;
498 DBT versionData;
499 int ret;
500 versionKey.data = VERSION_STRING"Version";
501 versionKey.size = sizeof(VERSION_STRING"Version") - 1;
502
503 if (handle->db == NULL((void*)0)) {
504 return 255;
505 }
506
507 /* lookup version string in database */
508 ret = keydb_Get(handle, &versionKey, &versionData, 0);
509
510 /* error accessing the database */
511 if (ret < 0) {
512 return 255;
513 }
514
515 if (ret >= 1) {
516 return 0;
517 }
518 return *((unsigned char *)versionData.data);
519}
520
521static PRBool
522seckey_HasAServerKey(NSSLOWKEYDBHandle *handle)
523{
524 DBT key;
525 DBT data;
526 int ret;
527 PRBool found = PR_FALSE0;
528
529 ret = keydb_Seq(handle, &key, &data, R_FIRST3);
530 if (ret) {
531 return PR_FALSE0;
532 }
533
534 do {
535 /* skip version record */
536 if (data.size > 1) {
537 /* skip salt */
538 if (key.size == (sizeof(SALT_STRING"global-salt") - 1)) {
539 if (PORT_Memcmpmemcmp(key.data, SALT_STRING"global-salt", key.size) == 0) {
540 continue;
541 }
542 }
543 /* skip pw check entry */
544 if (key.size == KEYDB_PW_CHECK_LEN14) {
545 if (PORT_Memcmpmemcmp(key.data, KEYDB_PW_CHECK_STRING"password-check",
546 KEYDB_PW_CHECK_LEN14) == 0) {
547 continue;
548 }
549 }
550
551 /* keys stored by nickname will have 0 as the last byte of the
552 * db key. Other keys must be stored by modulus. We will not
553 * update those because they are left over from a keygen that
554 * never resulted in a cert.
555 */
556 if (((unsigned char *)key.data)[key.size - 1] != 0) {
557 continue;
558 }
559
560 if (PORT_Strcmpstrcmp(key.data, "Server-Key") == 0) {
561 found = PR_TRUE1;
562 break;
563 }
564 }
565 } while (keydb_Seq(handle, &key, &data, R_NEXT7) == 0);
566
567 return found;
568}
569
570/* forward declare local create function */
571static NSSLOWKEYDBHandle *nsslowkey_NewHandle(DB *dbHandle);
572
573/*
574 * currently updates key database from v2 to v3
575 */
576static SECStatus
577nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle)
578{
579 SECStatus rv;
580 DBT checkKey;
581 DBT checkData;
582 DBT saltKey;
583 DBT saltData;
584 DBT key;
585 DBT data;
586 unsigned char version;
587 NSSLOWKEYDBKey *dbkey = NULL((void*)0);
588 NSSLOWKEYDBHandle *update = NULL((void*)0);
589 SECItem *oldSalt = NULL((void*)0);
590 int ret;
591 SECItem checkitem;
592
593 if (handle->updatedb == NULL((void*)0)) {
594 return SECSuccess;
595 }
596
597 /* create a full DB Handle for our update so we
598 * can use the correct locks for the db primatives */
599 update = nsslowkey_NewHandle(handle->updatedb);
600 if (update == NULL((void*)0)) {
601 return SECSuccess;
602 }
603
604 /* update has now inherited the database handle */
605 handle->updatedb = NULL((void*)0);
606
607 /*
608 * check the version record
609 */
610 version = nsslowkey_version(update);
611 if (version != 2) {
612 goto done;
613 }
614
615 saltKey.data = SALT_STRING"global-salt";
616 saltKey.size = sizeof(SALT_STRING"global-salt") - 1;
617
618 ret = keydb_Get(update, &saltKey, &saltData, 0);
619 if (ret) {
620 /* no salt in old db, so it is corrupted */
621 goto done;
622 }
623
624 oldSalt = decodeKeyDBGlobalSalt(&saltData);
625 if (oldSalt == NULL((void*)0)) {
626 /* bad salt in old db, so it is corrupted */
627 goto done;
628 }
629
630 /*
631 * look for a pw check entry
632 */
633 checkKey.data = KEYDB_PW_CHECK_STRING"password-check";
634 checkKey.size = KEYDB_PW_CHECK_LEN14;
635
636 ret = keydb_Get(update, &checkKey, &checkData, 0);
637 if (ret) {
638 /*
639 * if we have a key, but no KEYDB_PW_CHECK_STRING, then this must
640 * be an old server database, and it does have a password associated
641 * with it. Put a fake entry in so we can identify this db when we do
642 * get the password for it.
643 */
644 if (seckey_HasAServerKey(update)) {
645 DBT fcheckKey;
646 DBT fcheckData;
647
648 /*
649 * include a fake string
650 */
651 fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING"fake-password-check";
652 fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN19;
653 fcheckData.data = "1";
654 fcheckData.size = 1;
655 /* put global salt into the new database now */
656 ret = keydb_Put(handle, &saltKey, &saltData, 0);
657 if (ret) {
658 goto done;
659 }
660 ret = keydb_Put(handle, &fcheckKey, &fcheckData, 0);
661 if (ret) {
662 goto done;
663 }
664 } else {
665 goto done;
666 }
667 } else {
668 /* put global salt into the new database now */
669 ret = keydb_Put(handle, &saltKey, &saltData, 0);
670 if (ret) {
671 goto done;
672 }
673
674 dbkey = decode_dbkey(&checkData, 2);
675 if (dbkey == NULL((void*)0)) {
676 goto done;
677 }
678 checkitem = dbkey->derPK;
679 dbkey->derPK.data = NULL((void*)0);
680
681 /* format the new pw check entry */
682 rv = encodePWCheckEntry(NULL((void*)0), &dbkey->derPK, SEC_OID_RC4, &checkitem);
683 if (rv != SECSuccess) {
684 goto done;
685 }
686
687 rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE1);
688 if (rv != SECSuccess) {
689 goto done;
690 }
691
692 /* free the dbkey */
693 sec_destroy_dbkey(dbkey);
694 dbkey = NULL((void*)0);
695 }
696
697 /* now traverse the database */
698 ret = keydb_Seq(update, &key, &data, R_FIRST3);
699 if (ret) {
700 goto done;
701 }
702
703 do {
704 /* skip version record */
705 if (data.size > 1) {
706 /* skip salt */
707 if (key.size == (sizeof(SALT_STRING"global-salt") - 1)) {
708 if (PORT_Memcmpmemcmp(key.data, SALT_STRING"global-salt", key.size) == 0) {
709 continue;
710 }
711 }
712 /* skip pw check entry */
713 if (key.size == checkKey.size) {
714 if (PORT_Memcmpmemcmp(key.data, checkKey.data, key.size) == 0) {
715 continue;
716 }
717 }
718
719 /* keys stored by nickname will have 0 as the last byte of the
720 * db key. Other keys must be stored by modulus. We will not
721 * update those because they are left over from a keygen that
722 * never resulted in a cert.
723 */
724 if (((unsigned char *)key.data)[key.size - 1] != 0) {
725 continue;
726 }
727
728 dbkey = decode_dbkey(&data, 2);
729 if (dbkey == NULL((void*)0)) {
730 continue;
731 }
732
733 /* This puts the key into the new database with the same
734 * index (nickname) that it had before. The second pass
735 * of the update will have the password. It will decrypt
736 * and re-encrypt the entries using a new algorithm.
737 */
738 dbkey->nickname = (char *)key.data;
739 rv = put_dbkey(handle, &key, dbkey, PR_FALSE0);
740 dbkey->nickname = NULL((void*)0);
741
742 sec_destroy_dbkey(dbkey);
743 }
744 } while (keydb_Seq(update, &key, &data, R_NEXT7) == 0);
745
746 dbkey = NULL((void*)0);
747
748done:
749 /* sync the database */
750 ret = keydb_Sync(handle, 0);
Value stored to 'ret' is never read
751
752 nsslowkey_CloseKeyDB(update);
753
754 if (oldSalt) {
755 SECITEM_FreeItemSECITEM_FreeItem_Util(oldSalt, PR_TRUE1);
756 }
757
758 if (dbkey) {
759 sec_destroy_dbkey(dbkey);
760 }
761
762 return (SECSuccess);
763}
764
765static SECStatus
766openNewDB(const char *appName, const char *prefix, const char *dbname,
767 NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg)
768{
769 SECStatus rv = SECFailure;
770 int status = RDB_FAIL1;
771 char *updname = NULL((void*)0);
772 DB *updatedb = NULL((void*)0);
773 PRBool updated = PR_FALSE0;
774 int ret;
775
776 if (appName) {
777 handle->db = rdbopen(appName, prefix, "key", NO_CREATE(02 | 0100 | 01000), &status);
778 } else {
779 handle->db = dbopen(dbname, NO_CREATE(02 | 0100 | 01000), 0600, DB_HASH, 0);
780 }
781 /* if create fails then we lose */
782 if (handle->db == NULL((void*)0)) {
783 return (status == RDB_RETRY2) ? SECWouldBlock : SECFailure;
784 }
785
786 /* force a transactional read, which will verify that one and only one
787 * process attempts the update. */
788 if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION3) {
789 /* someone else has already updated the database for us */
790 db_InitComplete(handle->db);
791 return SECSuccess;
792 }
793
794 /*
795 * if we are creating a multiaccess database, see if there is a
796 * local database we can update from.
797 */
798 if (appName) {
799 NSSLOWKEYDBHandle *updateHandle;
800 updatedb = dbopen(dbname, NO_RDONLY00, 0600, DB_HASH, 0);
801 if (!updatedb) {
802 goto noupdate;
803 }
804
805 /* nsslowkey_version needs a full handle because it calls
806 * the kdb_Get() function, which needs to lock.
807 */
808 updateHandle = nsslowkey_NewHandle(updatedb);
809 if (!updateHandle) {
810 updatedb->close(updatedb);
811 goto noupdate;
812 }
813
814 handle->version = nsslowkey_version(updateHandle);
815 if (handle->version != NSSLOWKEY_DB_FILE_VERSION3) {
816 nsslowkey_CloseKeyDB(updateHandle);
817 goto noupdate;
818 }
819
820 /* copy the new DB from the old one */
821 db_Copy(handle->db, updatedb);
822 nsslowkey_CloseKeyDB(updateHandle);
823 db_InitComplete(handle->db);
824 return SECSuccess;
825 }
826noupdate:
827
828 /* update the version number */
829 rv = makeGlobalVersion(handle);
830 if (rv != SECSuccess) {
831 goto loser;
832 }
833
834 /*
835 * try to update from v2 db
836 */
837 updname = (*namecb)(cbarg, 2);
838 if (updname != NULL((void*)0)) {
839 handle->updatedb = dbopen(updname, NO_RDONLY00, 0600, DB_HASH, 0);
840 PORT_FreePORT_Free_Util(updname);
841
842 if (handle->updatedb) {
843 /*
844 * Try to update the db using a null password. If the db
845 * doesn't have a password, then this will work. If it does
846 * have a password, then this will fail and we will do the
847 * update later
848 */
849 rv = nsslowkey_UpdateKeyDBPass1(handle);
850 if (rv == SECSuccess) {
851 updated = PR_TRUE1;
852 }
853 }
854 }
855
856 /* we are using the old salt if we updated from an old db */
857 if (!updated) {
858 rv = makeGlobalSalt(handle);
859 if (rv != SECSuccess) {
860 goto loser;
861 }
862 }
863
864 /* sync the database */
865 ret = keydb_Sync(handle, 0);
866 if (ret) {
867 rv = SECFailure;
868 goto loser;
869 }
870 rv = SECSuccess;
871
872loser:
873 db_InitComplete(handle->db);
874 return rv;
875}
876
877static DB *
878openOldDB(const char *appName, const char *prefix, const char *dbname,
879 PRBool openflags)
880{
881 DB *db = NULL((void*)0);
882
883 if (appName) {
884 db = rdbopen(appName, prefix, "key", openflags, NULL((void*)0));
885 } else {
886 db = dbopen(dbname, openflags, 0600, DB_HASH, 0);
887 }
888
889 return db;
890}
891
892/* check for correct version number */
893static PRBool
894verifyVersion(NSSLOWKEYDBHandle *handle)
895{
896 int version = nsslowkey_version(handle);
897
898 handle->version = version;
899 if (version != NSSLOWKEY_DB_FILE_VERSION3) {
900 if (handle->db) {
901 keydb_Close(handle);
902 handle->db = NULL((void*)0);
903 }
904 }
905 return handle->db != NULL((void*)0);
906}
907
908static NSSLOWKEYDBHandle *
909nsslowkey_NewHandle(DB *dbHandle)
910{
911 NSSLOWKEYDBHandle *handle;
912 handle = (NSSLOWKEYDBHandle *)PORT_ZAllocPORT_ZAlloc_Util(sizeof(NSSLOWKEYDBHandle));
913 if (handle == NULL((void*)0)) {
914 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
915 return NULL((void*)0);
916 }
917
918 handle->appname = NULL((void*)0);
919 handle->dbname = NULL((void*)0);
920 handle->global_salt = NULL((void*)0);
921 handle->updatedb = NULL((void*)0);
922 handle->db = dbHandle;
923 handle->ref = 1;
924 handle->lock = PZ_NewLock(nssILockKeyDB)PR_NewLock();
925
926 return handle;
927}
928
929NSSLOWKEYDBHandle *
930nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix,
931 NSSLOWKEYDBNameFunc namecb, void *cbarg)
932{
933 NSSLOWKEYDBHandle *handle = NULL((void*)0);
934 SECStatus rv;
935 int openflags;
936 char *dbname = NULL((void*)0);
937
938 handle = nsslowkey_NewHandle(NULL((void*)0));
939
940 openflags = readOnly ? NO_RDONLY00 : NO_RDWR02;
941
942 dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION3);
943 if (dbname == NULL((void*)0)) {
944 goto loser;
945 }
946 handle->appname = appName ? PORT_StrdupPORT_Strdup_Util(appName) : NULL((void*)0);
947 handle->dbname = (appName == NULL((void*)0)) ? PORT_StrdupPORT_Strdup_Util(dbname) : (prefix ? PORT_StrdupPORT_Strdup_Util(prefix) : NULL((void*)0));
948 handle->readOnly = readOnly;
949
950 handle->db = openOldDB(appName, prefix, dbname, openflags);
951 if (handle->db) {
952 verifyVersion(handle);
953 if (handle->version == 255) {
954 goto loser;
955 }
956 }
957
958 /* if first open fails, try to create a new DB */
959 if (handle->db == NULL((void*)0)) {
960 if (readOnly) {
961 goto loser;
962 }
963
964 rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg);
965 /* two processes started to initialize the database at the same time.
966 * The multiprocess code blocked the second one, then had it retry to
967 * see if it can just open the database normally */
968 if (rv == SECWouldBlock) {
969 handle->db = openOldDB(appName, prefix, dbname, openflags);
970 verifyVersion(handle);
971 if (handle->db == NULL((void*)0)) {
972 goto loser;
973 }
974 } else if (rv != SECSuccess) {
975 goto loser;
976 }
977 }
978
979 handle->global_salt = GetKeyDBGlobalSalt(handle);
980 if (dbname)
981 PORT_FreePORT_Free_Util(dbname);
982 return handle;
983
984loser:
985
986 if (dbname)
987 PORT_FreePORT_Free_Util(dbname);
988 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
989 nsslowkey_CloseKeyDB(handle);
990 return NULL((void*)0);
991}
992
993/*
994 * Close the database
995 */
996void
997nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle)
998{
999 if (handle != NULL((void*)0)) {
1000 if (handle->db != NULL((void*)0)) {
1001 keydb_Close(handle);
1002 }
1003 if (handle->updatedb) {
1004 handle->updatedb->close(handle->updatedb);
1005 }
1006 if (handle->dbname)
1007 PORT_FreePORT_Free_Util(handle->dbname);
1008 if (handle->appname)
1009 PORT_FreePORT_Free_Util(handle->appname);
1010 if (handle->global_salt) {
1011 SECITEM_FreeItemSECITEM_FreeItem_Util(handle->global_salt, PR_TRUE1);
1012 }
1013 if (handle->lock != NULL((void*)0)) {
1014 SKIP_AFTER_FORK(PZ_DestroyLock(handle->lock))if (!lg_parentForkedAfterC_Initialize) PR_DestroyLock((handle
->lock))
;
1015 }
1016
1017 PORT_FreePORT_Free_Util(handle);
1018 }
1019}
1020
1021/* Get the key database version */
1022int
1023nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle)
1024{
1025 PORT_Assert(handle != NULL)((handle != ((void*)0))?((void)0):PR_Assert("handle != NULL",
"keydb.c",1025))
;
1026
1027 return handle->version;
1028}
1029
1030/*
1031 * Delete a private key that was stored in the database
1032 */
1033SECStatus
1034nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, const SECItem *pubkey)
1035{
1036 DBT namekey;
1037 int ret;
1038
1039 if (handle == NULL((void*)0)) {
1040 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1041 return (SECFailure);
1042 }
1043
1044 /* set up db key and data */
1045 namekey.data = pubkey->data;
1046 namekey.size = pubkey->len;
1047
1048 /* delete it from the database */
1049 ret = keydb_Del(handle, &namekey, 0);
1050 if (ret) {
1051 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1052 return (SECFailure);
1053 }
1054
1055 /* sync the database */
1056 ret = keydb_Sync(handle, 0);
1057 if (ret) {
1058 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1059 return (SECFailure);
1060 }
1061
1062 return (SECSuccess);
1063}
1064
1065/*
1066 * Store a key in the database, indexed by its public key modulus.(value!)
1067 */
1068SECStatus
1069nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle,
1070 NSSLOWKEYPrivateKey *privkey,
1071 SECItem *pubKeyData,
1072 char *nickname,
1073 SDB *sdb)
1074{
1075 return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData,
1076 nickname, sdb, PR_FALSE0);
1077}
1078
1079SECStatus
1080nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle,
1081 NSSLOWKEYPrivateKey *privkey,
1082 SECItem *pubKeyData,
1083 char *nickname,
1084 SDB *sdb)
1085{
1086 return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData,
1087 nickname, sdb, PR_TRUE1);
1088}
1089
1090/* see if the symetric CKA_ID already Exists.
1091 */
1092PRBool
1093nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id)
1094{
1095 DBT namekey;
1096 DBT dummy;
1097 int status;
1098
1099 namekey.data = (char *)id->data;
1100 namekey.size = id->len;
1101 status = keydb_Get(handle, &namekey, &dummy, 0);
1102 if (status) {
1103 return PR_FALSE0;
1104 }
1105
1106 return PR_TRUE1;
1107}
1108
1109/* see if the public key for this cert is in the database filed
1110 * by modulus
1111 */
1112PRBool
1113nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert)
1114{
1115 NSSLOWKEYPublicKey *pubkey = NULL((void*)0);
1116 DBT namekey;
1117 DBT dummy;
1118 int status;
1119
1120 /* get cert's public key */
1121 pubkey = nsslowcert_ExtractPublicKey(cert);
1122 if (pubkey == NULL((void*)0)) {
1123 return PR_FALSE0;
1124 }
1125
1126 /* TNH - make key from NSSLOWKEYPublicKey */
1127 switch (pubkey->keyType) {
1128 case NSSLOWKEYRSAKey:
1129 namekey.data = pubkey->u.rsa.modulus.data;
1130 namekey.size = pubkey->u.rsa.modulus.len;
1131 break;
1132 case NSSLOWKEYDSAKey:
1133 namekey.data = pubkey->u.dsa.publicValue.data;
1134 namekey.size = pubkey->u.dsa.publicValue.len;
1135 break;
1136 case NSSLOWKEYDHKey:
1137 namekey.data = pubkey->u.dh.publicValue.data;
1138 namekey.size = pubkey->u.dh.publicValue.len;
1139 break;
1140 case NSSLOWKEYECKey:
1141 namekey.data = pubkey->u.ec.publicValue.data;
1142 namekey.size = pubkey->u.ec.publicValue.len;
1143 break;
1144 default:
1145 /* XXX We don't do Fortezza or DH yet. */
1146 return PR_FALSE0;
1147 }
1148
1149 if (handle->version != 3) {
1150 unsigned char buf[SHA1_LENGTH20];
1151 SHA1_HashBuf(buf, namekey.data, namekey.size);
1152 /* NOTE: don't use pubkey after this! it's now thrashed */
1153 PORT_Memcpymemcpy(namekey.data, buf, sizeof(buf));
1154 namekey.size = sizeof(buf);
1155 }
1156
1157 status = keydb_Get(handle, &namekey, &dummy, 0);
1158 /* some databases have the key stored as a signed value */
1159 if (status) {
1160 unsigned char *buf = (unsigned char *)PORT_AllocPORT_Alloc_Util(namekey.size + 1);
1161 if (buf) {
1162 PORT_Memcpymemcpy(&buf[1], namekey.data, namekey.size);
1163 buf[0] = 0;
1164 namekey.data = buf;
1165 namekey.size++;
1166 status = keydb_Get(handle, &namekey, &dummy, 0);
1167 PORT_FreePORT_Free_Util(buf);
1168 }
1169 }
1170 lg_nsslowkey_DestroyPublicKey(pubkey);
1171 if (status) {
1172 return PR_FALSE0;
1173 }
1174
1175 return PR_TRUE1;
1176}
1177
1178typedef struct NSSLowPasswordDataParamStr {
1179 SECItem salt;
1180 SECItem iter;
1181} NSSLowPasswordDataParam;
1182
1183static const SEC_ASN1Template NSSLOWPasswordParamTemplate[] = {
1184 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(NSSLowPasswordDataParam) },
1185 { SEC_ASN1_OCTET_STRING0x04, offsetof(NSSLowPasswordDataParam, salt)__builtin_offsetof(NSSLowPasswordDataParam, salt) },
1186 { SEC_ASN1_INTEGER0x02, offsetof(NSSLowPasswordDataParam, iter)__builtin_offsetof(NSSLowPasswordDataParam, iter) },
1187 { 0 }
1188};
1189struct LGEncryptedDataInfoStr {
1190 SECAlgorithmID algorithm;
1191 SECItem encryptedData;
1192};
1193typedef struct LGEncryptedDataInfoStr LGEncryptedDataInfo;
1194
1195const SEC_ASN1Template lg_EncryptedDataInfoTemplate[] = {
1196 { SEC_ASN1_SEQUENCE0x10,
1197 0, NULL((void*)0), sizeof(LGEncryptedDataInfo) },
1198 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0,
1199 offsetof(LGEncryptedDataInfo, algorithm)__builtin_offsetof(LGEncryptedDataInfo, algorithm),
1200 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util },
1201 { SEC_ASN1_OCTET_STRING0x04,
1202 offsetof(LGEncryptedDataInfo, encryptedData)__builtin_offsetof(LGEncryptedDataInfo, encryptedData) },
1203 { 0 }
1204};
1205
1206static SECItem *
1207nsslowkey_EncodePW(SECOidTag alg, const SECItem *salt, SECItem *data)
1208{
1209 NSSLowPasswordDataParam param;
1210 LGEncryptedDataInfo edi;
1211 PLArenaPool *arena;
1212 unsigned char one = 1;
1213 SECItem *epw = NULL((void*)0);
1214 SECItem *encParam;
1215 int iterLen = 0;
1216 int saltLen;
1217 SECStatus rv;
1218
1219 param.salt = *salt;
1220 param.iter.type = siBuffer; /* encode as signed integer */
1221 param.iter.data = &one;
1222 param.iter.len = 1;
1223 edi.encryptedData = *data;
1224
1225 iterLen = salt->len > 1 ? salt->data[salt->len - 1] : 2;
1226 saltLen = (salt->len - iterLen) - 1;
1227 /* if the resulting saltLen is a sha hash length, then assume that
1228 * the iteration count is tacked on the end of the buffer */
1229 if ((saltLen == SHA1_LENGTH20) || (saltLen == SHA256_LENGTH32) || (saltLen == SHA384_LENGTH48) || (saltLen == SHA224_LENGTH28) ||
1230 (saltLen == SHA512_LENGTH64)) {
1231 param.iter.data = &salt->data[saltLen];
1232 param.iter.len = iterLen;
1233 param.salt.len = saltLen;
1234 }
1235
1236 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1237 if (arena == NULL((void*)0)) {
1238 return NULL((void*)0);
1239 }
1240
1241 encParam = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(arena, NULL((void*)0), &param,
1242 NSSLOWPasswordParamTemplate);
1243 if (encParam == NULL((void*)0)) {
1244 goto loser;
1245 }
1246 rv = SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(arena, &edi.algorithm, alg, encParam);
1247 if (rv != SECSuccess) {
1248 goto loser;
1249 }
1250 epw = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(NULL((void*)0), NULL((void*)0), &edi, lg_EncryptedDataInfoTemplate);
1251
1252loser:
1253 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1254 return epw;
1255}
1256
1257static SECItem *
1258nsslowkey_DecodePW(const SECItem *derData, SECOidTag *alg, SECItem *salt)
1259{
1260 NSSLowPasswordDataParam param;
1261 LGEncryptedDataInfo edi;
1262 PLArenaPool *arena;
1263 SECItem *pwe = NULL((void*)0);
1264 SECStatus rv;
1265
1266 salt->data = NULL((void*)0);
1267 param.iter.type = siBuffer; /* decode as signed integer */
1268
1269 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1270 if (arena == NULL((void*)0)) {
1271 return NULL((void*)0);
1272 }
1273
1274 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(arena, &edi, lg_EncryptedDataInfoTemplate,
1275 derData);
1276 if (rv != SECSuccess) {
1277 goto loser;
1278 }
1279 *alg = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&edi.algorithm);
1280 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(arena, &param, NSSLOWPasswordParamTemplate,
1281 &edi.algorithm.parameters);
1282 if (rv != SECSuccess) {
1283 goto loser;
1284 }
1285 /* if the iteration count isn't one, tack it at the end of the salt */
1286 if (!((param.iter.len == 1) && (param.iter.data[0] == 1))) {
1287 int total_len = param.salt.len + param.iter.len + 1;
1288 salt->data = PORT_AllocPORT_Alloc_Util(total_len);
1289 if (salt->data == NULL((void*)0)) {
1290 goto loser;
1291 }
1292 PORT_Memcpymemcpy(salt->data, param.salt.data, param.salt.len);
1293 PORT_Memcpymemcpy(&salt->data[param.salt.len], param.iter.data,
1294 param.iter.len);
1295 salt->data[total_len - 1] = param.iter.len;
1296 salt->len = total_len;
1297 } else {
1298 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(NULL((void*)0), salt, &param.salt);
1299 if (rv != SECSuccess) {
1300 goto loser;
1301 }
1302 }
1303 pwe = SECITEM_DupItemSECITEM_DupItem_Util(&edi.encryptedData);
1304
1305loser:
1306 if (!pwe && salt->data) {
1307 PORT_FreePORT_Free_Util(salt->data);
1308 salt->data = NULL((void*)0);
1309 }
1310 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1311 return pwe;
1312}
1313
1314/*
1315 * check to see if the user has a password
1316 */
1317static SECStatus
1318nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle, NSSLOWKEYPasswordEntry *entry)
1319{
1320 DBT checkkey; /*, checkdata; */
1321 NSSLOWKEYDBKey *dbkey = NULL((void*)0);
1322 SECItem *global_salt = NULL((void*)0);
1323 SECItem *item = NULL((void*)0);
1324 SECItem entryData, oid;
1325 SECItem none = { siBuffer, NULL((void*)0), 0 };
1326 SECStatus rv = SECFailure;
1327 SECOidTag algorithm;
1328
1329 if (handle == NULL((void*)0)) {
1330 /* PORT_SetError */
1331 return (SECFailure);
1332 }
1333
1334 global_salt = GetKeyDBGlobalSalt(handle);
1335 if (!global_salt) {
1336 global_salt = &none;
1337 }
1338 if (global_salt->len > sizeof(entry->data)) {
1339 /* PORT_SetError */
1340 goto loser;
1341 }
1342
1343 PORT_Memcpymemcpy(entry->data, global_salt->data, global_salt->len);
1344 entry->salt.data = entry->data;
1345 entry->salt.len = global_salt->len;
1346 entry->value.data = &entry->data[entry->salt.len];
1347
1348 checkkey.data = KEYDB_PW_CHECK_STRING"password-check";
1349 checkkey.size = KEYDB_PW_CHECK_LEN14;
1350 dbkey = get_dbkey(handle, &checkkey);
1351 if (dbkey == NULL((void*)0)) {
1352 /* handle 'FAKE' check here */
1353 goto loser;
1354 }
1355
1356 oid.len = dbkey->derPK.data[0];
1357 oid.data = &dbkey->derPK.data[1];
1358
1359 if (dbkey->derPK.len < (KEYDB_PW_CHECK_LEN14 + 1 + oid.len)) {
1360 goto loser;
1361 }
1362 algorithm = SECOID_FindOIDTagSECOID_FindOIDTag_Util(&oid);
1363 entryData.type = siBuffer;
1364 entryData.len = dbkey->derPK.len - (oid.len + 1);
1365 entryData.data = &dbkey->derPK.data[oid.len + 1];
1366
1367 item = nsslowkey_EncodePW(algorithm, &dbkey->salt, &entryData);
1368 if (!item || (item->len + entry->salt.len) > sizeof(entry->data)) {
1369 goto loser;
1370 }
1371 PORT_Memcpymemcpy(entry->value.data, item->data, item->len);
1372 entry->value.len = item->len;
1373 rv = SECSuccess;
1374
1375loser:
1376 if (item) {
1377 SECITEM_FreeItemSECITEM_FreeItem_Util(item, PR_TRUE1);
1378 }
1379 if (dbkey) {
1380 sec_destroy_dbkey(dbkey);
1381 }
1382 if (global_salt != &none) {
1383 SECITEM_FreeItemSECITEM_FreeItem_Util(global_salt, PR_TRUE1);
1384 }
1385 return rv;
1386}
1387
1388/*
1389 * check to see if the user has a password
1390 */
1391static SECStatus
1392nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle, NSSLOWKEYPasswordEntry *entry)
1393{
1394 DBT checkkey;
1395 NSSLOWKEYDBKey *dbkey = NULL((void*)0);
1396 SECItem *item = NULL((void*)0);
1397 SECItem salt;
1398 SECOidTag algid = SEC_OID_UNKNOWN;
1399 SECStatus rv = SECFailure;
1400 PLArenaPool *arena;
1401 int ret;
1402
1403 if (handle == NULL((void*)0)) {
1404 /* PORT_SetError */
1405 return (SECFailure);
1406 }
1407
1408 checkkey.data = KEYDB_PW_CHECK_STRING"password-check";
1409 checkkey.size = KEYDB_PW_CHECK_LEN14;
1410
1411 salt.data = NULL((void*)0);
1412 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1413 if (arena == NULL((void*)0)) {
1414 return SECFailure;
1415 }
1416
1417 item = nsslowkey_DecodePW(&entry->value, &algid, &salt);
1418 if (item == NULL((void*)0)) {
1419 goto loser;
1420 }
1421
1422 dbkey = PORT_ArenaZNew(arena, NSSLOWKEYDBKey)(NSSLOWKEYDBKey *)PORT_ArenaZAlloc_Util(arena, sizeof(NSSLOWKEYDBKey
))
;
1423 if (dbkey == NULL((void*)0)) {
1424 goto loser;
1425 }
1426
1427 dbkey->arena = arena;
1428
1429 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &dbkey->salt, &salt);
1430 if (rv != SECSuccess) {
1431 goto loser;
1432 }
1433
1434 rv = encodePWCheckEntry(arena, &dbkey->derPK, algid, item);
1435 if (rv != SECSuccess) {
1436 goto loser;
1437 }
1438
1439 rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE1);
1440 if (rv != SECSuccess) {
1441 goto loser;
1442 }
1443
1444 if (handle->global_salt) {
1445 SECITEM_FreeItemSECITEM_FreeItem_Util(handle->global_salt, PR_TRUE1);
1446 handle->global_salt = NULL((void*)0);
1447 }
1448 rv = StoreKeyDBGlobalSalt(handle, &entry->salt);
1449 if (rv != SECSuccess) {
1450 goto loser;
1451 }
1452 ret = keydb_Sync(handle, 0);
1453 if (ret) {
1454 rv = SECFailure;
1455 goto loser;
1456 }
1457 handle->global_salt = GetKeyDBGlobalSalt(handle);
1458
1459loser:
1460 if (item) {
1461 SECITEM_FreeItemSECITEM_FreeItem_Util(item, PR_TRUE1);
1462 }
1463 if (arena) {
1464 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_TRUE1);
1465 }
1466 if (salt.data) {
1467 PORT_FreePORT_Free_Util(salt.data);
1468 }
1469 return rv;
1470}
1471
1472#ifdef EC_DEBUG
1473#define SEC_PRINT(str1, str2, num, sitem) \
1474 printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
1475 str1, str2, num, sitem->len); \
1476 for (i = 0; i < sitem->len; i++) { \
1477 printf("%02x:", sitem->data[i]); \
1478 } \
1479 printf("\n")
1480#else
1481#define SEC_PRINT(a, b, c, d)
1482#endif /* EC_DEBUG */
1483
1484SECStatus
1485seckey_encrypt_private_key(PLArenaPool *permarena, NSSLOWKEYPrivateKey *pk,
1486 SDB *sdbpw, SECItem *result)
1487{
1488 NSSLOWKEYPrivateKeyInfo *pki = NULL((void*)0);
1489 SECStatus rv = SECFailure;
1490 PLArenaPool *temparena = NULL((void*)0);
1491 SECItem *der_item = NULL((void*)0);
1492 SECItem *cipherText = NULL((void*)0);
1493 SECItem *dummy = NULL((void*)0);
1494#ifdef EC_DEBUG
1495 SECItem *fordebug = NULL((void*)0);
1496#endif
1497 int savelen;
1498
1499 temparena = PORT_NewArenaPORT_NewArena_Util(SEC_ASN1_DEFAULT_ARENA_SIZE(2048));
1500 if (temparena == NULL((void*)0))
1501 goto loser;
1502
1503 /* allocate structures */
1504 pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(temparena,
1505 sizeof(NSSLOWKEYPrivateKeyInfo));
1506 der_item = (SECItem *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(temparena, sizeof(SECItem));
1507 if ((pki == NULL((void*)0)) || (der_item == NULL((void*)0)))
1508 goto loser;
1509
1510 /* setup private key info */
1511 dummy = SEC_ASN1EncodeIntegerSEC_ASN1EncodeInteger_Util(temparena, &(pki->version),
1512 NSSLOWKEY_PRIVATE_KEY_INFO_VERSION0);
1513 if (dummy == NULL((void*)0))
1514 goto loser;
1515
1516 /* Encode the key, and set the algorithm (with params) */
1517 switch (pk->keyType) {
1518 case NSSLOWKEYRSAKey:
1519 lg_prepare_low_rsa_priv_key_for_asn1(pk);
1520 dummy = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(temparena, &(pki->privateKey), pk,
1521 lg_nsslowkey_RSAPrivateKeyTemplate);
1522 if (dummy == NULL((void*)0)) {
1523 rv = SECFailure;
1524 goto loser;
1525 }
1526
1527 rv = SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(temparena, &(pki->algorithm),
1528 SEC_OID_PKCS1_RSA_ENCRYPTION, 0);
1529 if (rv == SECFailure) {
1530 goto loser;
1531 }
1532
1533 break;
1534 case NSSLOWKEYDSAKey:
1535 lg_prepare_low_dsa_priv_key_for_asn1(pk);
1536 dummy = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(temparena, &(pki->privateKey), pk,
1537 lg_nsslowkey_DSAPrivateKeyTemplate);
1538 if (dummy == NULL((void*)0)) {
1539 rv = SECFailure;
1540 goto loser;
1541 }
1542
1543 lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
1544 dummy = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(temparena, NULL((void*)0), &pk->u.dsa.params,
1545 lg_nsslowkey_PQGParamsTemplate);
1546 if (dummy == NULL((void*)0)) {
1547 rv = SECFailure;
1548 goto loser;
1549 }
1550
1551 rv = SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(temparena, &(pki->algorithm),
1552 SEC_OID_ANSIX9_DSA_SIGNATURE, dummy);
1553 if (rv == SECFailure) {
1554 goto loser;
1555 }
1556
1557 break;
1558 case NSSLOWKEYDHKey:
1559 lg_prepare_low_dh_priv_key_for_asn1(pk);
1560 dummy = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(temparena, &(pki->privateKey), pk,
1561 lg_nsslowkey_DHPrivateKeyTemplate);
1562 if (dummy == NULL((void*)0)) {
1563 rv = SECFailure;
1564 goto loser;
1565 }
1566
1567 rv = SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(temparena, &(pki->algorithm),
1568 SEC_OID_X942_DIFFIE_HELMAN_KEY, dummy);
1569 if (rv == SECFailure) {
1570 goto loser;
1571 }
1572 break;
1573 case NSSLOWKEYECKey:
1574 lg_prepare_low_ec_priv_key_for_asn1(pk);
1575 /* Public value is encoded as a bit string so adjust length
1576 * to be in bits before ASN encoding and readjust
1577 * immediately after.
1578 *
1579 * Since the SECG specification recommends not including the
1580 * parameters as part of ECPrivateKey, we zero out the curveOID
1581 * length before encoding and restore it later.
1582 */
1583 pk->u.ec.publicValue.len <<= 3;
1584 savelen = pk->u.ec.ecParams.curveOID.len;
1585 pk->u.ec.ecParams.curveOID.len = 0;
1586 dummy = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(temparena, &(pki->privateKey), pk,
1587 lg_nsslowkey_ECPrivateKeyTemplate);
1588 pk->u.ec.ecParams.curveOID.len = savelen;
1589 pk->u.ec.publicValue.len >>= 3;
1590
1591 if (dummy == NULL((void*)0)) {
1592 rv = SECFailure;
1593 goto loser;
1594 }
1595
1596 dummy = &pk->u.ec.ecParams.DEREncoding;
1597
1598 /* At this point dummy should contain the encoded params */
1599 rv = SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(temparena, &(pki->algorithm),
1600 SEC_OID_ANSIX962_EC_PUBLIC_KEY, dummy);
1601
1602 if (rv == SECFailure) {
1603 goto loser;
1604 }
1605
1606#ifdef EC_DEBUG
1607 fordebug = &(pki->privateKey);
1608 SEC_PRINT("seckey_encrypt_private_key()", "PrivateKey",
1609 pk->keyType, fordebug);
1610#endif
1611
1612 break;
1613 default:
1614 /* We don't support DH or Fortezza private keys yet */
1615 PORT_Assert(PR_FALSE)((0)?((void)0):PR_Assert("PR_FALSE","keydb.c",1615));
1616 break;
1617 }
1618
1619 /* setup encrypted private key info */
1620 dummy = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(temparena, der_item, pki,
1621 lg_nsslowkey_PrivateKeyInfoTemplate);
1622
1623 SEC_PRINT("seckey_encrypt_private_key()", "PrivateKeyInfo",
1624 pk->keyType, der_item);
1625
1626 if (dummy == NULL((void*)0)) {
1627 rv = SECFailure;
1628 goto loser;
1629 }
1630
1631 rv = lg_util_encrypt(temparena, sdbpw, dummy, &cipherText);
1632 if (rv != SECSuccess) {
1633 goto loser;
1634 }
1635
1636 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(permarena, result, cipherText);
1637
1638loser:
1639
1640 if (temparena != NULL((void*)0))
1641 PORT_FreeArenaPORT_FreeArena_Util(temparena, PR_TRUE1);
1642
1643 return rv;
1644}
1645
1646static SECStatus
1647seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SDB *sdbpw,
1648 NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update)
1649{
1650 NSSLOWKEYDBKey *dbkey = NULL((void*)0);
1651 PLArenaPool *arena = NULL((void*)0);
1652 SECStatus rv = SECFailure;
1653
1654 if ((keydb == NULL((void*)0)) || (index == NULL((void*)0)) || (sdbpw == NULL((void*)0)) ||
1655 (pk == NULL((void*)0)))
1656 return SECFailure;
1657
1658 arena = PORT_NewArenaPORT_NewArena_Util(SEC_ASN1_DEFAULT_ARENA_SIZE(2048));
1659 if (arena == NULL((void*)0))
1660 return SECFailure;
1661
1662 dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, sizeof(NSSLOWKEYDBKey));
1663 if (dbkey == NULL((void*)0))
1664 goto loser;
1665 dbkey->arena = arena;
1666 dbkey->nickname = nickname;
1667
1668 rv = seckey_encrypt_private_key(arena, pk, sdbpw, &dbkey->derPK);
1669 if (rv != SECSuccess)
1670 goto loser;
1671
1672 rv = put_dbkey(keydb, index, dbkey, update);
1673
1674/* let success fall through */
1675loser:
1676 if (arena != NULL((void*)0))
1677 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_TRUE1);
1678
1679 return rv;
1680}
1681
1682/*
1683 * Store a key in the database, indexed by its public key modulus.
1684 * Note that the nickname is optional. It was only used by keyutil.
1685 */
1686SECStatus
1687nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle,
1688 NSSLOWKEYPrivateKey *privkey,
1689 SECItem *pubKeyData,
1690 char *nickname,
1691 SDB *sdbpw,
1692 PRBool update)
1693{
1694 DBT namekey;
1695 SECStatus rv;
1696
1697 if (handle == NULL((void*)0)) {
1698 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1699 return (SECFailure);
1700 }
1701
1702 /* set up db key and data */
1703 namekey.data = pubKeyData->data;
1704 namekey.size = pubKeyData->len;
1705
1706 /* encrypt the private key */
1707 rv = seckey_put_private_key(handle, &namekey, sdbpw, privkey, nickname,
1708 update);
1709
1710 return (rv);
1711}
1712
1713static NSSLOWKEYPrivateKey *
1714seckey_decrypt_private_key(SECItem *epki,
1715 SDB *sdbpw)
1716{
1717 NSSLOWKEYPrivateKey *pk = NULL((void*)0);
1718 NSSLOWKEYPrivateKeyInfo *pki = NULL((void*)0);
1719 SECStatus rv = SECFailure;
1720 PLArenaPool *temparena = NULL((void*)0), *permarena = NULL((void*)0);
1721 SECItem *dest = NULL((void*)0);
1722#ifdef EC_DEBUG
1723 SECItem *fordebug = NULL((void*)0);
1724#endif
1725
1726 if ((epki == NULL((void*)0)) || (sdbpw == NULL((void*)0)))
1727 goto loser;
1728
1729 temparena = PORT_NewArenaPORT_NewArena_Util(SEC_ASN1_DEFAULT_ARENA_SIZE(2048));
1730 permarena = PORT_NewArenaPORT_NewArena_Util(SEC_ASN1_DEFAULT_ARENA_SIZE(2048));
1731 if ((temparena == NULL((void*)0)) || (permarena == NULL((void*)0)))
1732 goto loser;
1733
1734 /* allocate temporary items */
1735 pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(temparena,
1736 sizeof(NSSLOWKEYPrivateKeyInfo));
1737
1738 /* allocate permanent arena items */
1739 pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(permarena,
1740 sizeof(NSSLOWKEYPrivateKey));
1741
1742 if ((pk == NULL((void*)0)) || (pki == NULL((void*)0)))
1743 goto loser;
1744
1745 pk->arena = permarena;
1746
1747 rv = lg_util_decrypt(sdbpw, epki, &dest);
1748 if (rv != SECSuccess) {
1749 goto loser;
1750 }
1751
1752 if (dest != NULL((void*)0)) {
1753 SECItem newPrivateKey;
1754 SECItem newAlgParms;
1755
1756 SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1,
1757 dest);
1758
1759 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(temparena, pki,
1760 lg_nsslowkey_PrivateKeyInfoTemplate, dest);
1761 if (rv == SECSuccess) {
1762 switch (SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&pki->algorithm)) {
1763 case SEC_OID_X500_RSA_ENCRYPTION:
1764 case SEC_OID_PKCS1_RSA_ENCRYPTION:
1765 pk->keyType = NSSLOWKEYRSAKey;
1766 lg_prepare_low_rsa_priv_key_for_asn1(pk);
1767 if (SECSuccess != SECITEM_CopyItemSECITEM_CopyItem_Util(permarena, &newPrivateKey,
1768 &pki->privateKey))
1769 break;
1770 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(permarena, pk,
1771 lg_nsslowkey_RSAPrivateKeyTemplate,
1772 &newPrivateKey);
1773 if (rv == SECSuccess) {
1774 break;
1775 }
1776 /* Try decoding with the alternative template, but only allow
1777 * a zero-length modulus for a secret key object.
1778 * See bug 715073.
1779 */
1780 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(permarena, pk,
1781 lg_nsslowkey_RSAPrivateKeyTemplate2,
1782 &newPrivateKey);
1783 /* A publicExponent of 0 is the defining property of a secret
1784 * key disguised as an RSA key. When decoding with the
1785 * alternative template, only accept a secret key with an
1786 * improperly encoded modulus and a publicExponent of 0.
1787 */
1788 if (rv == SECSuccess) {
1789 if (pk->u.rsa.modulus.len == 2 &&
1790 pk->u.rsa.modulus.data[0] == SEC_ASN1_INTEGER0x02 &&
1791 pk->u.rsa.modulus.data[1] == 0 &&
1792 pk->u.rsa.publicExponent.len == 1 &&
1793 pk->u.rsa.publicExponent.data[0] == 0) {
1794 /* Fix the zero-length integer by setting it to 0. */
1795 pk->u.rsa.modulus.data = pk->u.rsa.publicExponent.data;
1796 pk->u.rsa.modulus.len = pk->u.rsa.publicExponent.len;
1797 } else {
1798 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DER);
1799 rv = SECFailure;
1800 }
1801 }
1802 break;
1803 case SEC_OID_ANSIX9_DSA_SIGNATURE:
1804 pk->keyType = NSSLOWKEYDSAKey;
1805 lg_prepare_low_dsa_priv_key_for_asn1(pk);
1806 if (SECSuccess != SECITEM_CopyItemSECITEM_CopyItem_Util(permarena, &newPrivateKey,
1807 &pki->privateKey))
1808 break;
1809 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(permarena, pk,
1810 lg_nsslowkey_DSAPrivateKeyTemplate,
1811 &newPrivateKey);
1812 if (rv != SECSuccess)
1813 goto loser;
1814 lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
1815 if (SECSuccess != SECITEM_CopyItemSECITEM_CopyItem_Util(permarena, &newAlgParms,
1816 &pki->algorithm.parameters))
1817 break;
1818 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(permarena, &pk->u.dsa.params,
1819 lg_nsslowkey_PQGParamsTemplate,
1820 &newAlgParms);
1821 break;
1822 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
1823 pk->keyType = NSSLOWKEYDHKey;
1824 lg_prepare_low_dh_priv_key_for_asn1(pk);
1825 if (SECSuccess != SECITEM_CopyItemSECITEM_CopyItem_Util(permarena, &newPrivateKey,
1826 &pki->privateKey))
1827 break;
1828 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(permarena, pk,
1829 lg_nsslowkey_DHPrivateKeyTemplate,
1830 &newPrivateKey);
1831 break;
1832 case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
1833 pk->keyType = NSSLOWKEYECKey;
1834 lg_prepare_low_ec_priv_key_for_asn1(pk);
1835
1836#ifdef EC_DEBUG
1837 fordebug = &pki->privateKey;
1838 SEC_PRINT("seckey_decrypt_private_key()", "PrivateKey",
1839 pk->keyType, fordebug);
1840#endif
1841 if (SECSuccess != SECITEM_CopyItemSECITEM_CopyItem_Util(permarena, &newPrivateKey,
1842 &pki->privateKey))
1843 break;
1844 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(permarena, pk,
1845 lg_nsslowkey_ECPrivateKeyTemplate,
1846 &newPrivateKey);
1847 if (rv != SECSuccess)
1848 goto loser;
1849
1850 lg_prepare_low_ecparams_for_asn1(&pk->u.ec.ecParams);
1851
1852 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(permarena,
1853 &pk->u.ec.ecParams.DEREncoding,
1854 &pki->algorithm.parameters);
1855
1856 if (rv != SECSuccess)
1857 goto loser;
1858
1859 /* Fill out the rest of EC params */
1860 rv = LGEC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding,
1861 &pk->u.ec.ecParams);
1862
1863 if (rv != SECSuccess)
1864 goto loser;
1865
1866 if (pk->u.ec.publicValue.len != 0) {
1867 pk->u.ec.publicValue.len >>= 3;
1868 }
1869
1870 break;
1871 default:
1872 rv = SECFailure;
1873 break;
1874 }
1875 } else if (PORT_GetErrorPORT_GetError_Util() == SEC_ERROR_BAD_DER) {
1876 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_PASSWORD);
1877 goto loser;
1878 }
1879 }
1880
1881/* let success fall through */
1882loser:
1883 if (temparena != NULL((void*)0))
1884 PORT_FreeArenaPORT_FreeArena_Util(temparena, PR_TRUE1);
1885 if (dest != NULL((void*)0))
1886 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(dest, PR_TRUE1);
1887
1888 if (rv != SECSuccess) {
1889 if (permarena != NULL((void*)0))
1890 PORT_FreeArenaPORT_FreeArena_Util(permarena, PR_TRUE1);
1891 pk = NULL((void*)0);
1892 }
1893
1894 return pk;
1895}
1896
1897static NSSLOWKEYPrivateKey *
1898seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SDB *sdbpw)
1899{
1900 if ((dbkey == NULL((void*)0)) || (sdbpw == NULL((void*)0))) {
1901 return NULL((void*)0);
1902 }
1903
1904 return seckey_decrypt_private_key(&(dbkey->derPK), sdbpw);
1905}
1906
1907static NSSLOWKEYPrivateKey *
1908seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname,
1909 SDB *sdbpw)
1910{
1911 NSSLOWKEYDBKey *dbkey = NULL((void*)0);
1912 NSSLOWKEYPrivateKey *pk = NULL((void*)0);
1913
1914 if ((keydb == NULL((void*)0)) || (index == NULL((void*)0)) || (sdbpw == NULL((void*)0))) {
1915 return NULL((void*)0);
1916 }
1917
1918 dbkey = get_dbkey(keydb, index);
1919 if (dbkey == NULL((void*)0)) {
1920 goto loser;
1921 }
1922
1923 if (nickname) {
1924 if (dbkey->nickname && (dbkey->nickname[0] != 0)) {
1925 *nickname = PORT_StrdupPORT_Strdup_Util(dbkey->nickname);
1926 } else {
1927 *nickname = NULL((void*)0);
1928 }
1929 }
1930
1931 pk = seckey_decode_encrypted_private_key(dbkey, sdbpw);
1932
1933/* let success fall through */
1934loser:
1935
1936 if (dbkey != NULL((void*)0)) {
1937 sec_destroy_dbkey(dbkey);
1938 }
1939
1940 return pk;
1941}
1942
1943/*
1944 * Find a key in the database, indexed by its public key modulus
1945 * This is used to find keys that have been stored before their
1946 * certificate arrives. Once the certificate arrives the key
1947 * is looked up by the public modulus in the certificate, and the
1948 * re-stored by its nickname.
1949 */
1950NSSLOWKEYPrivateKey *
1951nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus,
1952 SDB *sdbpw)
1953{
1954 DBT namekey;
1955 NSSLOWKEYPrivateKey *pk = NULL((void*)0);
1956
1957 if (handle == NULL((void*)0)) {
1958 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1959 return NULL((void*)0);
1960 }
1961
1962 /* set up db key */
1963 namekey.data = modulus->data;
1964 namekey.size = modulus->len;
1965
1966 pk = seckey_get_private_key(handle, &namekey, NULL((void*)0), sdbpw);
1967
1968 /* no need to free dbkey, since its on the stack, and the data it
1969 * points to is owned by the database
1970 */
1971 return (pk);
1972}
1973
1974char *
1975nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle,
1976 SECItem *modulus, SDB *sdbpw)
1977{
1978 DBT namekey;
1979 NSSLOWKEYPrivateKey *pk = NULL((void*)0);
1980 char *nickname = NULL((void*)0);
1981
1982 if (handle == NULL((void*)0)) {
1983 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1984 return NULL((void*)0);
1985 }
1986
1987 /* set up db key */
1988 namekey.data = modulus->data;
1989 namekey.size = modulus->len;
1990
1991 pk = seckey_get_private_key(handle, &namekey, &nickname, sdbpw);
1992 if (pk) {
1993 lg_nsslowkey_DestroyPrivateKey(pk);
1994 }
1995
1996 /* no need to free dbkey, since its on the stack, and the data it
1997 * points to is owned by the database
1998 */
1999 return (nickname);
2000}
2001/* ===== ENCODING ROUTINES ===== */
2002
2003static SECStatus
2004encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
2005 SECItem *encCheck)
2006{
2007 SECOidData *oidData;
2008
2009 oidData = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(alg);
2010 if (oidData == NULL((void*)0)) {
2011 return SECFailure;
2012 }
2013
2014 entry->len = 1 + oidData->oid.len + encCheck->len;
2015 if (arena) {
2016 entry->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, entry->len);
2017 } else {
2018 entry->data = (unsigned char *)PORT_AllocPORT_Alloc_Util(entry->len);
2019 }
2020
2021 if (entry->data == NULL((void*)0)) {
2022 return SECFailure;
2023 }
2024
2025 /* first length of oid */
2026 entry->data[0] = (unsigned char)oidData->oid.len;
2027 /* next oid itself */
2028 PORT_Memcpymemcpy(&entry->data[1], oidData->oid.data, oidData->oid.len);
2029 /* finally the encrypted check string */
2030 PORT_Memcpymemcpy(&entry->data[1 + oidData->oid.len], encCheck->data,
2031 encCheck->len);
2032
2033 return SECSuccess;
2034}
2035
2036#define MAX_DB_SIZE0xffff 0xffff
2037/*
2038 * Clear out all the keys in the existing database
2039 */
2040static SECStatus
2041nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle)
2042{
2043 SECStatus rv;
2044 int errors = 0;
2045
2046 if (handle->db == NULL((void*)0)) {
2047 return (SECSuccess);
2048 }
2049
2050 if (handle->readOnly) {
2051 /* set an error code */
2052 return SECFailure;
2053 }
2054
2055 if (handle->appname == NULL((void*)0) && handle->dbname == NULL((void*)0)) {
2056 return SECFailure;
2057 }
2058
2059 keydb_Close(handle);
2060 if (handle->appname) {
2061 handle->db =
2062 rdbopen(handle->appname, handle->dbname, "key", NO_CREATE(02 | 0100 | 01000), NULL((void*)0));
2063 } else {
2064 handle->db = dbopen(handle->dbname, NO_CREATE(02 | 0100 | 01000), 0600, DB_HASH, 0);
2065 }
2066 if (handle->db == NULL((void*)0)) {
2067 /* set an error code */
2068 return SECFailure;
2069 }
2070
2071 rv = makeGlobalVersion(handle);
2072 if (rv != SECSuccess) {
2073 errors++;
2074 goto done;
2075 }
2076
2077 if (handle->global_salt) {
2078 rv = StoreKeyDBGlobalSalt(handle, handle->global_salt);
2079 } else {
2080 rv = makeGlobalSalt(handle);
2081 if (rv == SECSuccess) {
2082 handle->global_salt = GetKeyDBGlobalSalt(handle);
2083 }
2084 }
2085 if (rv != SECSuccess) {
2086 errors++;
2087 }
2088
2089done:
2090 /* sync the database */
2091 (void)keydb_Sync(handle, 0);
2092 db_InitComplete(handle->db);
2093
2094 return (errors == 0 ? SECSuccess : SECFailure);
2095}
2096
2097static int
2098keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
2099{
2100 int ret;
2101 PRLock *kdbLock = kdb->lock;
2102 DB *db = kdb->db;
2103
2104 PORT_Assert(kdbLock != NULL)((kdbLock != ((void*)0))?((void)0):PR_Assert("kdbLock != NULL"
,"keydb.c",2104))
;
2105 PZ_Lock(kdbLock)PR_Lock((kdbLock));
2106
2107 ret = (*db->get)(db, key, data, flags);
2108
2109 (void)PZ_Unlock(kdbLock)PR_Unlock((kdbLock));
2110
2111 return (ret);
2112}
2113
2114static int
2115keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
2116{
2117 int ret = 0;
2118 PRLock *kdbLock = kdb->lock;
2119 DB *db = kdb->db;
2120
2121 PORT_Assert(kdbLock != NULL)((kdbLock != ((void*)0))?((void)0):PR_Assert("kdbLock != NULL"
,"keydb.c",2121))
;
2122 PZ_Lock(kdbLock)PR_Lock((kdbLock));
2123
2124 ret = (*db->put)(db, key, data, flags);
2125
2126 (void)PZ_Unlock(kdbLock)PR_Unlock((kdbLock));
2127
2128 return (ret);
2129}
2130
2131static int
2132keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags)
2133{
2134 int ret;
2135 PRLock *kdbLock = kdb->lock;
2136 DB *db = kdb->db;
2137
2138 PORT_Assert(kdbLock != NULL)((kdbLock != ((void*)0))?((void)0):PR_Assert("kdbLock != NULL"
,"keydb.c",2138))
;
2139 PZ_Lock(kdbLock)PR_Lock((kdbLock));
2140
2141 ret = (*db->sync)(db, flags);
2142
2143 (void)PZ_Unlock(kdbLock)PR_Unlock((kdbLock));
2144
2145 return (ret);
2146}
2147
2148static int
2149keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags)
2150{
2151 int ret;
2152 PRLock *kdbLock = kdb->lock;
2153 DB *db = kdb->db;
2154
2155 PORT_Assert(kdbLock != NULL)((kdbLock != ((void*)0))?((void)0):PR_Assert("kdbLock != NULL"
,"keydb.c",2155))
;
2156 PZ_Lock(kdbLock)PR_Lock((kdbLock));
2157
2158 ret = (*db->del)(db, key, flags);
2159
2160 (void)PZ_Unlock(kdbLock)PR_Unlock((kdbLock));
2161
2162 return (ret);
2163}
2164
2165static int
2166keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
2167{
2168 int ret;
2169 PRLock *kdbLock = kdb->lock;
2170 DB *db = kdb->db;
2171
2172 PORT_Assert(kdbLock != NULL)((kdbLock != ((void*)0))?((void)0):PR_Assert("kdbLock != NULL"
,"keydb.c",2172))
;
2173 PZ_Lock(kdbLock)PR_Lock((kdbLock));
2174
2175 ret = (*db->seq)(db, key, data, flags);
2176
2177 (void)PZ_Unlock(kdbLock)PR_Unlock((kdbLock));
2178
2179 return (ret);
2180}
2181
2182static void
2183keydb_Close(NSSLOWKEYDBHandle *kdb)
2184{
2185 PRLock *kdbLock = kdb->lock;
2186 DB *db = kdb->db;
2187
2188 PORT_Assert(kdbLock != NULL)((kdbLock != ((void*)0))?((void)0):PR_Assert("kdbLock != NULL"
,"keydb.c",2188))
;
2189 SKIP_AFTER_FORK(PZ_Lock(kdbLock))if (!lg_parentForkedAfterC_Initialize) PR_Lock((kdbLock));
2190
2191 (*db->close)(db);
2192
2193 SKIP_AFTER_FORK(PZ_Unlock(kdbLock))if (!lg_parentForkedAfterC_Initialize) PR_Unlock((kdbLock));
2194
2195 return;
2196}
2197
2198/*
2199 * SDB Entry Points for the Key DB
2200 */
2201
2202CK_RV
2203lg_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2)
2204{
2205 NSSLOWKEYDBHandle *keydb;
2206 NSSLOWKEYPasswordEntry entry;
2207 SECStatus rv;
2208
2209 keydb = lg_getKeyDB(sdb);
2210 if (keydb == NULL((void*)0)) {
2211 return CKR_TOKEN_WRITE_PROTECTED0x000000E2UL;
2212 }
2213 if (PORT_Strcmpstrcmp(id, "password") != 0) {
2214 /* shouldn't happen */
2215 return CKR_GENERAL_ERROR0x00000005UL; /* no extra data stored */
2216 }
2217 rv = nsslowkey_GetPWCheckEntry(keydb, &entry);
2218 if (rv != SECSuccess) {
2219 return CKR_GENERAL_ERROR0x00000005UL;
2220 }
2221 item1->len = entry.salt.len;
2222 PORT_Memcpymemcpy(item1->data, entry.salt.data, item1->len);
2223 item2->len = entry.value.len;
2224 PORT_Memcpymemcpy(item2->data, entry.value.data, item2->len);
2225 return CKR_OK0x00000000UL;
2226}
2227
2228CK_RV
2229lg_PutMetaData(SDB *sdb, const char *id,
2230 const SECItem *item1, const SECItem *item2)
2231{
2232 NSSLOWKEYDBHandle *keydb;
2233 NSSLOWKEYPasswordEntry entry;
2234 SECStatus rv;
2235
2236 keydb = lg_getKeyDB(sdb);
2237 if (keydb == NULL((void*)0)) {
2238 return CKR_TOKEN_WRITE_PROTECTED0x000000E2UL;
2239 }
2240 if (PORT_Strcmpstrcmp(id, "password") != 0) {
2241 /* shouldn't happen */
2242 return CKR_GENERAL_ERROR0x00000005UL; /* no extra data stored */
2243 }
2244 entry.salt = *item1;
2245 entry.value = *item2;
2246 rv = nsslowkey_PutPWCheckEntry(keydb, &entry);
2247 if (rv != SECSuccess) {
2248 return CKR_GENERAL_ERROR0x00000005UL;
2249 }
2250 return CKR_OK0x00000000UL;
2251}
2252
2253CK_RV
2254lg_DestroyMetaData(SDB *db, const char *id)
2255{
2256 return CKR_GENERAL_ERROR0x00000005UL; /* no extra data stored */
2257}
2258
2259CK_RV
2260lg_Reset(SDB *sdb)
2261{
2262 NSSLOWKEYDBHandle *keydb;
2263 SECStatus rv;
2264
2265 keydb = lg_getKeyDB(sdb);
2266 if (keydb == NULL((void*)0)) {
2267 return CKR_TOKEN_WRITE_PROTECTED0x000000E2UL;
2268 }
2269 rv = nsslowkey_ResetKeyDB(keydb);
2270 if (rv != SECSuccess) {
2271 return CKR_GENERAL_ERROR0x00000005UL;
2272 }
2273 return CKR_OK0x00000000UL;
2274}