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 "secerr.h"
13
14 #include "keydbi.h"
15 #include "lgdb.h"
16
17 /*
18 * Record keys for keydb
19 */
20 #define SALT_STRING "global-salt"
21 #define VERSION_STRING "Version"
22 #define KEYDB_PW_CHECK_STRING "password-check"
23 #define KEYDB_PW_CHECK_LEN 14
24 #define KEYDB_FAKE_PW_CHECK_STRING "fake-password-check"
25 #define KEYDB_FAKE_PW_CHECK_LEN 19
26
27 /* Size of the global salt for key database */
28 #define SALT_LENGTH 16
29
30 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
31
32 const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = {
33 { SEC_ASN1_SEQUENCE,
34 0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) },
35 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
36 offsetof(NSSLOWKEYEncryptedPrivateKeyInfo, algorithm),
37 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
38 { SEC_ASN1_OCTET_STRING,
39 offsetof(NSSLOWKEYEncryptedPrivateKeyInfo, encryptedData) },
40 { 0 }
41 };
42
43 const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = {
44 { SEC_ASN1_POINTER, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate }
45 };
46
47 /* ====== Default key databse encryption algorithm ====== */
48 static void
sec_destroy_dbkey(NSSLOWKEYDBKey * dbkey)49 sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey)
50 {
51 if (dbkey && dbkey->arena) {
52 PORT_FreeArena(dbkey->arena, PR_FALSE);
53 }
54 }
55
56 static void
free_dbt(DBT * dbt)57 free_dbt(DBT *dbt)
58 {
59 if (dbt) {
60 PORT_Free(dbt->data);
61 PORT_Free(dbt);
62 }
63
64 return;
65 }
66
67 static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
68 unsigned int flags);
69 static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
70 unsigned int flags);
71 static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags);
72 static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags);
73 static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
74 unsigned int flags);
75 static void keydb_Close(NSSLOWKEYDBHandle *db);
76
77 /*
78 * format of key database entries for version 3 of database:
79 * byte offset field
80 * ----------- -----
81 * 0 version
82 * 1 salt-len
83 * 2 nn-len
84 * 3.. salt-data
85 * ... nickname
86 * ... encrypted-key-data
87 */
88 static DBT *
encode_dbkey(NSSLOWKEYDBKey * dbkey,unsigned char version)89 encode_dbkey(NSSLOWKEYDBKey *dbkey, unsigned char version)
90 {
91 DBT *bufitem = NULL;
92 unsigned char *buf;
93 int nnlen;
94 char *nn;
95
96 bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT));
97 if (bufitem == NULL) {
98 goto loser;
99 }
100
101 if (dbkey->nickname) {
102 nn = dbkey->nickname;
103 nnlen = PORT_Strlen(nn) + 1;
104 } else {
105 nn = "";
106 nnlen = 1;
107 }
108
109 /* compute the length of the record */
110 /* 1 + 1 + 1 == version number header + salt length + nn len */
111 bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1;
112
113 bufitem->data = (void *)PORT_ZAlloc(bufitem->size);
114 if (bufitem->data == NULL) {
115 goto loser;
116 }
117
118 buf = (unsigned char *)bufitem->data;
119
120 /* set version number */
121 buf[0] = version;
122
123 /* set length of salt */
124 PORT_Assert(dbkey->salt.len < 256);
125 buf[1] = dbkey->salt.len;
126
127 /* set length of nickname */
128 PORT_Assert(nnlen < 256);
129 buf[2] = nnlen;
130
131 /* copy salt */
132 if (dbkey->salt.len > 0) {
133 PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len);
134 }
135
136 /* copy nickname */
137 PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen);
138
139 /* copy encrypted key */
140 PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data,
141 dbkey->derPK.len);
142
143 return (bufitem);
144
145 loser:
146 if (bufitem) {
147 free_dbt(bufitem);
148 }
149
150 return (NULL);
151 }
152
153 static NSSLOWKEYDBKey *
decode_dbkey(DBT * bufitem,int expectedVersion)154 decode_dbkey(DBT *bufitem, int expectedVersion)
155 {
156 NSSLOWKEYDBKey *dbkey;
157 PLArenaPool *arena = NULL;
158 unsigned char *buf;
159 int version;
160 int keyoff;
161 int nnlen;
162 int saltoff;
163
164 buf = (unsigned char *)bufitem->data;
165
166 version = buf[0];
167
168 if (version != expectedVersion) {
169 goto loser;
170 }
171
172 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
173 if (arena == NULL) {
174 goto loser;
175 }
176
177 dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
178 if (dbkey == NULL) {
179 goto loser;
180 }
181
182 dbkey->arena = arena;
183 dbkey->salt.data = NULL;
184 dbkey->derPK.data = NULL;
185
186 dbkey->salt.len = buf[1];
187 dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len);
188 if (dbkey->salt.data == NULL) {
189 goto loser;
190 }
191
192 saltoff = 2;
193 keyoff = 2 + dbkey->salt.len;
194
195 if (expectedVersion >= 3) {
196 nnlen = buf[2];
197 if (nnlen) {
198 dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1);
199 if (dbkey->nickname) {
200 PORT_Memcpy(dbkey->nickname, &buf[keyoff + 1], nnlen);
201 }
202 }
203 keyoff += (nnlen + 1);
204 saltoff = 3;
205 }
206
207 PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len);
208
209 dbkey->derPK.len = bufitem->size - keyoff;
210 dbkey->derPK.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->derPK.len);
211 if (dbkey->derPK.data == NULL) {
212 goto loser;
213 }
214
215 PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len);
216
217 return (dbkey);
218
219 loser:
220
221 if (arena) {
222 PORT_FreeArena(arena, PR_FALSE);
223 }
224
225 return (NULL);
226 }
227
228 static NSSLOWKEYDBKey *
get_dbkey(NSSLOWKEYDBHandle * handle,DBT * index)229 get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index)
230 {
231 NSSLOWKEYDBKey *dbkey;
232 DBT entry;
233 int ret;
234
235 /* get it from the database */
236 ret = keydb_Get(handle, index, &entry, 0);
237 if (ret) {
238 PORT_SetError(SEC_ERROR_BAD_DATABASE);
239 return NULL;
240 }
241
242 /* set up dbkey struct */
243
244 dbkey = decode_dbkey(&entry, handle->version);
245
246 return (dbkey);
247 }
248
249 static SECStatus
put_dbkey(NSSLOWKEYDBHandle * handle,DBT * index,NSSLOWKEYDBKey * dbkey,PRBool update)250 put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update)
251 {
252 DBT *keydata = NULL;
253 int status;
254
255 keydata = encode_dbkey(dbkey, handle->version);
256 if (keydata == NULL) {
257 goto loser;
258 }
259
260 /* put it in the database */
261 if (update) {
262 status = keydb_Put(handle, index, keydata, 0);
263 } else {
264 status = keydb_Put(handle, index, keydata, R_NOOVERWRITE);
265 }
266
267 if (status) {
268 goto loser;
269 }
270
271 /* sync the database */
272 status = keydb_Sync(handle, 0);
273 if (status) {
274 goto loser;
275 }
276
277 free_dbt(keydata);
278 return (SECSuccess);
279
280 loser:
281 if (keydata) {
282 free_dbt(keydata);
283 }
284
285 return (SECFailure);
286 }
287
288 SECStatus
nsslowkey_TraverseKeys(NSSLOWKEYDBHandle * handle,SECStatus (* keyfunc)(DBT * k,DBT * d,void * pdata),void * udata)289 nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle,
290 SECStatus (*keyfunc)(DBT *k, DBT *d, void *pdata),
291 void *udata)
292 {
293 DBT data;
294 DBT key;
295 SECStatus status;
296 int ret;
297
298 if (handle == NULL) {
299 return (SECFailure);
300 }
301
302 ret = keydb_Seq(handle, &key, &data, R_FIRST);
303 if (ret) {
304 return (SECFailure);
305 }
306
307 do {
308 /* skip version record */
309 if (data.size > 1) {
310 if (key.size == (sizeof(SALT_STRING) - 1)) {
311 if (PORT_Memcmp(key.data, SALT_STRING, key.size) == 0) {
312 continue;
313 }
314 }
315
316 /* skip password check */
317 if (key.size == KEYDB_PW_CHECK_LEN) {
318 if (PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,
319 KEYDB_PW_CHECK_LEN) == 0) {
320 continue;
321 }
322 }
323
324 status = (*keyfunc)(&key, &data, udata);
325 if (status != SECSuccess) {
326 return (status);
327 }
328 }
329 } while (keydb_Seq(handle, &key, &data, R_NEXT) == 0);
330
331 return (SECSuccess);
332 }
333
334 #ifdef notdef
335 typedef struct keyNode {
336 struct keyNode *next;
337 DBT key;
338 } keyNode;
339
340 typedef struct {
341 PLArenaPool *arena;
342 keyNode *head;
343 } keyList;
344
345 static SECStatus
sec_add_key_to_list(DBT * key,DBT * data,void * arg)346 sec_add_key_to_list(DBT *key, DBT *data, void *arg)
347 {
348 keyList *keylist;
349 keyNode *node;
350 void *keydata;
351
352 keylist = (keyList *)arg;
353
354 /* allocate the node struct */
355 node = (keyNode *)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode));
356 if (node == NULL) {
357 return (SECFailure);
358 }
359
360 /* allocate room for key data */
361 keydata = PORT_ArenaZAlloc(keylist->arena, key->size);
362 if (keydata == NULL) {
363 return (SECFailure);
364 }
365
366 /* link node into list */
367 node->next = keylist->head;
368 keylist->head = node;
369
370 /* copy key into node */
371 PORT_Memcpy(keydata, key->data, key->size);
372 node->key.size = key->size;
373 node->key.data = keydata;
374
375 return (SECSuccess);
376 }
377 #endif
378
379 static SECItem *
decodeKeyDBGlobalSalt(DBT * saltData)380 decodeKeyDBGlobalSalt(DBT *saltData)
381 {
382 SECItem *saltitem;
383
384 saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
385 if (saltitem == NULL) {
386 return (NULL);
387 }
388
389 saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size);
390 if (saltitem->data == NULL) {
391 PORT_Free(saltitem);
392 return (NULL);
393 }
394
395 saltitem->len = saltData->size;
396 PORT_Memcpy(saltitem->data, saltData->data, saltitem->len);
397
398 return (saltitem);
399 }
400
401 static SECItem *
GetKeyDBGlobalSalt(NSSLOWKEYDBHandle * handle)402 GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
403 {
404 DBT saltKey;
405 DBT saltData;
406 int ret;
407
408 saltKey.data = SALT_STRING;
409 saltKey.size = sizeof(SALT_STRING) - 1;
410
411 ret = keydb_Get(handle, &saltKey, &saltData, 0);
412 if (ret) {
413 return (NULL);
414 }
415
416 return (decodeKeyDBGlobalSalt(&saltData));
417 }
418
419 static SECStatus
StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle * handle,SECItem * salt)420 StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle, SECItem *salt)
421 {
422 DBT saltKey;
423 DBT saltData;
424 int status;
425
426 saltKey.data = SALT_STRING;
427 saltKey.size = sizeof(SALT_STRING) - 1;
428
429 saltData.data = (void *)salt->data;
430 saltData.size = salt->len;
431
432 /* put global salt into the database now */
433 status = keydb_Put(handle, &saltKey, &saltData, 0);
434 if (status) {
435 return (SECFailure);
436 }
437
438 return (SECSuccess);
439 }
440
441 static SECStatus
makeGlobalVersion(NSSLOWKEYDBHandle * handle)442 makeGlobalVersion(NSSLOWKEYDBHandle *handle)
443 {
444 unsigned char version;
445 DBT versionData;
446 DBT versionKey;
447 int status;
448
449 version = NSSLOWKEY_DB_FILE_VERSION;
450 versionData.data = &version;
451 versionData.size = 1;
452 versionKey.data = VERSION_STRING;
453 versionKey.size = sizeof(VERSION_STRING) - 1;
454
455 /* put version string into the database now */
456 status = keydb_Put(handle, &versionKey, &versionData, 0);
457 if (status) {
458 return (SECFailure);
459 }
460 handle->version = version;
461
462 return (SECSuccess);
463 }
464
465 static SECStatus
makeGlobalSalt(NSSLOWKEYDBHandle * handle)466 makeGlobalSalt(NSSLOWKEYDBHandle *handle)
467 {
468 DBT saltKey;
469 DBT saltData;
470 unsigned char saltbuf[16];
471 int status;
472
473 saltKey.data = SALT_STRING;
474 saltKey.size = sizeof(SALT_STRING) - 1;
475
476 saltData.data = (void *)saltbuf;
477 saltData.size = sizeof(saltbuf);
478 RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf));
479
480 /* put global salt into the database now */
481 status = keydb_Put(handle, &saltKey, &saltData, 0);
482 if (status) {
483 return (SECFailure);
484 }
485
486 return (SECSuccess);
487 }
488
489 static SECStatus
490 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
491 SECItem *encCheck);
492
493 static unsigned char
nsslowkey_version(NSSLOWKEYDBHandle * handle)494 nsslowkey_version(NSSLOWKEYDBHandle *handle)
495 {
496 DBT versionKey;
497 DBT versionData;
498 int ret;
499 versionKey.data = VERSION_STRING;
500 versionKey.size = sizeof(VERSION_STRING) - 1;
501
502 if (handle->db == NULL) {
503 return 255;
504 }
505
506 /* lookup version string in database */
507 ret = keydb_Get(handle, &versionKey, &versionData, 0);
508
509 /* error accessing the database */
510 if (ret < 0) {
511 return 255;
512 }
513
514 if (ret >= 1) {
515 return 0;
516 }
517 return *((unsigned char *)versionData.data);
518 }
519
520 static PRBool
seckey_HasAServerKey(NSSLOWKEYDBHandle * handle)521 seckey_HasAServerKey(NSSLOWKEYDBHandle *handle)
522 {
523 DBT key;
524 DBT data;
525 int ret;
526 PRBool found = PR_FALSE;
527
528 ret = keydb_Seq(handle, &key, &data, R_FIRST);
529 if (ret) {
530 return PR_FALSE;
531 }
532
533 do {
534 /* skip version record */
535 if (data.size > 1) {
536 /* skip salt */
537 if (key.size == (sizeof(SALT_STRING) - 1)) {
538 if (PORT_Memcmp(key.data, SALT_STRING, key.size) == 0) {
539 continue;
540 }
541 }
542 /* skip pw check entry */
543 if (key.size == KEYDB_PW_CHECK_LEN) {
544 if (PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,
545 KEYDB_PW_CHECK_LEN) == 0) {
546 continue;
547 }
548 }
549
550 /* keys stored by nickname will have 0 as the last byte of the
551 * db key. Other keys must be stored by modulus. We will not
552 * update those because they are left over from a keygen that
553 * never resulted in a cert.
554 */
555 if (((unsigned char *)key.data)[key.size - 1] != 0) {
556 continue;
557 }
558
559 if (PORT_Strcmp(key.data, "Server-Key") == 0) {
560 found = PR_TRUE;
561 break;
562 }
563 }
564 } while (keydb_Seq(handle, &key, &data, R_NEXT) == 0);
565
566 return found;
567 }
568
569 /* forward declare local create function */
570 static NSSLOWKEYDBHandle *nsslowkey_NewHandle(DB *dbHandle);
571
572 /*
573 * currently updates key database from v2 to v3
574 */
575 static SECStatus
nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle * handle)576 nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle)
577 {
578 SECStatus rv;
579 DBT checkKey;
580 DBT checkData;
581 DBT saltKey;
582 DBT saltData;
583 DBT key;
584 DBT data;
585 unsigned char version;
586 NSSLOWKEYDBKey *dbkey = NULL;
587 NSSLOWKEYDBHandle *update = NULL;
588 SECItem *oldSalt = NULL;
589 int ret;
590 SECItem checkitem;
591
592 if (handle->updatedb == NULL) {
593 return SECSuccess;
594 }
595
596 /* create a full DB Handle for our update so we
597 * can use the correct locks for the db primatives */
598 update = nsslowkey_NewHandle(handle->updatedb);
599 if (update == NULL) {
600 return SECSuccess;
601 }
602
603 /* update has now inherited the database handle */
604 handle->updatedb = NULL;
605
606 /*
607 * check the version record
608 */
609 version = nsslowkey_version(update);
610 if (version != 2) {
611 goto done;
612 }
613
614 saltKey.data = SALT_STRING;
615 saltKey.size = sizeof(SALT_STRING) - 1;
616
617 ret = keydb_Get(update, &saltKey, &saltData, 0);
618 if (ret) {
619 /* no salt in old db, so it is corrupted */
620 goto done;
621 }
622
623 oldSalt = decodeKeyDBGlobalSalt(&saltData);
624 if (oldSalt == NULL) {
625 /* bad salt in old db, so it is corrupted */
626 goto done;
627 }
628
629 /*
630 * look for a pw check entry
631 */
632 checkKey.data = KEYDB_PW_CHECK_STRING;
633 checkKey.size = KEYDB_PW_CHECK_LEN;
634
635 ret = keydb_Get(update, &checkKey, &checkData, 0);
636 if (ret) {
637 /*
638 * if we have a key, but no KEYDB_PW_CHECK_STRING, then this must
639 * be an old server database, and it does have a password associated
640 * with it. Put a fake entry in so we can identify this db when we do
641 * get the password for it.
642 */
643 if (seckey_HasAServerKey(update)) {
644 DBT fcheckKey;
645 DBT fcheckData;
646
647 /*
648 * include a fake string
649 */
650 fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING;
651 fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN;
652 fcheckData.data = "1";
653 fcheckData.size = 1;
654 /* put global salt into the new database now */
655 ret = keydb_Put(handle, &saltKey, &saltData, 0);
656 if (ret) {
657 goto done;
658 }
659 ret = keydb_Put(handle, &fcheckKey, &fcheckData, 0);
660 if (ret) {
661 goto done;
662 }
663 } else {
664 goto done;
665 }
666 } else {
667 /* put global salt into the new database now */
668 ret = keydb_Put(handle, &saltKey, &saltData, 0);
669 if (ret) {
670 goto done;
671 }
672
673 dbkey = decode_dbkey(&checkData, 2);
674 if (dbkey == NULL) {
675 goto done;
676 }
677 checkitem = dbkey->derPK;
678 dbkey->derPK.data = NULL;
679
680 /* format the new pw check entry */
681 rv = encodePWCheckEntry(NULL, &dbkey->derPK, SEC_OID_RC4, &checkitem);
682 if (rv != SECSuccess) {
683 goto done;
684 }
685
686 rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE);
687 if (rv != SECSuccess) {
688 goto done;
689 }
690
691 /* free the dbkey */
692 sec_destroy_dbkey(dbkey);
693 dbkey = NULL;
694 }
695
696 /* now traverse the database */
697 ret = keydb_Seq(update, &key, &data, R_FIRST);
698 if (ret) {
699 goto done;
700 }
701
702 do {
703 /* skip version record */
704 if (data.size > 1) {
705 /* skip salt */
706 if (key.size == (sizeof(SALT_STRING) - 1)) {
707 if (PORT_Memcmp(key.data, SALT_STRING, key.size) == 0) {
708 continue;
709 }
710 }
711 /* skip pw check entry */
712 if (key.size == checkKey.size) {
713 if (PORT_Memcmp(key.data, checkKey.data, key.size) == 0) {
714 continue;
715 }
716 }
717
718 /* keys stored by nickname will have 0 as the last byte of the
719 * db key. Other keys must be stored by modulus. We will not
720 * update those because they are left over from a keygen that
721 * never resulted in a cert.
722 */
723 if (((unsigned char *)key.data)[key.size - 1] != 0) {
724 continue;
725 }
726
727 dbkey = decode_dbkey(&data, 2);
728 if (dbkey == NULL) {
729 continue;
730 }
731
732 /* This puts the key into the new database with the same
733 * index (nickname) that it had before. The second pass
734 * of the update will have the password. It will decrypt
735 * and re-encrypt the entries using a new algorithm.
736 */
737 dbkey->nickname = (char *)key.data;
738 rv = put_dbkey(handle, &key, dbkey, PR_FALSE);
739 dbkey->nickname = NULL;
740
741 sec_destroy_dbkey(dbkey);
742 }
743 } while (keydb_Seq(update, &key, &data, R_NEXT) == 0);
744
745 dbkey = NULL;
746
747 done:
748 /* sync the database */
749 ret = keydb_Sync(handle, 0);
750
751 nsslowkey_CloseKeyDB(update);
752
753 if (oldSalt) {
754 SECITEM_FreeItem(oldSalt, PR_TRUE);
755 }
756
757 if (dbkey) {
758 sec_destroy_dbkey(dbkey);
759 }
760
761 return (SECSuccess);
762 }
763
764 static SECStatus
openNewDB(const char * appName,const char * prefix,const char * dbname,NSSLOWKEYDBHandle * handle,NSSLOWKEYDBNameFunc namecb,void * cbarg)765 openNewDB(const char *appName, const char *prefix, const char *dbname,
766 NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg)
767 {
768 SECStatus rv = SECFailure;
769 int status = RDB_FAIL;
770 char *updname = NULL;
771 DB *updatedb = NULL;
772 PRBool updated = PR_FALSE;
773 int ret;
774
775 if (appName) {
776 handle->db = rdbopen(appName, prefix, "key", NO_CREATE, &status);
777 } else {
778 handle->db = dbopen(dbname, NO_CREATE, 0600, DB_HASH, 0);
779 }
780 /* if create fails then we lose */
781 if (handle->db == NULL) {
782 return (status == RDB_RETRY) ? SECWouldBlock : SECFailure;
783 }
784
785 /* force a transactional read, which will verify that one and only one
786 * process attempts the update. */
787 if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION) {
788 /* someone else has already updated the database for us */
789 db_InitComplete(handle->db);
790 return SECSuccess;
791 }
792
793 /*
794 * if we are creating a multiaccess database, see if there is a
795 * local database we can update from.
796 */
797 if (appName) {
798 NSSLOWKEYDBHandle *updateHandle;
799 updatedb = dbopen(dbname, NO_RDONLY, 0600, DB_HASH, 0);
800 if (!updatedb) {
801 goto noupdate;
802 }
803
804 /* nsslowkey_version needs a full handle because it calls
805 * the kdb_Get() function, which needs to lock.
806 */
807 updateHandle = nsslowkey_NewHandle(updatedb);
808 if (!updateHandle) {
809 updatedb->close(updatedb);
810 goto noupdate;
811 }
812
813 handle->version = nsslowkey_version(updateHandle);
814 if (handle->version != NSSLOWKEY_DB_FILE_VERSION) {
815 nsslowkey_CloseKeyDB(updateHandle);
816 goto noupdate;
817 }
818
819 /* copy the new DB from the old one */
820 db_Copy(handle->db, updatedb);
821 nsslowkey_CloseKeyDB(updateHandle);
822 db_InitComplete(handle->db);
823 return SECSuccess;
824 }
825 noupdate:
826
827 /* update the version number */
828 rv = makeGlobalVersion(handle);
829 if (rv != SECSuccess) {
830 goto loser;
831 }
832
833 /*
834 * try to update from v2 db
835 */
836 updname = (*namecb)(cbarg, 2);
837 if (updname != NULL) {
838 handle->updatedb = dbopen(updname, NO_RDONLY, 0600, DB_HASH, 0);
839 PORT_Free(updname);
840
841 if (handle->updatedb) {
842 /*
843 * Try to update the db using a null password. If the db
844 * doesn't have a password, then this will work. If it does
845 * have a password, then this will fail and we will do the
846 * update later
847 */
848 rv = nsslowkey_UpdateKeyDBPass1(handle);
849 if (rv == SECSuccess) {
850 updated = PR_TRUE;
851 }
852 }
853 }
854
855 /* we are using the old salt if we updated from an old db */
856 if (!updated) {
857 rv = makeGlobalSalt(handle);
858 if (rv != SECSuccess) {
859 goto loser;
860 }
861 }
862
863 /* sync the database */
864 ret = keydb_Sync(handle, 0);
865 if (ret) {
866 rv = SECFailure;
867 goto loser;
868 }
869 rv = SECSuccess;
870
871 loser:
872 db_InitComplete(handle->db);
873 return rv;
874 }
875
876 static DB *
openOldDB(const char * appName,const char * prefix,const char * dbname,PRBool openflags)877 openOldDB(const char *appName, const char *prefix, const char *dbname,
878 PRBool openflags)
879 {
880 DB *db = NULL;
881
882 if (appName) {
883 db = rdbopen(appName, prefix, "key", openflags, NULL);
884 } else {
885 db = dbopen(dbname, openflags, 0600, DB_HASH, 0);
886 }
887
888 return db;
889 }
890
891 /* check for correct version number */
892 static PRBool
verifyVersion(NSSLOWKEYDBHandle * handle)893 verifyVersion(NSSLOWKEYDBHandle *handle)
894 {
895 int version = nsslowkey_version(handle);
896
897 handle->version = version;
898 if (version != NSSLOWKEY_DB_FILE_VERSION) {
899 if (handle->db) {
900 keydb_Close(handle);
901 handle->db = NULL;
902 }
903 }
904 return handle->db != NULL;
905 }
906
907 static NSSLOWKEYDBHandle *
nsslowkey_NewHandle(DB * dbHandle)908 nsslowkey_NewHandle(DB *dbHandle)
909 {
910 NSSLOWKEYDBHandle *handle;
911 handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc(sizeof(NSSLOWKEYDBHandle));
912 if (handle == NULL) {
913 PORT_SetError(SEC_ERROR_NO_MEMORY);
914 return NULL;
915 }
916
917 handle->appname = NULL;
918 handle->dbname = NULL;
919 handle->global_salt = NULL;
920 handle->updatedb = NULL;
921 handle->db = dbHandle;
922 handle->ref = 1;
923 handle->lock = PZ_NewLock(nssILockKeyDB);
924
925 return handle;
926 }
927
928 NSSLOWKEYDBHandle *
nsslowkey_OpenKeyDB(PRBool readOnly,const char * appName,const char * prefix,NSSLOWKEYDBNameFunc namecb,void * cbarg)929 nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix,
930 NSSLOWKEYDBNameFunc namecb, void *cbarg)
931 {
932 NSSLOWKEYDBHandle *handle = NULL;
933 SECStatus rv;
934 int openflags;
935 char *dbname = NULL;
936
937 handle = nsslowkey_NewHandle(NULL);
938
939 openflags = readOnly ? NO_RDONLY : NO_RDWR;
940
941 dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION);
942 if (dbname == NULL) {
943 goto loser;
944 }
945 handle->appname = appName ? PORT_Strdup(appName) : NULL;
946 handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) : (prefix ? PORT_Strdup(prefix) : NULL);
947 handle->readOnly = readOnly;
948
949 handle->db = openOldDB(appName, prefix, dbname, openflags);
950 if (handle->db) {
951 verifyVersion(handle);
952 if (handle->version == 255) {
953 goto loser;
954 }
955 }
956
957 /* if first open fails, try to create a new DB */
958 if (handle->db == NULL) {
959 if (readOnly) {
960 goto loser;
961 }
962
963 rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg);
964 /* two processes started to initialize the database at the same time.
965 * The multiprocess code blocked the second one, then had it retry to
966 * see if it can just open the database normally */
967 if (rv == SECWouldBlock) {
968 handle->db = openOldDB(appName, prefix, dbname, openflags);
969 verifyVersion(handle);
970 if (handle->db == NULL) {
971 goto loser;
972 }
973 } else if (rv != SECSuccess) {
974 goto loser;
975 }
976 }
977
978 handle->global_salt = GetKeyDBGlobalSalt(handle);
979 if (dbname)
980 PORT_Free(dbname);
981 return handle;
982
983 loser:
984
985 if (dbname)
986 PORT_Free(dbname);
987 PORT_SetError(SEC_ERROR_BAD_DATABASE);
988 nsslowkey_CloseKeyDB(handle);
989 return NULL;
990 }
991
992 /*
993 * Close the database
994 */
995 void
nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle * handle)996 nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle)
997 {
998 if (handle != NULL) {
999 if (handle->db != NULL) {
1000 keydb_Close(handle);
1001 }
1002 if (handle->updatedb) {
1003 handle->updatedb->close(handle->updatedb);
1004 }
1005 if (handle->dbname)
1006 PORT_Free(handle->dbname);
1007 if (handle->appname)
1008 PORT_Free(handle->appname);
1009 if (handle->global_salt) {
1010 SECITEM_FreeItem(handle->global_salt, PR_TRUE);
1011 }
1012 if (handle->lock != NULL) {
1013 SKIP_AFTER_FORK(PZ_DestroyLock(handle->lock));
1014 }
1015
1016 PORT_Free(handle);
1017 }
1018 }
1019
1020 /* Get the key database version */
1021 int
nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle * handle)1022 nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle)
1023 {
1024 PORT_Assert(handle != NULL);
1025
1026 return handle->version;
1027 }
1028
1029 /*
1030 * Delete a private key that was stored in the database
1031 */
1032 SECStatus
nsslowkey_DeleteKey(NSSLOWKEYDBHandle * handle,const SECItem * pubkey)1033 nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, const SECItem *pubkey)
1034 {
1035 DBT namekey;
1036 int ret;
1037
1038 if (handle == NULL) {
1039 PORT_SetError(SEC_ERROR_BAD_DATABASE);
1040 return (SECFailure);
1041 }
1042
1043 /* set up db key and data */
1044 namekey.data = pubkey->data;
1045 namekey.size = pubkey->len;
1046
1047 /* delete it from the database */
1048 ret = keydb_Del(handle, &namekey, 0);
1049 if (ret) {
1050 PORT_SetError(SEC_ERROR_BAD_DATABASE);
1051 return (SECFailure);
1052 }
1053
1054 /* sync the database */
1055 ret = keydb_Sync(handle, 0);
1056 if (ret) {
1057 PORT_SetError(SEC_ERROR_BAD_DATABASE);
1058 return (SECFailure);
1059 }
1060
1061 return (SECSuccess);
1062 }
1063
1064 /*
1065 * Store a key in the database, indexed by its public key modulus.(value!)
1066 */
1067 SECStatus
nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle * handle,NSSLOWKEYPrivateKey * privkey,SECItem * pubKeyData,char * nickname,SDB * sdb)1068 nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle,
1069 NSSLOWKEYPrivateKey *privkey,
1070 SECItem *pubKeyData,
1071 char *nickname,
1072 SDB *sdb)
1073 {
1074 return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData,
1075 nickname, sdb, PR_FALSE);
1076 }
1077
1078 SECStatus
nsslowkey_UpdateNickname(NSSLOWKEYDBHandle * handle,NSSLOWKEYPrivateKey * privkey,SECItem * pubKeyData,char * nickname,SDB * sdb)1079 nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle,
1080 NSSLOWKEYPrivateKey *privkey,
1081 SECItem *pubKeyData,
1082 char *nickname,
1083 SDB *sdb)
1084 {
1085 return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData,
1086 nickname, sdb, PR_TRUE);
1087 }
1088
1089 /* see if the symetric CKA_ID already Exists.
1090 */
1091 PRBool
nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle * handle,SECItem * id)1092 nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id)
1093 {
1094 DBT namekey;
1095 DBT dummy;
1096 int status;
1097
1098 namekey.data = (char *)id->data;
1099 namekey.size = id->len;
1100 status = keydb_Get(handle, &namekey, &dummy, 0);
1101 if (status) {
1102 return PR_FALSE;
1103 }
1104
1105 return PR_TRUE;
1106 }
1107
1108 /* see if the public key for this cert is in the database filed
1109 * by modulus
1110 */
1111 PRBool
nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle * handle,NSSLOWCERTCertificate * cert)1112 nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert)
1113 {
1114 NSSLOWKEYPublicKey *pubkey = NULL;
1115 DBT namekey;
1116 DBT dummy;
1117 int status;
1118
1119 /* get cert's public key */
1120 pubkey = nsslowcert_ExtractPublicKey(cert);
1121 if (pubkey == NULL) {
1122 return PR_FALSE;
1123 }
1124
1125 /* TNH - make key from NSSLOWKEYPublicKey */
1126 switch (pubkey->keyType) {
1127 case NSSLOWKEYRSAKey:
1128 namekey.data = pubkey->u.rsa.modulus.data;
1129 namekey.size = pubkey->u.rsa.modulus.len;
1130 break;
1131 case NSSLOWKEYDSAKey:
1132 namekey.data = pubkey->u.dsa.publicValue.data;
1133 namekey.size = pubkey->u.dsa.publicValue.len;
1134 break;
1135 case NSSLOWKEYDHKey:
1136 namekey.data = pubkey->u.dh.publicValue.data;
1137 namekey.size = pubkey->u.dh.publicValue.len;
1138 break;
1139 case NSSLOWKEYECKey:
1140 namekey.data = pubkey->u.ec.publicValue.data;
1141 namekey.size = pubkey->u.ec.publicValue.len;
1142 break;
1143 default:
1144 /* XXX We don't do Fortezza or DH yet. */
1145 return PR_FALSE;
1146 }
1147
1148 if (handle->version != 3) {
1149 unsigned char buf[SHA1_LENGTH];
1150 SHA1_HashBuf(buf, namekey.data, namekey.size);
1151 /* NOTE: don't use pubkey after this! it's now thrashed */
1152 PORT_Memcpy(namekey.data, buf, sizeof(buf));
1153 namekey.size = sizeof(buf);
1154 }
1155
1156 status = keydb_Get(handle, &namekey, &dummy, 0);
1157 /* some databases have the key stored as a signed value */
1158 if (status) {
1159 unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size + 1);
1160 if (buf) {
1161 PORT_Memcpy(&buf[1], namekey.data, namekey.size);
1162 buf[0] = 0;
1163 namekey.data = buf;
1164 namekey.size++;
1165 status = keydb_Get(handle, &namekey, &dummy, 0);
1166 PORT_Free(buf);
1167 }
1168 }
1169 lg_nsslowkey_DestroyPublicKey(pubkey);
1170 if (status) {
1171 return PR_FALSE;
1172 }
1173
1174 return PR_TRUE;
1175 }
1176
1177 typedef struct NSSLowPasswordDataParamStr {
1178 SECItem salt;
1179 SECItem iter;
1180 } NSSLowPasswordDataParam;
1181
1182 static const SEC_ASN1Template NSSLOWPasswordParamTemplate[] =
1183 {
1184 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLowPasswordDataParam) },
1185 { SEC_ASN1_OCTET_STRING, offsetof(NSSLowPasswordDataParam, salt) },
1186 { SEC_ASN1_INTEGER, offsetof(NSSLowPasswordDataParam, iter) },
1187 { 0 }
1188 };
1189 struct LGEncryptedDataInfoStr {
1190 SECAlgorithmID algorithm;
1191 SECItem encryptedData;
1192 };
1193 typedef struct LGEncryptedDataInfoStr LGEncryptedDataInfo;
1194
1195 const SEC_ASN1Template lg_EncryptedDataInfoTemplate[] = {
1196 { SEC_ASN1_SEQUENCE,
1197 0, NULL, sizeof(LGEncryptedDataInfo) },
1198 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
1199 offsetof(LGEncryptedDataInfo, algorithm),
1200 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1201 { SEC_ASN1_OCTET_STRING,
1202 offsetof(LGEncryptedDataInfo, encryptedData) },
1203 { 0 }
1204 };
1205
1206 static SECItem *
nsslowkey_EncodePW(SECOidTag alg,const SECItem * salt,SECItem * data)1207 nsslowkey_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;
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_LENGTH) || (saltLen == SHA256_LENGTH) || (saltLen == SHA384_LENGTH) || (saltLen == SHA224_LENGTH) ||
1230 (saltLen == SHA512_LENGTH)) {
1231 param.iter.data = &salt->data[saltLen];
1232 param.iter.len = iterLen;
1233 param.salt.len = saltLen;
1234 }
1235
1236 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1237 if (arena == NULL) {
1238 return NULL;
1239 }
1240
1241 encParam = SEC_ASN1EncodeItem(arena, NULL, ¶m,
1242 NSSLOWPasswordParamTemplate);
1243 if (encParam == NULL) {
1244 goto loser;
1245 }
1246 rv = SECOID_SetAlgorithmID(arena, &edi.algorithm, alg, encParam);
1247 if (rv != SECSuccess) {
1248 goto loser;
1249 }
1250 epw = SEC_ASN1EncodeItem(NULL, NULL, &edi, lg_EncryptedDataInfoTemplate);
1251
1252 loser:
1253 PORT_FreeArena(arena, PR_FALSE);
1254 return epw;
1255 }
1256
1257 static SECItem *
nsslowkey_DecodePW(const SECItem * derData,SECOidTag * alg,SECItem * salt)1258 nsslowkey_DecodePW(const SECItem *derData, SECOidTag *alg, SECItem *salt)
1259 {
1260 NSSLowPasswordDataParam param;
1261 LGEncryptedDataInfo edi;
1262 PLArenaPool *arena;
1263 SECItem *pwe = NULL;
1264 SECStatus rv;
1265
1266 salt->data = NULL;
1267 param.iter.type = siBuffer; /* decode as signed integer */
1268
1269 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1270 if (arena == NULL) {
1271 return NULL;
1272 }
1273
1274 rv = SEC_QuickDERDecodeItem(arena, &edi, lg_EncryptedDataInfoTemplate,
1275 derData);
1276 if (rv != SECSuccess) {
1277 goto loser;
1278 }
1279 *alg = SECOID_GetAlgorithmTag(&edi.algorithm);
1280 rv = SEC_QuickDERDecodeItem(arena, ¶m, 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_Alloc(total_len);
1289 if (salt->data == NULL) {
1290 goto loser;
1291 }
1292 PORT_Memcpy(salt->data, param.salt.data, param.salt.len);
1293 PORT_Memcpy(&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_CopyItem(NULL, salt, ¶m.salt);
1299 if (rv != SECSuccess) {
1300 goto loser;
1301 }
1302 }
1303 pwe = SECITEM_DupItem(&edi.encryptedData);
1304
1305 loser:
1306 if (!pwe && salt->data) {
1307 PORT_Free(salt->data);
1308 salt->data = NULL;
1309 }
1310 PORT_FreeArena(arena, PR_FALSE);
1311 return pwe;
1312 }
1313
1314 /*
1315 * check to see if the user has a password
1316 */
1317 static SECStatus
nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle * handle,NSSLOWKEYPasswordEntry * entry)1318 nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle, NSSLOWKEYPasswordEntry *entry)
1319 {
1320 DBT checkkey; /*, checkdata; */
1321 NSSLOWKEYDBKey *dbkey = NULL;
1322 SECItem *global_salt = NULL;
1323 SECItem *item = NULL;
1324 SECItem entryData, oid;
1325 SECItem none = { siBuffer, NULL, 0 };
1326 SECStatus rv = SECFailure;
1327 SECOidTag algorithm;
1328
1329 if (handle == NULL) {
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_Memcpy(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;
1349 checkkey.size = KEYDB_PW_CHECK_LEN;
1350 dbkey = get_dbkey(handle, &checkkey);
1351 if (dbkey == NULL) {
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_LEN + 1 + oid.len)) {
1360 goto loser;
1361 }
1362 algorithm = SECOID_FindOIDTag(&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_Memcpy(entry->value.data, item->data, item->len);
1372 entry->value.len = item->len;
1373 rv = SECSuccess;
1374
1375 loser:
1376 if (item) {
1377 SECITEM_FreeItem(item, PR_TRUE);
1378 }
1379 if (dbkey) {
1380 sec_destroy_dbkey(dbkey);
1381 }
1382 if (global_salt != &none) {
1383 SECITEM_FreeItem(global_salt, PR_TRUE);
1384 }
1385 return rv;
1386 }
1387
1388 /*
1389 * check to see if the user has a password
1390 */
1391 static SECStatus
nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle * handle,NSSLOWKEYPasswordEntry * entry)1392 nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle, NSSLOWKEYPasswordEntry *entry)
1393 {
1394 DBT checkkey;
1395 NSSLOWKEYDBKey *dbkey = NULL;
1396 SECItem *item = NULL;
1397 SECItem salt;
1398 SECOidTag algid = SEC_OID_UNKNOWN;
1399 SECStatus rv = SECFailure;
1400 PLArenaPool *arena;
1401 int ret;
1402
1403 if (handle == NULL) {
1404 /* PORT_SetError */
1405 return (SECFailure);
1406 }
1407
1408 checkkey.data = KEYDB_PW_CHECK_STRING;
1409 checkkey.size = KEYDB_PW_CHECK_LEN;
1410
1411 salt.data = NULL;
1412 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1413 if (arena == NULL) {
1414 return SECFailure;
1415 }
1416
1417 item = nsslowkey_DecodePW(&entry->value, &algid, &salt);
1418 if (item == NULL) {
1419 goto loser;
1420 }
1421
1422 dbkey = PORT_ArenaZNew(arena, NSSLOWKEYDBKey);
1423 if (dbkey == NULL) {
1424 goto loser;
1425 }
1426
1427 dbkey->arena = arena;
1428
1429 rv = SECITEM_CopyItem(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_TRUE);
1440 if (rv != SECSuccess) {
1441 goto loser;
1442 }
1443
1444 if (handle->global_salt) {
1445 SECITEM_FreeItem(handle->global_salt, PR_TRUE);
1446 handle->global_salt = NULL;
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
1459 loser:
1460 if (item) {
1461 SECITEM_FreeItem(item, PR_TRUE);
1462 }
1463 if (arena) {
1464 PORT_FreeArena(arena, PR_TRUE);
1465 }
1466 if (salt.data) {
1467 PORT_Free(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
1484 SECStatus
seckey_encrypt_private_key(PLArenaPool * permarena,NSSLOWKEYPrivateKey * pk,SDB * sdbpw,SECItem * result)1485 seckey_encrypt_private_key(PLArenaPool *permarena, NSSLOWKEYPrivateKey *pk,
1486 SDB *sdbpw, SECItem *result)
1487 {
1488 NSSLOWKEYPrivateKeyInfo *pki = NULL;
1489 SECStatus rv = SECFailure;
1490 PLArenaPool *temparena = NULL;
1491 SECItem *der_item = NULL;
1492 SECItem *cipherText = NULL;
1493 SECItem *dummy = NULL;
1494 #ifdef EC_DEBUG
1495 SECItem *fordebug = NULL;
1496 #endif
1497 int savelen;
1498
1499 temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1500 if (temparena == NULL)
1501 goto loser;
1502
1503 /* allocate structures */
1504 pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena,
1505 sizeof(NSSLOWKEYPrivateKeyInfo));
1506 der_item = (SECItem *)PORT_ArenaZAlloc(temparena, sizeof(SECItem));
1507 if ((pki == NULL) || (der_item == NULL))
1508 goto loser;
1509
1510 /* setup private key info */
1511 dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version),
1512 NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
1513 if (dummy == NULL)
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_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
1521 lg_nsslowkey_RSAPrivateKeyTemplate);
1522 if (dummy == NULL) {
1523 rv = SECFailure;
1524 goto loser;
1525 }
1526
1527 rv = SECOID_SetAlgorithmID(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_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
1537 lg_nsslowkey_DSAPrivateKeyTemplate);
1538 if (dummy == NULL) {
1539 rv = SECFailure;
1540 goto loser;
1541 }
1542
1543 lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
1544 dummy = SEC_ASN1EncodeItem(temparena, NULL, &pk->u.dsa.params,
1545 lg_nsslowkey_PQGParamsTemplate);
1546 if (dummy == NULL) {
1547 rv = SECFailure;
1548 goto loser;
1549 }
1550
1551 rv = SECOID_SetAlgorithmID(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_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
1561 lg_nsslowkey_DHPrivateKeyTemplate);
1562 if (dummy == NULL) {
1563 rv = SECFailure;
1564 goto loser;
1565 }
1566
1567 rv = SECOID_SetAlgorithmID(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_ASN1EncodeItem(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) {
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_SetAlgorithmID(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);
1616 break;
1617 }
1618
1619 /* setup encrypted private key info */
1620 dummy = SEC_ASN1EncodeItem(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) {
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_CopyItem(permarena, result, cipherText);
1637
1638 loser:
1639
1640 if (temparena != NULL)
1641 PORT_FreeArena(temparena, PR_TRUE);
1642
1643 return rv;
1644 }
1645
1646 static SECStatus
seckey_put_private_key(NSSLOWKEYDBHandle * keydb,DBT * index,SDB * sdbpw,NSSLOWKEYPrivateKey * pk,char * nickname,PRBool update)1647 seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SDB *sdbpw,
1648 NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update)
1649 {
1650 NSSLOWKEYDBKey *dbkey = NULL;
1651 PLArenaPool *arena = NULL;
1652 SECStatus rv = SECFailure;
1653
1654 if ((keydb == NULL) || (index == NULL) || (sdbpw == NULL) ||
1655 (pk == NULL))
1656 return SECFailure;
1657
1658 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1659 if (arena == NULL)
1660 return SECFailure;
1661
1662 dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
1663 if (dbkey == NULL)
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 */
1675 loser:
1676 if (arena != NULL)
1677 PORT_FreeArena(arena, PR_TRUE);
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 */
1686 SECStatus
nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle * handle,NSSLOWKEYPrivateKey * privkey,SECItem * pubKeyData,char * nickname,SDB * sdbpw,PRBool update)1687 nsslowkey_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) {
1698 PORT_SetError(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
1713 static NSSLOWKEYPrivateKey *
seckey_decrypt_private_key(SECItem * epki,SDB * sdbpw)1714 seckey_decrypt_private_key(SECItem *epki,
1715 SDB *sdbpw)
1716 {
1717 NSSLOWKEYPrivateKey *pk = NULL;
1718 NSSLOWKEYPrivateKeyInfo *pki = NULL;
1719 SECStatus rv = SECFailure;
1720 PLArenaPool *temparena = NULL, *permarena = NULL;
1721 SECItem *dest = NULL;
1722 #ifdef EC_DEBUG
1723 SECItem *fordebug = NULL;
1724 #endif
1725
1726 if ((epki == NULL) || (sdbpw == NULL))
1727 goto loser;
1728
1729 temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1730 permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1731 if ((temparena == NULL) || (permarena == NULL))
1732 goto loser;
1733
1734 /* allocate temporary items */
1735 pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena,
1736 sizeof(NSSLOWKEYPrivateKeyInfo));
1737
1738 /* allocate permanent arena items */
1739 pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(permarena,
1740 sizeof(NSSLOWKEYPrivateKey));
1741
1742 if ((pk == NULL) || (pki == NULL))
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) {
1753 SECItem newPrivateKey;
1754 SECItem newAlgParms;
1755
1756 SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1,
1757 dest);
1758
1759 rv = SEC_QuickDERDecodeItem(temparena, pki,
1760 lg_nsslowkey_PrivateKeyInfoTemplate, dest);
1761 if (rv == SECSuccess) {
1762 switch (SECOID_GetAlgorithmTag(&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_CopyItem(permarena, &newPrivateKey,
1768 &pki->privateKey))
1769 break;
1770 rv = SEC_QuickDERDecodeItem(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_QuickDERDecodeItem(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_INTEGER &&
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_SetError(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_CopyItem(permarena, &newPrivateKey,
1807 &pki->privateKey))
1808 break;
1809 rv = SEC_QuickDERDecodeItem(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_CopyItem(permarena, &newAlgParms,
1816 &pki->algorithm.parameters))
1817 break;
1818 rv = SEC_QuickDERDecodeItem(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_CopyItem(permarena, &newPrivateKey,
1826 &pki->privateKey))
1827 break;
1828 rv = SEC_QuickDERDecodeItem(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_CopyItem(permarena, &newPrivateKey,
1842 &pki->privateKey))
1843 break;
1844 rv = SEC_QuickDERDecodeItem(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_CopyItem(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_GetError() == SEC_ERROR_BAD_DER) {
1876 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
1877 goto loser;
1878 }
1879 }
1880
1881 /* let success fall through */
1882 loser:
1883 if (temparena != NULL)
1884 PORT_FreeArena(temparena, PR_TRUE);
1885 if (dest != NULL)
1886 SECITEM_ZfreeItem(dest, PR_TRUE);
1887
1888 if (rv != SECSuccess) {
1889 if (permarena != NULL)
1890 PORT_FreeArena(permarena, PR_TRUE);
1891 pk = NULL;
1892 }
1893
1894 return pk;
1895 }
1896
1897 static NSSLOWKEYPrivateKey *
seckey_decode_encrypted_private_key(NSSLOWKEYDBKey * dbkey,SDB * sdbpw)1898 seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SDB *sdbpw)
1899 {
1900 if ((dbkey == NULL) || (sdbpw == NULL)) {
1901 return NULL;
1902 }
1903
1904 return seckey_decrypt_private_key(&(dbkey->derPK), sdbpw);
1905 }
1906
1907 static NSSLOWKEYPrivateKey *
seckey_get_private_key(NSSLOWKEYDBHandle * keydb,DBT * index,char ** nickname,SDB * sdbpw)1908 seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname,
1909 SDB *sdbpw)
1910 {
1911 NSSLOWKEYDBKey *dbkey = NULL;
1912 NSSLOWKEYPrivateKey *pk = NULL;
1913
1914 if ((keydb == NULL) || (index == NULL) || (sdbpw == NULL)) {
1915 return NULL;
1916 }
1917
1918 dbkey = get_dbkey(keydb, index);
1919 if (dbkey == NULL) {
1920 goto loser;
1921 }
1922
1923 if (nickname) {
1924 if (dbkey->nickname && (dbkey->nickname[0] != 0)) {
1925 *nickname = PORT_Strdup(dbkey->nickname);
1926 } else {
1927 *nickname = NULL;
1928 }
1929 }
1930
1931 pk = seckey_decode_encrypted_private_key(dbkey, sdbpw);
1932
1933 /* let success fall through */
1934 loser:
1935
1936 if (dbkey != NULL) {
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 */
1950 NSSLOWKEYPrivateKey *
nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle * handle,SECItem * modulus,SDB * sdbpw)1951 nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus,
1952 SDB *sdbpw)
1953 {
1954 DBT namekey;
1955 NSSLOWKEYPrivateKey *pk = NULL;
1956
1957 if (handle == NULL) {
1958 PORT_SetError(SEC_ERROR_BAD_DATABASE);
1959 return NULL;
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, 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
1974 char *
nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle * handle,SECItem * modulus,SDB * sdbpw)1975 nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle,
1976 SECItem *modulus, SDB *sdbpw)
1977 {
1978 DBT namekey;
1979 NSSLOWKEYPrivateKey *pk = NULL;
1980 char *nickname = NULL;
1981
1982 if (handle == NULL) {
1983 PORT_SetError(SEC_ERROR_BAD_DATABASE);
1984 return NULL;
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
2003 static SECStatus
encodePWCheckEntry(PLArenaPool * arena,SECItem * entry,SECOidTag alg,SECItem * encCheck)2004 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
2005 SECItem *encCheck)
2006 {
2007 SECOidData *oidData;
2008
2009 oidData = SECOID_FindOIDByTag(alg);
2010 if (oidData == NULL) {
2011 return SECFailure;
2012 }
2013
2014 entry->len = 1 + oidData->oid.len + encCheck->len;
2015 if (arena) {
2016 entry->data = (unsigned char *)PORT_ArenaAlloc(arena, entry->len);
2017 } else {
2018 entry->data = (unsigned char *)PORT_Alloc(entry->len);
2019 }
2020
2021 if (entry->data == NULL) {
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_Memcpy(&entry->data[1], oidData->oid.data, oidData->oid.len);
2029 /* finally the encrypted check string */
2030 PORT_Memcpy(&entry->data[1 + oidData->oid.len], encCheck->data,
2031 encCheck->len);
2032
2033 return SECSuccess;
2034 }
2035
2036 #define MAX_DB_SIZE 0xffff
2037 /*
2038 * Clear out all the keys in the existing database
2039 */
2040 static SECStatus
nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle * handle)2041 nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle)
2042 {
2043 SECStatus rv;
2044 int errors = 0;
2045
2046 if (handle->db == NULL) {
2047 return (SECSuccess);
2048 }
2049
2050 if (handle->readOnly) {
2051 /* set an error code */
2052 return SECFailure;
2053 }
2054
2055 if (handle->appname == NULL && handle->dbname == NULL) {
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, NULL);
2063 } else {
2064 handle->db = dbopen(handle->dbname, NO_CREATE, 0600, DB_HASH, 0);
2065 }
2066 if (handle->db == NULL) {
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
2089 done:
2090 /* sync the database */
2091 (void)keydb_Sync(handle, 0);
2092 db_InitComplete(handle->db);
2093
2094 return (errors == 0 ? SECSuccess : SECFailure);
2095 }
2096
2097 static int
keydb_Get(NSSLOWKEYDBHandle * kdb,DBT * key,DBT * data,unsigned int flags)2098 keydb_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);
2105 PZ_Lock(kdbLock);
2106
2107 ret = (*db->get)(db, key, data, flags);
2108
2109 (void)PZ_Unlock(kdbLock);
2110
2111 return (ret);
2112 }
2113
2114 static int
keydb_Put(NSSLOWKEYDBHandle * kdb,DBT * key,DBT * data,unsigned int flags)2115 keydb_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);
2122 PZ_Lock(kdbLock);
2123
2124 ret = (*db->put)(db, key, data, flags);
2125
2126 (void)PZ_Unlock(kdbLock);
2127
2128 return (ret);
2129 }
2130
2131 static int
keydb_Sync(NSSLOWKEYDBHandle * kdb,unsigned int flags)2132 keydb_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);
2139 PZ_Lock(kdbLock);
2140
2141 ret = (*db->sync)(db, flags);
2142
2143 (void)PZ_Unlock(kdbLock);
2144
2145 return (ret);
2146 }
2147
2148 static int
keydb_Del(NSSLOWKEYDBHandle * kdb,DBT * key,unsigned int flags)2149 keydb_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);
2156 PZ_Lock(kdbLock);
2157
2158 ret = (*db->del)(db, key, flags);
2159
2160 (void)PZ_Unlock(kdbLock);
2161
2162 return (ret);
2163 }
2164
2165 static int
keydb_Seq(NSSLOWKEYDBHandle * kdb,DBT * key,DBT * data,unsigned int flags)2166 keydb_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);
2173 PZ_Lock(kdbLock);
2174
2175 ret = (*db->seq)(db, key, data, flags);
2176
2177 (void)PZ_Unlock(kdbLock);
2178
2179 return (ret);
2180 }
2181
2182 static void
keydb_Close(NSSLOWKEYDBHandle * kdb)2183 keydb_Close(NSSLOWKEYDBHandle *kdb)
2184 {
2185 PRLock *kdbLock = kdb->lock;
2186 DB *db = kdb->db;
2187
2188 PORT_Assert(kdbLock != NULL);
2189 SKIP_AFTER_FORK(PZ_Lock(kdbLock));
2190
2191 (*db->close)(db);
2192
2193 SKIP_AFTER_FORK(PZ_Unlock(kdbLock));
2194
2195 return;
2196 }
2197
2198 /*
2199 * SDB Entry Points for the Key DB
2200 */
2201
2202 CK_RV
lg_GetMetaData(SDB * sdb,const char * id,SECItem * item1,SECItem * item2)2203 lg_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) {
2211 return CKR_TOKEN_WRITE_PROTECTED;
2212 }
2213 if (PORT_Strcmp(id, "password") != 0) {
2214 /* shouldn't happen */
2215 return CKR_GENERAL_ERROR; /* no extra data stored */
2216 }
2217 rv = nsslowkey_GetPWCheckEntry(keydb, &entry);
2218 if (rv != SECSuccess) {
2219 return CKR_GENERAL_ERROR;
2220 }
2221 item1->len = entry.salt.len;
2222 PORT_Memcpy(item1->data, entry.salt.data, item1->len);
2223 item2->len = entry.value.len;
2224 PORT_Memcpy(item2->data, entry.value.data, item2->len);
2225 return CKR_OK;
2226 }
2227
2228 CK_RV
lg_PutMetaData(SDB * sdb,const char * id,const SECItem * item1,const SECItem * item2)2229 lg_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) {
2238 return CKR_TOKEN_WRITE_PROTECTED;
2239 }
2240 if (PORT_Strcmp(id, "password") != 0) {
2241 /* shouldn't happen */
2242 return CKR_GENERAL_ERROR; /* 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_ERROR;
2249 }
2250 return CKR_OK;
2251 }
2252
2253 CK_RV
lg_DestroyMetaData(SDB * db,const char * id)2254 lg_DestroyMetaData(SDB *db, const char *id)
2255 {
2256 return CKR_GENERAL_ERROR; /* no extra data stored */
2257 }
2258
2259 CK_RV
lg_Reset(SDB * sdb)2260 lg_Reset(SDB *sdb)
2261 {
2262 NSSLOWKEYDBHandle *keydb;
2263 SECStatus rv;
2264
2265 keydb = lg_getKeyDB(sdb);
2266 if (keydb == NULL) {
2267 return CKR_TOKEN_WRITE_PROTECTED;
2268 }
2269 rv = nsslowkey_ResetKeyDB(keydb);
2270 if (rv != SECSuccess) {
2271 return CKR_GENERAL_ERROR;
2272 }
2273 return CKR_OK;
2274 }
2275