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, &param,
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, &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_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, &param.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