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