OLD | NEW |
| (Empty) |
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 * The following code handles the storage of PKCS 11 modules used by the | |
6 * NSS. For the rest of NSS, only one kind of database handle exists: | |
7 * | |
8 * SFTKDBHandle | |
9 * | |
10 * There is one SFTKDBHandle for the each key database and one for each cert | |
11 * database. These databases are opened as associated pairs, one pair per | |
12 * slot. SFTKDBHandles are reference counted objects. | |
13 * | |
14 * Each SFTKDBHandle points to a low level database handle (SDB). This handle | |
15 * represents the underlying physical database. These objects are not | |
16 * reference counted, an are 'owned' by their respective SFTKDBHandles. | |
17 * | |
18 * | |
19 */ | |
20 #include "sftkdb.h" | |
21 #include "sftkdbti.h" | |
22 #include "pkcs11t.h" | |
23 #include "pkcs11i.h" | |
24 #include "sdb.h" | |
25 #include "prprf.h" | |
26 #include "secasn1.h" | |
27 #include "pratom.h" | |
28 #include "blapi.h" | |
29 #include "secoid.h" | |
30 #include "lowpbe.h" | |
31 #include "secdert.h" | |
32 #include "prsystem.h" | |
33 #include "lgglue.h" | |
34 #include "secerr.h" | |
35 #include "softoken.h" | |
36 | |
37 /****************************************************************** | |
38 * | |
39 * Key DB password handling functions | |
40 * | |
41 * These functions manage the key db password (set, reset, initialize, use). | |
42 * | |
43 * The key is managed on 'this side' of the database. All private data is | |
44 * encrypted before it is sent to the database itself. Besides PBE's, the | |
45 * database management code can also mix in various fixed keys so the data | |
46 * in the database is no longer considered 'plain text'. | |
47 */ | |
48 | |
49 | |
50 /* take string password and turn it into a key. The key is dependent | |
51 * on a global salt entry acquired from the database. This salted | |
52 * value will be based to a pkcs5 pbe function before it is used | |
53 * in an actual encryption */ | |
54 static SECStatus | |
55 sftkdb_passwordToKey(SFTKDBHandle *keydb, SECItem *salt, | |
56 const char *pw, SECItem *key) | |
57 { | |
58 SHA1Context *cx = NULL; | |
59 SECStatus rv = SECFailure; | |
60 | |
61 key->data = PORT_Alloc(SHA1_LENGTH); | |
62 if (key->data == NULL) { | |
63 goto loser; | |
64 } | |
65 key->len = SHA1_LENGTH; | |
66 | |
67 cx = SHA1_NewContext(); | |
68 if ( cx == NULL) { | |
69 goto loser; | |
70 } | |
71 SHA1_Begin(cx); | |
72 if (salt && salt->data ) { | |
73 SHA1_Update(cx, salt->data, salt->len); | |
74 } | |
75 SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw)); | |
76 SHA1_End(cx, key->data, &key->len, key->len); | |
77 rv = SECSuccess; | |
78 | |
79 loser: | |
80 if (cx) { | |
81 SHA1_DestroyContext(cx, PR_TRUE); | |
82 } | |
83 if (rv != SECSuccess) { | |
84 if (key->data != NULL) { | |
85 PORT_ZFree(key->data,key->len); | |
86 } | |
87 key->data = NULL; | |
88 } | |
89 return rv; | |
90 } | |
91 | |
92 /* | |
93 * Cipher text stored in the database contains 3 elements: | |
94 * 1) an identifier describing the encryption algorithm. | |
95 * 2) an entry specific salt value. | |
96 * 3) the encrypted value. | |
97 * | |
98 * The following data structure represents the encrypted data in a decoded | |
99 * (but still encrypted) form. | |
100 */ | |
101 typedef struct sftkCipherValueStr sftkCipherValue; | |
102 struct sftkCipherValueStr { | |
103 PLArenaPool *arena; | |
104 SECOidTag alg; | |
105 NSSPKCS5PBEParameter *param; | |
106 SECItem salt; | |
107 SECItem value; | |
108 }; | |
109 | |
110 #define SFTK_CIPHERTEXT_VERSION 3 | |
111 | |
112 struct SFTKDBEncryptedDataInfoStr { | |
113 SECAlgorithmID algorithm; | |
114 SECItem encryptedData; | |
115 }; | |
116 typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo; | |
117 | |
118 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) | |
119 | |
120 const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate[] = { | |
121 { SEC_ASN1_SEQUENCE, | |
122 0, NULL, sizeof(SFTKDBEncryptedDataInfo) }, | |
123 { SEC_ASN1_INLINE | SEC_ASN1_XTRN , | |
124 offsetof(SFTKDBEncryptedDataInfo,algorithm), | |
125 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, | |
126 { SEC_ASN1_OCTET_STRING, | |
127 offsetof(SFTKDBEncryptedDataInfo,encryptedData) }, | |
128 { 0 } | |
129 }; | |
130 | |
131 /* | |
132 * This parses the cipherText into cipher value. NOTE: cipherValue will point | |
133 * to data in cipherText, if cipherText is freed, cipherValue will be invalid. | |
134 */ | |
135 static SECStatus | |
136 sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue) | |
137 { | |
138 PLArenaPool *arena = NULL; | |
139 SFTKDBEncryptedDataInfo edi; | |
140 SECStatus rv; | |
141 | |
142 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
143 if (arena == NULL) { | |
144 return SECFailure; | |
145 } | |
146 cipherValue->arena = NULL; | |
147 cipherValue->param = NULL; | |
148 | |
149 rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate, | |
150 cipherText); | |
151 if (rv != SECSuccess) { | |
152 goto loser; | |
153 } | |
154 cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm); | |
155 cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm); | |
156 if (cipherValue->param == NULL) { | |
157 goto loser; | |
158 } | |
159 cipherValue->value = edi.encryptedData; | |
160 cipherValue->arena = arena; | |
161 | |
162 return SECSuccess; | |
163 loser: | |
164 if (cipherValue->param) { | |
165 nsspkcs5_DestroyPBEParameter(cipherValue->param); | |
166 cipherValue->param = NULL; | |
167 } | |
168 if (arena) { | |
169 PORT_FreeArena(arena,PR_FALSE); | |
170 } | |
171 return SECFailure; | |
172 } | |
173 | |
174 | |
175 | |
176 /* | |
177 * unlike decode, Encode actually allocates a SECItem the caller must free | |
178 * The caller can pass an optional arena to to indicate where to place | |
179 * the resultant cipherText. | |
180 */ | |
181 static SECStatus | |
182 sftkdb_encodeCipherText(PLArenaPool *arena, sftkCipherValue *cipherValue, | |
183 SECItem **cipherText) | |
184 { | |
185 SFTKDBEncryptedDataInfo edi; | |
186 SECAlgorithmID *algid; | |
187 SECStatus rv; | |
188 PLArenaPool *localArena = NULL; | |
189 | |
190 | |
191 localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
192 if (localArena == NULL) { | |
193 return SECFailure; | |
194 } | |
195 | |
196 algid = nsspkcs5_CreateAlgorithmID(localArena, cipherValue->alg, | |
197 cipherValue->param); | |
198 if (algid == NULL) { | |
199 rv = SECFailure; | |
200 goto loser; | |
201 } | |
202 rv = SECOID_CopyAlgorithmID(localArena, &edi.algorithm, algid); | |
203 SECOID_DestroyAlgorithmID(algid, PR_TRUE); | |
204 if (rv != SECSuccess) { | |
205 goto loser; | |
206 } | |
207 edi.encryptedData = cipherValue->value; | |
208 | |
209 *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi, | |
210 sftkdb_EncryptedDataInfoTemplate); | |
211 if (*cipherText == NULL) { | |
212 rv = SECFailure; | |
213 } | |
214 | |
215 loser: | |
216 if (localArena) { | |
217 PORT_FreeArena(localArena,PR_FALSE); | |
218 } | |
219 | |
220 return rv; | |
221 } | |
222 | |
223 | |
224 /* | |
225 * Use our key to decode a cipherText block from the database. | |
226 * | |
227 * plain text is allocated by nsspkcs5_CipherData and must be freed | |
228 * with SECITEM_FreeItem by the caller. | |
229 */ | |
230 SECStatus | |
231 sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText, SECItem **plain) | |
232 { | |
233 SECStatus rv; | |
234 sftkCipherValue cipherValue; | |
235 | |
236 /* First get the cipher type */ | |
237 rv = sftkdb_decodeCipherText(cipherText, &cipherValue); | |
238 if (rv != SECSuccess) { | |
239 goto loser; | |
240 } | |
241 | |
242 *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value,
| |
243 PR_FALSE, NULL); | |
244 if (*plain == NULL) { | |
245 rv = SECFailure; | |
246 goto loser; | |
247 } | |
248 | |
249 loser: | |
250 if (cipherValue.param) { | |
251 nsspkcs5_DestroyPBEParameter(cipherValue.param); | |
252 } | |
253 if (cipherValue.arena) { | |
254 PORT_FreeArena(cipherValue.arena,PR_FALSE); | |
255 } | |
256 return rv; | |
257 } | |
258 | |
259 /* | |
260 * encrypt a block. This function returned the encrypted ciphertext which | |
261 * the caller must free. If the caller provides an arena, cipherText will | |
262 * be allocated out of that arena. This also generated the per entry | |
263 * salt automatically. | |
264 */ | |
265 SECStatus | |
266 sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey, | |
267 SECItem *plainText, SECItem **cipherText) | |
268 { | |
269 SECStatus rv; | |
270 sftkCipherValue cipherValue; | |
271 SECItem *cipher = NULL; | |
272 NSSPKCS5PBEParameter *param = NULL; | |
273 unsigned char saltData[HASH_LENGTH_MAX]; | |
274 | |
275 cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC; | |
276 cipherValue.salt.len = SHA1_LENGTH; | |
277 cipherValue.salt.data = saltData; | |
278 RNG_GenerateGlobalRandomBytes(saltData,cipherValue.salt.len); | |
279 | |
280 param = nsspkcs5_NewParam(cipherValue.alg, HASH_AlgSHA1, &cipherValue.salt, | |
281 1); | |
282 if (param == NULL) { | |
283 rv = SECFailure; | |
284 goto loser; | |
285 } | |
286 cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL); | |
287 if (cipher == NULL) { | |
288 rv = SECFailure; | |
289 goto loser; | |
290 } | |
291 cipherValue.value = *cipher; | |
292 cipherValue.param = param; | |
293 | |
294 rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText); | |
295 if (rv != SECSuccess) { | |
296 goto loser; | |
297 } | |
298 | |
299 loser: | |
300 if (cipher) { | |
301 SECITEM_FreeItem(cipher, PR_TRUE); | |
302 } | |
303 if (param) { | |
304 nsspkcs5_DestroyPBEParameter(param); | |
305 } | |
306 return rv; | |
307 } | |
308 | |
309 /* | |
310 * use the password and the pbe parameters to generate an HMAC for the | |
311 * given plain text data. This is used by sftkdb_VerifyAttribute and | |
312 * sftkdb_SignAttribute. Signature is returned in signData. The caller | |
313 * must preallocate the space in the secitem. | |
314 */ | |
315 static SECStatus | |
316 sftkdb_pbehash(SECOidTag sigOid, SECItem *passKey, | |
317 NSSPKCS5PBEParameter *param, | |
318 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType, | |
319 SECItem *plainText, SECItem *signData) | |
320 { | |
321 SECStatus rv = SECFailure; | |
322 SECItem *key = NULL; | |
323 HMACContext *hashCx = NULL; | |
324 HASH_HashType hashType = HASH_AlgNULL; | |
325 const SECHashObject *hashObj; | |
326 unsigned char addressData[SDB_ULONG_SIZE]; | |
327 | |
328 hashType = HASH_FromHMACOid(param->encAlg); | |
329 if (hashType == HASH_AlgNULL) { | |
330 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
331 return SECFailure; | |
332 } | |
333 | |
334 hashObj = HASH_GetRawHashObject(hashType); | |
335 if (hashObj == NULL) { | |
336 goto loser; | |
337 } | |
338 | |
339 key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE); | |
340 if (!key) { | |
341 goto loser; | |
342 } | |
343 | |
344 hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE); | |
345 if (!hashCx) { | |
346 goto loser; | |
347 } | |
348 HMAC_Begin(hashCx); | |
349 /* Tie this value to a particular object. This is most important for | |
350 * the trust attributes, where and attacker could copy a value for | |
351 * 'validCA' from another cert in the database */ | |
352 sftk_ULong2SDBULong(addressData, objectID); | |
353 HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE); | |
354 sftk_ULong2SDBULong(addressData, attrType); | |
355 HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE); | |
356 | |
357 HMAC_Update(hashCx, plainText->data, plainText->len); | |
358 rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len); | |
359 | |
360 loser: | |
361 if (hashCx) { | |
362 HMAC_Destroy(hashCx, PR_TRUE); | |
363 } | |
364 if (key) { | |
365 SECITEM_FreeItem(key,PR_TRUE); | |
366 } | |
367 return rv; | |
368 } | |
369 | |
370 /* | |
371 * Use our key to verify a signText block from the database matches | |
372 * the plainText from the database. The signText is a PKCS 5 v2 pbe. | |
373 * plainText is the plainText of the attribute. | |
374 */ | |
375 SECStatus | |
376 sftkdb_VerifyAttribute(SECItem *passKey, CK_OBJECT_HANDLE objectID, | |
377 CK_ATTRIBUTE_TYPE attrType, | |
378 SECItem *plainText, SECItem *signText) | |
379 { | |
380 SECStatus rv; | |
381 sftkCipherValue signValue; | |
382 SECItem signature; | |
383 unsigned char signData[HASH_LENGTH_MAX]; | |
384 | |
385 | |
386 /* First get the cipher type */ | |
387 rv = sftkdb_decodeCipherText(signText, &signValue); | |
388 if (rv != SECSuccess) { | |
389 goto loser; | |
390 } | |
391 signature.data = signData; | |
392 signature.len = sizeof(signData); | |
393 | |
394 rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param, | |
395 objectID, attrType, plainText, &signature); | |
396 if (rv != SECSuccess) { | |
397 goto loser; | |
398 } | |
399 if (SECITEM_CompareItem(&signValue.value,&signature) != 0) { | |
400 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
401 rv = SECFailure; | |
402 } | |
403 | |
404 loser: | |
405 if (signValue.param) { | |
406 nsspkcs5_DestroyPBEParameter(signValue.param); | |
407 } | |
408 if (signValue.arena) { | |
409 PORT_FreeArena(signValue.arena,PR_FALSE); | |
410 } | |
411 return rv; | |
412 } | |
413 | |
414 /* | |
415 * Use our key to create a signText block the plain text of an | |
416 * attribute. The signText is a PKCS 5 v2 pbe. | |
417 */ | |
418 SECStatus | |
419 sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey, | |
420 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType, | |
421 SECItem *plainText, SECItem **signature) | |
422 { | |
423 SECStatus rv; | |
424 sftkCipherValue signValue; | |
425 NSSPKCS5PBEParameter *param = NULL; | |
426 unsigned char saltData[HASH_LENGTH_MAX]; | |
427 unsigned char signData[HASH_LENGTH_MAX]; | |
428 SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */ | |
429 SECOidTag prfAlg = SEC_OID_HMAC_SHA256; /* hash for pb key generation */ | |
430 HASH_HashType prfType; | |
431 unsigned int hmacLength; | |
432 unsigned int prfLength; | |
433 | |
434 /* this code allows us to fetch the lengths and hashes on the fly | |
435 * by simply changing the OID above */ | |
436 prfType = HASH_FromHMACOid(prfAlg); | |
437 PORT_Assert(prfType != HASH_AlgNULL); | |
438 prfLength = HASH_GetRawHashObject(prfType)->length; | |
439 PORT_Assert(prfLength <= HASH_LENGTH_MAX); | |
440 | |
441 hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length; | |
442 PORT_Assert(hmacLength <= HASH_LENGTH_MAX); | |
443 | |
444 /* initialize our CipherValue structure */ | |
445 signValue.alg = SEC_OID_PKCS5_PBMAC1; | |
446 signValue.salt.len = prfLength; | |
447 signValue.salt.data = saltData; | |
448 signValue.value.data = signData; | |
449 signValue.value.len = hmacLength; | |
450 RNG_GenerateGlobalRandomBytes(saltData,prfLength); | |
451 | |
452 /* initialize our pkcs5 parameter */ | |
453 param = nsspkcs5_NewParam(signValue.alg, HASH_AlgSHA1, &signValue.salt, 1); | |
454 if (param == NULL) { | |
455 rv = SECFailure; | |
456 goto loser; | |
457 } | |
458 param->keyID = pbeBitGenIntegrityKey; | |
459 /* set the PKCS 5 v2 parameters, not extractable from the | |
460 * data passed into nsspkcs5_NewParam */ | |
461 param->encAlg = hmacAlg; | |
462 param->hashType = prfType; | |
463 param->keyLen = hmacLength; | |
464 rv = SECOID_SetAlgorithmID(param->poolp, ¶m->prfAlg, prfAlg, NULL); | |
465 if (rv != SECSuccess) { | |
466 goto loser; | |
467 } | |
468 | |
469 | |
470 /* calculate the mac */ | |
471 rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType, | |
472 plainText, &signValue.value); | |
473 if (rv != SECSuccess) { | |
474 goto loser; | |
475 } | |
476 signValue.param = param; | |
477 | |
478 /* write it out */ | |
479 rv = sftkdb_encodeCipherText(arena, &signValue, signature); | |
480 if (rv != SECSuccess) { | |
481 goto loser; | |
482 } | |
483 | |
484 loser: | |
485 if (param) { | |
486 nsspkcs5_DestroyPBEParameter(param); | |
487 } | |
488 return rv; | |
489 } | |
490 | |
491 /* | |
492 * safely swith the passed in key for the one caches in the keydb handle | |
493 * | |
494 * A key attached to the handle tells us the the token is logged in. | |
495 * We can used the key attached to the handle in sftkdb_EncryptAttribute | |
496 * and sftkdb_DecryptAttribute calls. | |
497 */ | |
498 static void | |
499 sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey) | |
500 { | |
501 unsigned char *data; | |
502 int len; | |
503 | |
504 if (keydb->passwordLock == NULL) { | |
505 PORT_Assert(keydb->type != SFTK_KEYDB_TYPE); | |
506 return; | |
507 } | |
508 | |
509 /* an atomic pointer set would be nice */ | |
510 SKIP_AFTER_FORK(PZ_Lock(keydb->passwordLock)); | |
511 data = keydb->passwordKey.data; | |
512 len = keydb->passwordKey.len; | |
513 keydb->passwordKey.data = passKey->data; | |
514 keydb->passwordKey.len = passKey->len; | |
515 passKey->data = data; | |
516 passKey->len = len; | |
517 SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock)); | |
518 } | |
519 | |
520 /* | |
521 * returns true if we are in a middle of a merge style update. | |
522 */ | |
523 PRBool | |
524 sftkdb_InUpdateMerge(SFTKDBHandle *keydb) | |
525 { | |
526 return keydb->updateID ? PR_TRUE : PR_FALSE; | |
527 } | |
528 | |
529 /* | |
530 * returns true if we are looking for the password for the user's old source | |
531 * database as part of a merge style update. | |
532 */ | |
533 PRBool | |
534 sftkdb_NeedUpdateDBPassword(SFTKDBHandle *keydb) | |
535 { | |
536 if (!sftkdb_InUpdateMerge(keydb)) { | |
537 return PR_FALSE; | |
538 } | |
539 if (keydb->updateDBIsInit && !keydb->updatePasswordKey) { | |
540 return PR_TRUE; | |
541 } | |
542 return PR_FALSE; | |
543 } | |
544 | |
545 /* | |
546 * fetch an update password key from a handle. | |
547 */ | |
548 SECItem * | |
549 sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle) | |
550 { | |
551 SECItem *key = NULL; | |
552 | |
553 /* if we're a cert db, fetch it from our peer key db */ | |
554 if (handle->type == SFTK_CERTDB_TYPE) { | |
555 handle = handle->peerDB; | |
556 } | |
557 | |
558 /* don't have one */ | |
559 if (!handle) { | |
560 return NULL; | |
561 } | |
562 | |
563 PZ_Lock(handle->passwordLock); | |
564 if (handle->updatePasswordKey) { | |
565 key = SECITEM_DupItem(handle->updatePasswordKey); | |
566 } | |
567 PZ_Unlock(handle->passwordLock); | |
568 | |
569 return key; | |
570 } | |
571 | |
572 /* | |
573 * free the update password key from a handle. | |
574 */ | |
575 void | |
576 sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle) | |
577 { | |
578 SECItem *key = NULL; | |
579 | |
580 /* don't have one */ | |
581 if (!handle) { | |
582 return; | |
583 } | |
584 | |
585 /* if we're a cert db, we don't have one */ | |
586 if (handle->type == SFTK_CERTDB_TYPE) { | |
587 return; | |
588 } | |
589 | |
590 PZ_Lock(handle->passwordLock); | |
591 if (handle->updatePasswordKey) { | |
592 key = handle->updatePasswordKey; | |
593 handle->updatePasswordKey = NULL; | |
594 } | |
595 PZ_Unlock(handle->passwordLock); | |
596 | |
597 if (key) { | |
598 SECITEM_ZfreeItem(key, PR_TRUE); | |
599 } | |
600 | |
601 return; | |
602 } | |
603 | |
604 /* | |
605 * what password db we use depends heavily on the update state machine | |
606 * | |
607 * 1) no update db, return the normal database. | |
608 * 2) update db and no merge return the update db. | |
609 * 3) update db and in merge: | |
610 * return the update db if we need the update db's password, | |
611 * otherwise return our normal datbase. | |
612 */ | |
613 static SDB * | |
614 sftk_getPWSDB(SFTKDBHandle *keydb) | |
615 { | |
616 if (!keydb->update) { | |
617 return keydb->db; | |
618 } | |
619 if (!sftkdb_InUpdateMerge(keydb)) { | |
620 return keydb->update; | |
621 } | |
622 if (sftkdb_NeedUpdateDBPassword(keydb)) { | |
623 return keydb->update; | |
624 } | |
625 return keydb->db; | |
626 } | |
627 | |
628 /* | |
629 * return success if we have a valid password entry. | |
630 * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT | |
631 * in the token flags. | |
632 */ | |
633 SECStatus | |
634 sftkdb_HasPasswordSet(SFTKDBHandle *keydb) | |
635 { | |
636 SECItem salt, value; | |
637 unsigned char saltData[SDB_MAX_META_DATA_LEN]; | |
638 unsigned char valueData[SDB_MAX_META_DATA_LEN]; | |
639 CK_RV crv; | |
640 SDB *db; | |
641 | |
642 if (keydb == NULL) { | |
643 return SECFailure; | |
644 } | |
645 | |
646 db = sftk_getPWSDB(keydb); | |
647 if (db == NULL) { | |
648 return SECFailure; | |
649 } | |
650 | |
651 salt.data = saltData; | |
652 salt.len = sizeof(saltData); | |
653 value.data = valueData; | |
654 value.len = sizeof(valueData); | |
655 crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value); | |
656 | |
657 /* If no password is set, we can update right away */ | |
658 if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update | |
659 && crv != CKR_OK) { | |
660 /* update the peer certdb if it exists */ | |
661 if (keydb->peerDB) { | |
662 sftkdb_Update(keydb->peerDB, NULL); | |
663 } | |
664 sftkdb_Update(keydb, NULL); | |
665 } | |
666 return (crv == CKR_OK) ? SECSuccess : SECFailure; | |
667 } | |
668 | |
669 #define SFTK_PW_CHECK_STRING "password-check" | |
670 #define SFTK_PW_CHECK_LEN 14 | |
671 | |
672 /* | |
673 * check if the supplied password is valid | |
674 */ | |
675 SECStatus | |
676 sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved) | |
677 { | |
678 SECStatus rv; | |
679 SECItem salt, value; | |
680 unsigned char saltData[SDB_MAX_META_DATA_LEN]; | |
681 unsigned char valueData[SDB_MAX_META_DATA_LEN]; | |
682 SECItem key; | |
683 SECItem *result = NULL; | |
684 SDB *db; | |
685 CK_RV crv; | |
686 | |
687 if (keydb == NULL) { | |
688 return SECFailure; | |
689 } | |
690 | |
691 db = sftk_getPWSDB(keydb); | |
692 if (db == NULL) { | |
693 return SECFailure; | |
694 } | |
695 | |
696 key.data = NULL; | |
697 key.len = 0; | |
698 | |
699 if (pw == NULL) pw=""; | |
700 | |
701 /* get the entry from the database */ | |
702 salt.data = saltData; | |
703 salt.len = sizeof(saltData); | |
704 value.data = valueData; | |
705 value.len = sizeof(valueData); | |
706 crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value); | |
707 if (crv != CKR_OK) { | |
708 rv = SECFailure; | |
709 goto done; | |
710 } | |
711 | |
712 /* get our intermediate key based on the entry salt value */ | |
713 rv = sftkdb_passwordToKey(keydb, &salt, pw, &key); | |
714 if (rv != SECSuccess) { | |
715 goto done; | |
716 } | |
717 | |
718 /* decrypt the entry value */ | |
719 rv = sftkdb_DecryptAttribute(&key, &value, &result); | |
720 if (rv != SECSuccess) { | |
721 goto done; | |
722 } | |
723 | |
724 /* if it's what we expect, update our key in the database handle and | |
725 * return Success */ | |
726 if ((result->len == SFTK_PW_CHECK_LEN) && | |
727 PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0){ | |
728 /* | |
729 * We have a password, now lets handle any potential update cases.. | |
730 * | |
731 * First, the normal case: no update. In this case we only need the | |
732 * the password for our only DB, which we now have, we switch | |
733 * the keys and fall through. | |
734 * Second regular (non-merge) update: The target DB does not yet have | |
735 * a password initialized, we now have the password for the source DB, | |
736 * so we can switch the keys and simply update the target database. | |
737 * Merge update case: This one is trickier. | |
738 * 1) If we need the source DB password, then we just got it here. | |
739 * We need to save that password, | |
740 * then we need to check to see if we need or have the target | |
741 * database password. | |
742 * If we have it (it's the same as the source), or don't need | |
743 * it (it's not set or is ""), we can start the update now. | |
744 * If we don't have it, we need the application to get it from | |
745 * the user. Clear our sessions out to simulate a token | |
746 * removal. C_GetTokenInfo will change the token description | |
747 * and the token will still appear to be logged out. | |
748 * 2) If we already have the source DB password, this password is | |
749 * for the target database. We can now move forward with the | |
750 * update, as we now have both required passwords. | |
751 * | |
752 */ | |
753 PZ_Lock(keydb->passwordLock); | |
754 if (sftkdb_NeedUpdateDBPassword(keydb)) { | |
755 /* Squirrel this special key away. | |
756 * This has the side effect of turning sftkdb_NeedLegacyPW off, | |
757 * as well as changing which database is returned from | |
758 * SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword() | |
759 * and sftkdb_HasPasswordSet()) */ | |
760 keydb->updatePasswordKey = SECITEM_DupItem(&key); | |
761 PZ_Unlock(keydb->passwordLock); | |
762 if (keydb->updatePasswordKey == NULL) { | |
763 /* PORT_Error set by SECITEM_DupItem */ | |
764 rv = SECFailure; | |
765 goto done; | |
766 } | |
767 | |
768 /* Simulate a token removal -- we need to do this any | |
769 * any case at this point so the token name is correct. */ | |
770 *tokenRemoved = PR_TRUE; | |
771 | |
772 /* | |
773 * OK, we got the update DB password, see if we need a password | |
774 * for the target... | |
775 */ | |
776 if (sftkdb_HasPasswordSet(keydb) == SECSuccess) { | |
777 /* We have a password, do we know what the password is? | |
778 * check 1) for the password the user supplied for the | |
779 * update DB, | |
780 * and 2) for the null password. | |
781 * | |
782 * RECURSION NOTE: we are calling ourselves here. This means | |
783 * any updates, switchKeys, etc will have been completed | |
784 * if these functions return successfully, in those cases | |
785 * just exit returning Success. We don't recurse infinitely | |
786 * because we are making this call from a NeedUpdateDBPassword | |
787 * block and we've already set that update password at this | |
788 * point. */ | |
789 rv = sftkdb_CheckPassword(keydb, pw, tokenRemoved); | |
790 if (rv == SECSuccess) { | |
791 /* source and target databases have the same password, we | |
792 * are good to go */ | |
793 goto done; | |
794 } | |
795 sftkdb_CheckPassword(keydb, "", tokenRemoved); | |
796 | |
797 /* | |
798 * Important 'NULL' code here. At this point either we | |
799 * succeeded in logging in with "" or we didn't. | |
800 * | |
801 * If we did succeed at login, our machine state will be set | |
802 * to logged in appropriately. The application will find that | |
803 * it's logged in as soon as it opens a new session. We have | |
804 * also completed the update. Life is good. | |
805 * | |
806 * If we did not succeed, well the user still successfully | |
807 * logged into the update database, since we faked the token | |
808 * removal it's just like the user logged into his smart card | |
809 * then removed it. the actual login work, so we report that | |
810 * success back to the user, but we won't actually be | |
811 * logged in. The application will find this out when it | |
812 * checks it's login state, thus triggering another password | |
813 * prompt so we can get the real target DB password. | |
814 * | |
815 * summary, we exit from here with SECSuccess no matter what. | |
816 */ | |
817 rv = SECSuccess; | |
818 goto done; | |
819 } else { | |
820 /* there is no password, just fall through to update. | |
821 * update will write the source DB's password record | |
822 * into the target DB just like it would in a non-merge | |
823 * update case. */ | |
824 } | |
825 } else { | |
826 PZ_Unlock(keydb->passwordLock); | |
827 } | |
828 /* load the keys, so the keydb can parse it's key set */ | |
829 sftkdb_switchKeys(keydb, &key); | |
830 | |
831 /* we need to update, do it now */ | |
832 if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) { | |
833 /* update the peer certdb if it exists */ | |
834 if (keydb->peerDB) { | |
835 sftkdb_Update(keydb->peerDB, &key); | |
836 } | |
837 sftkdb_Update(keydb, &key); | |
838 } | |
839 } else { | |
840 rv = SECFailure; | |
841 /*PORT_SetError( bad password); */ | |
842 } | |
843 | |
844 done: | |
845 if (key.data) { | |
846 PORT_ZFree(key.data,key.len); | |
847 } | |
848 if (result) { | |
849 SECITEM_FreeItem(result,PR_TRUE); | |
850 } | |
851 return rv; | |
852 } | |
853 | |
854 /* | |
855 * return Success if the there is a cached password key. | |
856 */ | |
857 SECStatus | |
858 sftkdb_PWCached(SFTKDBHandle *keydb) | |
859 { | |
860 return keydb->passwordKey.data ? SECSuccess : SECFailure; | |
861 } | |
862 | |
863 | |
864 static CK_RV | |
865 sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle, | |
866 CK_OBJECT_HANDLE id, SECItem *newKey) | |
867 { | |
868 CK_ATTRIBUTE authAttrs[] = { | |
869 {CKA_MODULUS, NULL, 0}, | |
870 {CKA_PUBLIC_EXPONENT, NULL, 0}, | |
871 {CKA_CERT_SHA1_HASH, NULL, 0}, | |
872 {CKA_CERT_MD5_HASH, NULL, 0}, | |
873 {CKA_TRUST_SERVER_AUTH, NULL, 0}, | |
874 {CKA_TRUST_CLIENT_AUTH, NULL, 0}, | |
875 {CKA_TRUST_EMAIL_PROTECTION, NULL, 0}, | |
876 {CKA_TRUST_CODE_SIGNING, NULL, 0}, | |
877 {CKA_TRUST_STEP_UP_APPROVED, NULL, 0}, | |
878 {CKA_NSS_OVERRIDE_EXTENSIONS, NULL, 0}, | |
879 }; | |
880 CK_ULONG authAttrCount = sizeof(authAttrs)/sizeof(CK_ATTRIBUTE); | |
881 unsigned int i, count; | |
882 SFTKDBHandle *keyHandle = handle; | |
883 SDB *keyTarget = NULL; | |
884 | |
885 id &= SFTK_OBJ_ID_MASK; | |
886 | |
887 if (handle->type != SFTK_KEYDB_TYPE) { | |
888 keyHandle = handle->peerDB; | |
889 } | |
890 | |
891 if (keyHandle == NULL) { | |
892 return CKR_OK; | |
893 } | |
894 | |
895 /* old DB's don't have meta data, finished with MACs */ | |
896 keyTarget = SFTK_GET_SDB(keyHandle); | |
897 if ((keyTarget->sdb_flags &SDB_HAS_META) == 0) { | |
898 return CKR_OK; | |
899 } | |
900 | |
901 /* | |
902 * STEP 1: find the MACed attributes of this object | |
903 */ | |
904 (void)sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount); | |
905 count = 0; | |
906 /* allocate space for the attributes */ | |
907 for (i=0; i < authAttrCount; i++) { | |
908 if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){ | |
909 continue; | |
910 } | |
911 count++; | |
912 authAttrs[i].pValue = PORT_ArenaAlloc(arena,authAttrs[i].ulValueLen); | |
913 if (authAttrs[i].pValue == NULL) { | |
914 break; | |
915 } | |
916 } | |
917 | |
918 /* if count was zero, none were found, finished with MACs */ | |
919 if (count == 0) { | |
920 return CKR_OK; | |
921 } | |
922 | |
923 (void)sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount); | |
924 /* ignore error code, we expect some possible errors */ | |
925 | |
926 /* GetAttributeValue just verified the old macs, safe to write | |
927 * them out then... */ | |
928 for (i=0; i < authAttrCount; i++) { | |
929 SECItem *signText; | |
930 SECItem plainText; | |
931 SECStatus rv; | |
932 | |
933 if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){ | |
934 continue; | |
935 } | |
936 | |
937 plainText.data = authAttrs[i].pValue; | |
938 plainText.len = authAttrs[i].ulValueLen; | |
939 rv = sftkdb_SignAttribute(arena, newKey, id, | |
940 authAttrs[i].type, &plainText, &signText); | |
941 if (rv != SECSuccess) { | |
942 return CKR_GENERAL_ERROR; | |
943 } | |
944 rv = sftkdb_PutAttributeSignature(handle, keyTarget, id, | |
945 authAttrs[i].type, signText); | |
946 if (rv != SECSuccess) { | |
947 return CKR_GENERAL_ERROR; | |
948 } | |
949 } | |
950 | |
951 return CKR_OK; | |
952 } | |
953 | |
954 static CK_RV | |
955 sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb, | |
956 CK_OBJECT_HANDLE id, SECItem *newKey) | |
957 { | |
958 CK_RV crv = CKR_OK; | |
959 CK_RV crv2; | |
960 CK_ATTRIBUTE *first, *last; | |
961 CK_ATTRIBUTE privAttrs[] = { | |
962 {CKA_VALUE, NULL, 0}, | |
963 {CKA_PRIVATE_EXPONENT, NULL, 0}, | |
964 {CKA_PRIME_1, NULL, 0}, | |
965 {CKA_PRIME_2, NULL, 0}, | |
966 {CKA_EXPONENT_1, NULL, 0}, | |
967 {CKA_EXPONENT_2, NULL, 0}, | |
968 {CKA_COEFFICIENT, NULL, 0} }; | |
969 CK_ULONG privAttrCount = sizeof(privAttrs)/sizeof(CK_ATTRIBUTE); | |
970 unsigned int i, count; | |
971 | |
972 /* | |
973 * STEP 1. Read the old attributes in the clear. | |
974 */ | |
975 | |
976 /* Get the attribute sizes. | |
977 * ignore the error code, we will have unknown attributes here */ | |
978 crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount); | |
979 | |
980 /* | |
981 * find the valid block of attributes and fill allocate space for | |
982 * their data */ | |
983 first = last = NULL; | |
984 for (i=0; i < privAttrCount; i++) { | |
985 /* find the block of attributes that are appropriate for this | |
986 * objects. There should only be once contiguous block, if not | |
987 * there's an error. | |
988 * | |
989 * find the first and last good entry. | |
990 */ | |
991 if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)){ | |
992 if (!first) continue; | |
993 if (!last) { | |
994 /* previous entry was last good entry */ | |
995 last= &privAttrs[i-1]; | |
996 } | |
997 continue; | |
998 } | |
999 if (!first) { | |
1000 first = &privAttrs[i]; | |
1001 } | |
1002 if (last) { | |
1003 /* OOPS, we've found another good entry beyond the end of the | |
1004 * last good entry, we need to fail here. */ | |
1005 crv = CKR_GENERAL_ERROR; | |
1006 break; | |
1007 } | |
1008 privAttrs[i].pValue = PORT_ArenaAlloc(arena,privAttrs[i].ulValueLen); | |
1009 if (privAttrs[i].pValue == NULL) { | |
1010 crv = CKR_HOST_MEMORY; | |
1011 break; | |
1012 } | |
1013 } | |
1014 if (first == NULL) { | |
1015 /* no valid entries found, return error based on crv2 */ | |
1016 return crv2; | |
1017 } | |
1018 if (last == NULL) { | |
1019 last = &privAttrs[privAttrCount-1]; | |
1020 } | |
1021 if (crv != CKR_OK) { | |
1022 return crv; | |
1023 } | |
1024 /* read the attributes */ | |
1025 count = (last-first)+1; | |
1026 crv = sftkdb_GetAttributeValue(keydb, id, first, count); | |
1027 if (crv != CKR_OK) { | |
1028 return crv; | |
1029 } | |
1030 | |
1031 /* | |
1032 * STEP 2: read the encrypt the attributes with the new key. | |
1033 */ | |
1034 for (i=0; i < count; i++) { | |
1035 SECItem plainText; | |
1036 SECItem *result; | |
1037 SECStatus rv; | |
1038 | |
1039 plainText.data = first[i].pValue; | |
1040 plainText.len = first[i].ulValueLen; | |
1041 rv = sftkdb_EncryptAttribute(arena, newKey, &plainText, &result); | |
1042 if (rv != SECSuccess) { | |
1043 return CKR_GENERAL_ERROR; | |
1044 } | |
1045 first[i].pValue = result->data; | |
1046 first[i].ulValueLen = result->len; | |
1047 /* clear our sensitive data out */ | |
1048 PORT_Memset(plainText.data, 0, plainText.len); | |
1049 } | |
1050 | |
1051 | |
1052 /* | |
1053 * STEP 3: write the newly encrypted attributes out directly | |
1054 */ | |
1055 id &= SFTK_OBJ_ID_MASK; | |
1056 keydb->newKey = newKey; | |
1057 crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count); | |
1058 keydb->newKey = NULL; | |
1059 | |
1060 return crv; | |
1061 } | |
1062 | |
1063 static CK_RV | |
1064 sftk_convertAttributes(SFTKDBHandle *handle, | |
1065 CK_OBJECT_HANDLE id, SECItem *newKey) | |
1066 { | |
1067 CK_RV crv = CKR_OK; | |
1068 PLArenaPool *arena = NULL; | |
1069 | |
1070 /* get a new arena to simplify cleanup */ | |
1071 arena = PORT_NewArena(1024); | |
1072 if (!arena) { | |
1073 return CKR_HOST_MEMORY; | |
1074 } | |
1075 | |
1076 /* | |
1077 * first handle the MACS | |
1078 */ | |
1079 crv = sftk_updateMacs(arena, handle, id, newKey); | |
1080 if (crv != CKR_OK) { | |
1081 goto loser; | |
1082 } | |
1083 | |
1084 if (handle->type == SFTK_KEYDB_TYPE) { | |
1085 crv = sftk_updateEncrypted(arena, handle, id, newKey); | |
1086 if (crv != CKR_OK) { | |
1087 goto loser; | |
1088 } | |
1089 } | |
1090 | |
1091 /* free up our mess */ | |
1092 /* NOTE: at this point we know we've cleared out any unencrypted data */ | |
1093 PORT_FreeArena(arena, PR_FALSE); | |
1094 return CKR_OK; | |
1095 | |
1096 loser: | |
1097 /* there may be unencrypted data, clear it out down */ | |
1098 PORT_FreeArena(arena, PR_TRUE); | |
1099 return crv; | |
1100 } | |
1101 | |
1102 | |
1103 /* | |
1104 * must be called with the old key active. | |
1105 */ | |
1106 CK_RV | |
1107 sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template, | |
1108 CK_ULONG count, SECItem *newKey) | |
1109 { | |
1110 SDBFind *find = NULL; | |
1111 CK_ULONG idCount = SFTK_MAX_IDS; | |
1112 CK_OBJECT_HANDLE ids[SFTK_MAX_IDS]; | |
1113 CK_RV crv, crv2; | |
1114 unsigned int i; | |
1115 | |
1116 crv = sftkdb_FindObjectsInit(handle, template, count, &find); | |
1117 | |
1118 if (crv != CKR_OK) { | |
1119 return crv; | |
1120 } | |
1121 while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) { | |
1122 crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount); | |
1123 for (i=0; (crv == CKR_OK) && (i < idCount); i++) { | |
1124 crv = sftk_convertAttributes(handle, ids[i], newKey); | |
1125 } | |
1126 } | |
1127 crv2 = sftkdb_FindObjectsFinal(handle, find); | |
1128 if (crv == CKR_OK) crv = crv2; | |
1129 | |
1130 return crv; | |
1131 } | |
1132 | |
1133 | |
1134 /* | |
1135 * change the database password. | |
1136 */ | |
1137 SECStatus | |
1138 sftkdb_ChangePassword(SFTKDBHandle *keydb, | |
1139 char *oldPin, char *newPin, PRBool *tokenRemoved) | |
1140 { | |
1141 SECStatus rv = SECSuccess; | |
1142 SECItem plainText; | |
1143 SECItem newKey; | |
1144 SECItem *result = NULL; | |
1145 SECItem salt, value; | |
1146 SFTKDBHandle *certdb; | |
1147 unsigned char saltData[SDB_MAX_META_DATA_LEN]; | |
1148 unsigned char valueData[SDB_MAX_META_DATA_LEN]; | |
1149 CK_RV crv; | |
1150 SDB *db; | |
1151 | |
1152 if (keydb == NULL) { | |
1153 return SECFailure; | |
1154 } | |
1155 | |
1156 db = SFTK_GET_SDB(keydb); | |
1157 if (db == NULL) { | |
1158 return SECFailure; | |
1159 } | |
1160 | |
1161 newKey.data = NULL; | |
1162 | |
1163 /* make sure we have a valid old pin */ | |
1164 crv = (*keydb->db->sdb_Begin)(keydb->db); | |
1165 if (crv != CKR_OK) { | |
1166 rv = SECFailure; | |
1167 goto loser; | |
1168 } | |
1169 salt.data = saltData; | |
1170 salt.len = sizeof(saltData); | |
1171 value.data = valueData; | |
1172 value.len = sizeof(valueData); | |
1173 crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value); | |
1174 if (crv == CKR_OK) { | |
1175 rv = sftkdb_CheckPassword(keydb, oldPin, tokenRemoved); | |
1176 if (rv == SECFailure) { | |
1177 goto loser; | |
1178 } | |
1179 } else { | |
1180 salt.len = SHA1_LENGTH; | |
1181 RNG_GenerateGlobalRandomBytes(salt.data,salt.len); | |
1182 } | |
1183 | |
1184 rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey); | |
1185 if (rv != SECSuccess) { | |
1186 goto loser; | |
1187 } | |
1188 | |
1189 | |
1190 /* | |
1191 * convert encrypted entries here. | |
1192 */ | |
1193 crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey); | |
1194 if (crv != CKR_OK) { | |
1195 rv = SECFailure; | |
1196 goto loser; | |
1197 } | |
1198 /* fix up certdb macs */ | |
1199 certdb = keydb->peerDB; | |
1200 if (certdb) { | |
1201 CK_ATTRIBUTE objectType = { CKA_CLASS, 0, sizeof(CK_OBJECT_CLASS) }; | |
1202 CK_OBJECT_CLASS myClass = CKO_NETSCAPE_TRUST; | |
1203 | |
1204 objectType.pValue = &myClass; | |
1205 crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey); | |
1206 if (crv != CKR_OK) { | |
1207 rv = SECFailure; | |
1208 goto loser; | |
1209 } | |
1210 myClass = CKO_PUBLIC_KEY; | |
1211 crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey); | |
1212 if (crv != CKR_OK) { | |
1213 rv = SECFailure; | |
1214 goto loser; | |
1215 } | |
1216 } | |
1217 | |
1218 | |
1219 plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING; | |
1220 plainText.len = SFTK_PW_CHECK_LEN; | |
1221 | |
1222 rv = sftkdb_EncryptAttribute(NULL, &newKey, &plainText, &result); | |
1223 if (rv != SECSuccess) { | |
1224 goto loser; | |
1225 } | |
1226 value.data = result->data; | |
1227 value.len = result->len; | |
1228 crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value); | |
1229 if (crv != CKR_OK) { | |
1230 rv = SECFailure; | |
1231 goto loser; | |
1232 } | |
1233 crv = (*keydb->db->sdb_Commit)(keydb->db); | |
1234 if (crv != CKR_OK) { | |
1235 rv = SECFailure; | |
1236 goto loser; | |
1237 } | |
1238 | |
1239 keydb->newKey = NULL; | |
1240 | |
1241 sftkdb_switchKeys(keydb, &newKey); | |
1242 | |
1243 loser: | |
1244 if (newKey.data) { | |
1245 PORT_ZFree(newKey.data,newKey.len); | |
1246 } | |
1247 if (result) { | |
1248 SECITEM_FreeItem(result, PR_TRUE); | |
1249 } | |
1250 if (rv != SECSuccess) { | |
1251 (*keydb->db->sdb_Abort)(keydb->db); | |
1252 } | |
1253 | |
1254 return rv; | |
1255 } | |
1256 | |
1257 /* | |
1258 * lose our cached password | |
1259 */ | |
1260 SECStatus | |
1261 sftkdb_ClearPassword(SFTKDBHandle *keydb) | |
1262 { | |
1263 SECItem oldKey; | |
1264 oldKey.data = NULL; | |
1265 oldKey.len = 0; | |
1266 sftkdb_switchKeys(keydb, &oldKey); | |
1267 if (oldKey.data) { | |
1268 PORT_ZFree(oldKey.data, oldKey.len); | |
1269 } | |
1270 return SECSuccess; | |
1271 } | |
1272 | |
1273 | |
OLD | NEW |