Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(566)

Side by Side Diff: nss/lib/softoken/sftkpwd.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/lib/softoken/sftkpars.c ('k') | nss/lib/softoken/softkver.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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, &param->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
OLDNEW
« no previous file with comments | « nss/lib/softoken/sftkpars.c ('k') | nss/lib/softoken/softkver.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698