comparison nss/lib/softoken/sftkpwd.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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, &cipherValue.salt, 1);
281 if (param == NULL) {
282 rv = SECFailure;
283 goto loser;
284 }
285 cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL);
286 if (cipher == NULL) {
287 rv = SECFailure;
288 goto loser;
289 }
290 cipherValue.value = *cipher;
291 cipherValue.param = param;
292
293 rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText);
294 if (rv != SECSuccess) {
295 goto loser;
296 }
297
298 loser:
299 if (cipher) {
300 SECITEM_FreeItem(cipher, PR_TRUE);
301 }
302 if (param) {
303 nsspkcs5_DestroyPBEParameter(param);
304 }
305 return rv;
306 }
307
308 /*
309 * use the password and the pbe parameters to generate an HMAC for the
310 * given plain text data. This is used by sftkdb_VerifyAttribute and
311 * sftkdb_SignAttribute. Signature is returned in signData. The caller
312 * must preallocate the space in the secitem.
313 */
314 static SECStatus
315 sftkdb_pbehash(SECOidTag sigOid, SECItem *passKey,
316 NSSPKCS5PBEParameter *param,
317 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
318 SECItem *plainText, SECItem *signData)
319 {
320 SECStatus rv = SECFailure;
321 SECItem *key = NULL;
322 HMACContext *hashCx = NULL;
323 HASH_HashType hashType = HASH_AlgNULL;
324 const SECHashObject *hashObj;
325 unsigned char addressData[SDB_ULONG_SIZE];
326
327 hashType = HASH_FromHMACOid(param->encAlg);
328 if (hashType == HASH_AlgNULL) {
329 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
330 return SECFailure;
331 }
332
333 hashObj = HASH_GetRawHashObject(hashType);
334 if (hashObj == NULL) {
335 goto loser;
336 }
337
338 key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE);
339 if (!key) {
340 goto loser;
341 }
342
343 hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE);
344 if (!hashCx) {
345 goto loser;
346 }
347 HMAC_Begin(hashCx);
348 /* Tie this value to a particular object. This is most important for
349 * the trust attributes, where and attacker could copy a value for
350 * 'validCA' from another cert in the database */
351 sftk_ULong2SDBULong(addressData, objectID);
352 HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
353 sftk_ULong2SDBULong(addressData, attrType);
354 HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
355
356 HMAC_Update(hashCx, plainText->data, plainText->len);
357 rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len);
358
359 loser:
360 if (hashCx) {
361 HMAC_Destroy(hashCx, PR_TRUE);
362 }
363 if (key) {
364 SECITEM_FreeItem(key,PR_TRUE);
365 }
366 return rv;
367 }
368
369 /*
370 * Use our key to verify a signText block from the database matches
371 * the plainText from the database. The signText is a PKCS 5 v2 pbe.
372 * plainText is the plainText of the attribute.
373 */
374 SECStatus
375 sftkdb_VerifyAttribute(SECItem *passKey, CK_OBJECT_HANDLE objectID,
376 CK_ATTRIBUTE_TYPE attrType,
377 SECItem *plainText, SECItem *signText)
378 {
379 SECStatus rv;
380 sftkCipherValue signValue;
381 SECItem signature;
382 unsigned char signData[HASH_LENGTH_MAX];
383
384
385 /* First get the cipher type */
386 rv = sftkdb_decodeCipherText(signText, &signValue);
387 if (rv != SECSuccess) {
388 goto loser;
389 }
390 signature.data = signData;
391 signature.len = sizeof(signData);
392
393 rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param,
394 objectID, attrType, plainText, &signature);
395 if (rv != SECSuccess) {
396 goto loser;
397 }
398 if (SECITEM_CompareItem(&signValue.value,&signature) != 0) {
399 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
400 rv = SECFailure;
401 }
402
403 loser:
404 if (signValue.param) {
405 nsspkcs5_DestroyPBEParameter(signValue.param);
406 }
407 if (signValue.arena) {
408 PORT_FreeArena(signValue.arena,PR_FALSE);
409 }
410 return rv;
411 }
412
413 /*
414 * Use our key to create a signText block the plain text of an
415 * attribute. The signText is a PKCS 5 v2 pbe.
416 */
417 SECStatus
418 sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey,
419 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
420 SECItem *plainText, SECItem **signature)
421 {
422 SECStatus rv;
423 sftkCipherValue signValue;
424 NSSPKCS5PBEParameter *param = NULL;
425 unsigned char saltData[HASH_LENGTH_MAX];
426 unsigned char signData[HASH_LENGTH_MAX];
427 SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */
428 SECOidTag prfAlg = SEC_OID_HMAC_SHA256; /* hash for pb key generation */
429 HASH_HashType prfType;
430 unsigned int hmacLength;
431 unsigned int prfLength;
432
433 /* this code allows us to fetch the lengths and hashes on the fly
434 * by simply changing the OID above */
435 prfType = HASH_FromHMACOid(prfAlg);
436 PORT_Assert(prfType != HASH_AlgNULL);
437 prfLength = HASH_GetRawHashObject(prfType)->length;
438 PORT_Assert(prfLength <= HASH_LENGTH_MAX);
439
440 hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length;
441 PORT_Assert(hmacLength <= HASH_LENGTH_MAX);
442
443 /* initialize our CipherValue structure */
444 signValue.alg = SEC_OID_PKCS5_PBMAC1;
445 signValue.salt.len = prfLength;
446 signValue.salt.data = saltData;
447 signValue.value.data = signData;
448 signValue.value.len = hmacLength;
449 RNG_GenerateGlobalRandomBytes(saltData,prfLength);
450
451 /* initialize our pkcs5 parameter */
452 param = nsspkcs5_NewParam(signValue.alg, &signValue.salt, 1);
453 if (param == NULL) {
454 rv = SECFailure;
455 goto loser;
456 }
457 param->keyID = pbeBitGenIntegrityKey;
458 /* set the PKCS 5 v2 parameters, not extractable from the
459 * data passed into nsspkcs5_NewParam */
460 param->encAlg = hmacAlg;
461 param->hashType = prfType;
462 param->keyLen = hmacLength;
463 rv = SECOID_SetAlgorithmID(param->poolp, &param->prfAlg, prfAlg, NULL);
464 if (rv != SECSuccess) {
465 goto loser;
466 }
467
468
469 /* calculate the mac */
470 rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType,
471 plainText, &signValue.value);
472 if (rv != SECSuccess) {
473 goto loser;
474 }
475 signValue.param = param;
476
477 /* write it out */
478 rv = sftkdb_encodeCipherText(arena, &signValue, signature);
479 if (rv != SECSuccess) {
480 goto loser;
481 }
482
483 loser:
484 if (param) {
485 nsspkcs5_DestroyPBEParameter(param);
486 }
487 return rv;
488 }
489
490 /*
491 * safely swith the passed in key for the one caches in the keydb handle
492 *
493 * A key attached to the handle tells us the the token is logged in.
494 * We can used the key attached to the handle in sftkdb_EncryptAttribute
495 * and sftkdb_DecryptAttribute calls.
496 */
497 static void
498 sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey)
499 {
500 unsigned char *data;
501 int len;
502
503 if (keydb->passwordLock == NULL) {
504 PORT_Assert(keydb->type != SFTK_KEYDB_TYPE);
505 return;
506 }
507
508 /* an atomic pointer set would be nice */
509 SKIP_AFTER_FORK(PZ_Lock(keydb->passwordLock));
510 data = keydb->passwordKey.data;
511 len = keydb->passwordKey.len;
512 keydb->passwordKey.data = passKey->data;
513 keydb->passwordKey.len = passKey->len;
514 passKey->data = data;
515 passKey->len = len;
516 SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock));
517 }
518
519 /*
520 * returns true if we are in a middle of a merge style update.
521 */
522 PRBool
523 sftkdb_InUpdateMerge(SFTKDBHandle *keydb)
524 {
525 return keydb->updateID ? PR_TRUE : PR_FALSE;
526 }
527
528 /*
529 * returns true if we are looking for the password for the user's old source
530 * database as part of a merge style update.
531 */
532 PRBool
533 sftkdb_NeedUpdateDBPassword(SFTKDBHandle *keydb)
534 {
535 if (!sftkdb_InUpdateMerge(keydb)) {
536 return PR_FALSE;
537 }
538 if (keydb->updateDBIsInit && !keydb->updatePasswordKey) {
539 return PR_TRUE;
540 }
541 return PR_FALSE;
542 }
543
544 /*
545 * fetch an update password key from a handle.
546 */
547 SECItem *
548 sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle)
549 {
550 SECItem *key = NULL;
551
552 /* if we're a cert db, fetch it from our peer key db */
553 if (handle->type == SFTK_CERTDB_TYPE) {
554 handle = handle->peerDB;
555 }
556
557 /* don't have one */
558 if (!handle) {
559 return NULL;
560 }
561
562 PZ_Lock(handle->passwordLock);
563 if (handle->updatePasswordKey) {
564 key = SECITEM_DupItem(handle->updatePasswordKey);
565 }
566 PZ_Unlock(handle->passwordLock);
567
568 return key;
569 }
570
571 /*
572 * free the update password key from a handle.
573 */
574 void
575 sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle)
576 {
577 SECItem *key = NULL;
578
579 /* don't have one */
580 if (!handle) {
581 return;
582 }
583
584 /* if we're a cert db, we don't have one */
585 if (handle->type == SFTK_CERTDB_TYPE) {
586 return;
587 }
588
589 PZ_Lock(handle->passwordLock);
590 if (handle->updatePasswordKey) {
591 key = handle->updatePasswordKey;
592 handle->updatePasswordKey = NULL;
593 }
594 PZ_Unlock(handle->passwordLock);
595
596 if (key) {
597 SECITEM_ZfreeItem(key, PR_TRUE);
598 }
599
600 return;
601 }
602
603 /*
604 * what password db we use depends heavily on the update state machine
605 *
606 * 1) no update db, return the normal database.
607 * 2) update db and no merge return the update db.
608 * 3) update db and in merge:
609 * return the update db if we need the update db's password,
610 * otherwise return our normal datbase.
611 */
612 static SDB *
613 sftk_getPWSDB(SFTKDBHandle *keydb)
614 {
615 if (!keydb->update) {
616 return keydb->db;
617 }
618 if (!sftkdb_InUpdateMerge(keydb)) {
619 return keydb->update;
620 }
621 if (sftkdb_NeedUpdateDBPassword(keydb)) {
622 return keydb->update;
623 }
624 return keydb->db;
625 }
626
627 /*
628 * return success if we have a valid password entry.
629 * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT
630 * in the token flags.
631 */
632 SECStatus
633 sftkdb_HasPasswordSet(SFTKDBHandle *keydb)
634 {
635 SECItem salt, value;
636 unsigned char saltData[SDB_MAX_META_DATA_LEN];
637 unsigned char valueData[SDB_MAX_META_DATA_LEN];
638 CK_RV crv;
639 SDB *db;
640
641 if (keydb == NULL) {
642 return SECFailure;
643 }
644
645 db = sftk_getPWSDB(keydb);
646 if (db == NULL) {
647 return SECFailure;
648 }
649
650 salt.data = saltData;
651 salt.len = sizeof(saltData);
652 value.data = valueData;
653 value.len = sizeof(valueData);
654 crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
655
656 /* If no password is set, we can update right away */
657 if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update
658 && crv != CKR_OK) {
659 /* update the peer certdb if it exists */
660 if (keydb->peerDB) {
661 sftkdb_Update(keydb->peerDB, NULL);
662 }
663 sftkdb_Update(keydb, NULL);
664 }
665 return (crv == CKR_OK) ? SECSuccess : SECFailure;
666 }
667
668 #define SFTK_PW_CHECK_STRING "password-check"
669 #define SFTK_PW_CHECK_LEN 14
670
671 /*
672 * check if the supplied password is valid
673 */
674 SECStatus
675 sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
676 {
677 SECStatus rv;
678 SECItem salt, value;
679 unsigned char saltData[SDB_MAX_META_DATA_LEN];
680 unsigned char valueData[SDB_MAX_META_DATA_LEN];
681 SECItem key;
682 SECItem *result = NULL;
683 SDB *db;
684 CK_RV crv;
685
686 if (keydb == NULL) {
687 return SECFailure;
688 }
689
690 db = sftk_getPWSDB(keydb);
691 if (db == NULL) {
692 return SECFailure;
693 }
694
695 key.data = NULL;
696 key.len = 0;
697
698 if (pw == NULL) pw="";
699
700 /* get the entry from the database */
701 salt.data = saltData;
702 salt.len = sizeof(saltData);
703 value.data = valueData;
704 value.len = sizeof(valueData);
705 crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
706 if (crv != CKR_OK) {
707 rv = SECFailure;
708 goto done;
709 }
710
711 /* get our intermediate key based on the entry salt value */
712 rv = sftkdb_passwordToKey(keydb, &salt, pw, &key);
713 if (rv != SECSuccess) {
714 goto done;
715 }
716
717 /* decrypt the entry value */
718 rv = sftkdb_DecryptAttribute(&key, &value, &result);
719 if (rv != SECSuccess) {
720 goto done;
721 }
722
723 /* if it's what we expect, update our key in the database handle and
724 * return Success */
725 if ((result->len == SFTK_PW_CHECK_LEN) &&
726 PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0){
727 /*
728 * We have a password, now lets handle any potential update cases..
729 *
730 * First, the normal case: no update. In this case we only need the
731 * the password for our only DB, which we now have, we switch
732 * the keys and fall through.
733 * Second regular (non-merge) update: The target DB does not yet have
734 * a password initialized, we now have the password for the source DB,
735 * so we can switch the keys and simply update the target database.
736 * Merge update case: This one is trickier.
737 * 1) If we need the source DB password, then we just got it here.
738 * We need to save that password,
739 * then we need to check to see if we need or have the target
740 * database password.
741 * If we have it (it's the same as the source), or don't need
742 * it (it's not set or is ""), we can start the update now.
743 * If we don't have it, we need the application to get it from
744 * the user. Clear our sessions out to simulate a token
745 * removal. C_GetTokenInfo will change the token description
746 * and the token will still appear to be logged out.
747 * 2) If we already have the source DB password, this password is
748 * for the target database. We can now move forward with the
749 * update, as we now have both required passwords.
750 *
751 */
752 PZ_Lock(keydb->passwordLock);
753 if (sftkdb_NeedUpdateDBPassword(keydb)) {
754 /* Squirrel this special key away.
755 * This has the side effect of turning sftkdb_NeedLegacyPW off,
756 * as well as changing which database is returned from
757 * SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword()
758 * and sftkdb_HasPasswordSet()) */
759 keydb->updatePasswordKey = SECITEM_DupItem(&key);
760 PZ_Unlock(keydb->passwordLock);
761 if (keydb->updatePasswordKey == NULL) {
762 /* PORT_Error set by SECITEM_DupItem */
763 rv = SECFailure;
764 goto done;
765 }
766
767 /* Simulate a token removal -- we need to do this any
768 * any case at this point so the token name is correct. */
769 *tokenRemoved = PR_TRUE;
770
771 /*
772 * OK, we got the update DB password, see if we need a password
773 * for the target...
774 */
775 if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
776 /* We have a password, do we know what the password is?
777 * check 1) for the password the user supplied for the
778 * update DB,
779 * and 2) for the null password.
780 *
781 * RECURSION NOTE: we are calling ourselves here. This means
782 * any updates, switchKeys, etc will have been completed
783 * if these functions return successfully, in those cases
784 * just exit returning Success. We don't recurse infinitely
785 * because we are making this call from a NeedUpdateDBPassword
786 * block and we've already set that update password at this
787 * point. */
788 rv = sftkdb_CheckPassword(keydb, pw, tokenRemoved);
789 if (rv == SECSuccess) {
790 /* source and target databases have the same password, we
791 * are good to go */
792 goto done;
793 }
794 sftkdb_CheckPassword(keydb, "", tokenRemoved);
795
796 /*
797 * Important 'NULL' code here. At this point either we
798 * succeeded in logging in with "" or we didn't.
799 *
800 * If we did succeed at login, our machine state will be set
801 * to logged in appropriately. The application will find that
802 * it's logged in as soon as it opens a new session. We have
803 * also completed the update. Life is good.
804 *
805 * If we did not succeed, well the user still successfully
806 * logged into the update database, since we faked the token
807 * removal it's just like the user logged into his smart card
808 * then removed it. the actual login work, so we report that
809 * success back to the user, but we won't actually be
810 * logged in. The application will find this out when it
811 * checks it's login state, thus triggering another password
812 * prompt so we can get the real target DB password.
813 *
814 * summary, we exit from here with SECSuccess no matter what.
815 */
816 rv = SECSuccess;
817 goto done;
818 } else {
819 /* there is no password, just fall through to update.
820 * update will write the source DB's password record
821 * into the target DB just like it would in a non-merge
822 * update case. */
823 }
824 } else {
825 PZ_Unlock(keydb->passwordLock);
826 }
827 /* load the keys, so the keydb can parse it's key set */
828 sftkdb_switchKeys(keydb, &key);
829
830 /* we need to update, do it now */
831 if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) {
832 /* update the peer certdb if it exists */
833 if (keydb->peerDB) {
834 sftkdb_Update(keydb->peerDB, &key);
835 }
836 sftkdb_Update(keydb, &key);
837 }
838 } else {
839 rv = SECFailure;
840 /*PORT_SetError( bad password); */
841 }
842
843 done:
844 if (key.data) {
845 PORT_ZFree(key.data,key.len);
846 }
847 if (result) {
848 SECITEM_FreeItem(result,PR_TRUE);
849 }
850 return rv;
851 }
852
853 /*
854 * return Success if the there is a cached password key.
855 */
856 SECStatus
857 sftkdb_PWCached(SFTKDBHandle *keydb)
858 {
859 return keydb->passwordKey.data ? SECSuccess : SECFailure;
860 }
861
862
863 static CK_RV
864 sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
865 CK_OBJECT_HANDLE id, SECItem *newKey)
866 {
867 CK_RV crv = CKR_OK;
868 CK_RV crv2;
869 CK_ATTRIBUTE authAttrs[] = {
870 {CKA_MODULUS, NULL, 0},
871 {CKA_PUBLIC_EXPONENT, NULL, 0},
872 {CKA_CERT_SHA1_HASH, NULL, 0},
873 {CKA_CERT_MD5_HASH, NULL, 0},
874 {CKA_TRUST_SERVER_AUTH, NULL, 0},
875 {CKA_TRUST_CLIENT_AUTH, NULL, 0},
876 {CKA_TRUST_EMAIL_PROTECTION, NULL, 0},
877 {CKA_TRUST_CODE_SIGNING, NULL, 0},
878 {CKA_TRUST_STEP_UP_APPROVED, NULL, 0},
879 {CKA_NSS_OVERRIDE_EXTENSIONS, NULL, 0},
880 };
881 CK_ULONG authAttrCount = sizeof(authAttrs)/sizeof(CK_ATTRIBUTE);
882 int i, count;
883 SFTKDBHandle *keyHandle = handle;
884 SDB *keyTarget = NULL;
885
886 id &= SFTK_OBJ_ID_MASK;
887
888 if (handle->type != SFTK_KEYDB_TYPE) {
889 keyHandle = handle->peerDB;
890 }
891
892 if (keyHandle == NULL) {
893 return CKR_OK;
894 }
895
896 /* old DB's don't have meta data, finished with MACs */
897 keyTarget = SFTK_GET_SDB(keyHandle);
898 if ((keyTarget->sdb_flags &SDB_HAS_META) == 0) {
899 return CKR_OK;
900 }
901
902 /*
903 * STEP 1: find the MACed attributes of this object
904 */
905 crv2 = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
906 count = 0;
907 /* allocate space for the attributes */
908 for (i=0; i < authAttrCount; i++) {
909 if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){
910 continue;
911 }
912 count++;
913 authAttrs[i].pValue = PORT_ArenaAlloc(arena,authAttrs[i].ulValueLen);
914 if (authAttrs[i].pValue == NULL) {
915 crv = CKR_HOST_MEMORY;
916 break;
917 }
918 }
919
920 /* if count was zero, none were found, finished with MACs */
921 if (count == 0) {
922 return CKR_OK;
923 }
924
925 crv = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
926 /* ignore error code, we expect some possible errors */
927
928 /* GetAttributeValue just verified the old macs, safe to write
929 * them out then... */
930 for (i=0; i < authAttrCount; i++) {
931 SECItem *signText;
932 SECItem plainText;
933 SECStatus rv;
934
935 if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){
936 continue;
937 }
938
939 plainText.data = authAttrs[i].pValue;
940 plainText.len = authAttrs[i].ulValueLen;
941 rv = sftkdb_SignAttribute(arena, newKey, id,
942 authAttrs[i].type, &plainText, &signText);
943 if (rv != SECSuccess) {
944 return CKR_GENERAL_ERROR;
945 }
946 rv = sftkdb_PutAttributeSignature(handle, keyTarget, id,
947 authAttrs[i].type, signText);
948 if (rv != SECSuccess) {
949 return CKR_GENERAL_ERROR;
950 }
951 }
952
953 return CKR_OK;
954 }
955
956 static CK_RV
957 sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
958 CK_OBJECT_HANDLE id, SECItem *newKey)
959 {
960 CK_RV crv = CKR_OK;
961 CK_RV crv2;
962 CK_ATTRIBUTE *first, *last;
963 CK_ATTRIBUTE privAttrs[] = {
964 {CKA_VALUE, NULL, 0},
965 {CKA_PRIVATE_EXPONENT, NULL, 0},
966 {CKA_PRIME_1, NULL, 0},
967 {CKA_PRIME_2, NULL, 0},
968 {CKA_EXPONENT_1, NULL, 0},
969 {CKA_EXPONENT_2, NULL, 0},
970 {CKA_COEFFICIENT, NULL, 0} };
971 CK_ULONG privAttrCount = sizeof(privAttrs)/sizeof(CK_ATTRIBUTE);
972 int i, count;
973
974 /*
975 * STEP 1. Read the old attributes in the clear.
976 */
977
978 /* Get the attribute sizes.
979 * ignore the error code, we will have unknown attributes here */
980 crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount);
981
982 /*
983 * find the valid block of attributes and fill allocate space for
984 * their data */
985 first = last = NULL;
986 for (i=0; i < privAttrCount; i++) {
987 /* find the block of attributes that are appropriate for this
988 * objects. There should only be once contiguous block, if not
989 * there's an error.
990 *
991 * find the first and last good entry.
992 */
993 if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)){
994 if (!first) continue;
995 if (!last) {
996 /* previous entry was last good entry */
997 last= &privAttrs[i-1];
998 }
999 continue;
1000 }
1001 if (!first) {
1002 first = &privAttrs[i];
1003 }
1004 if (last) {
1005 /* OOPS, we've found another good entry beyond the end of the
1006 * last good entry, we need to fail here. */
1007 crv = CKR_GENERAL_ERROR;
1008 break;
1009 }
1010 privAttrs[i].pValue = PORT_ArenaAlloc(arena,privAttrs[i].ulValueLen);
1011 if (privAttrs[i].pValue == NULL) {
1012 crv = CKR_HOST_MEMORY;
1013 break;
1014 }
1015 }
1016 if (first == NULL) {
1017 /* no valid entries found, return error based on crv2 */
1018 return crv2;
1019 }
1020 if (last == NULL) {
1021 last = &privAttrs[privAttrCount-1];
1022 }
1023 if (crv != CKR_OK) {
1024 return crv;
1025 }
1026 /* read the attributes */
1027 count = (last-first)+1;
1028 crv = sftkdb_GetAttributeValue(keydb, id, first, count);
1029 if (crv != CKR_OK) {
1030 return crv;
1031 }
1032
1033 /*
1034 * STEP 2: read the encrypt the attributes with the new key.
1035 */
1036 for (i=0; i < count; i++) {
1037 SECItem plainText;
1038 SECItem *result;
1039 SECStatus rv;
1040
1041 plainText.data = first[i].pValue;
1042 plainText.len = first[i].ulValueLen;
1043 rv = sftkdb_EncryptAttribute(arena, newKey, &plainText, &result);
1044 if (rv != SECSuccess) {
1045 return CKR_GENERAL_ERROR;
1046 }
1047 first[i].pValue = result->data;
1048 first[i].ulValueLen = result->len;
1049 /* clear our sensitive data out */
1050 PORT_Memset(plainText.data, 0, plainText.len);
1051 }
1052
1053
1054 /*
1055 * STEP 3: write the newly encrypted attributes out directly
1056 */
1057 id &= SFTK_OBJ_ID_MASK;
1058 keydb->newKey = newKey;
1059 crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count);
1060 keydb->newKey = NULL;
1061
1062 return crv;
1063 }
1064
1065 static CK_RV
1066 sftk_convertAttributes(SFTKDBHandle *handle,
1067 CK_OBJECT_HANDLE id, SECItem *newKey)
1068 {
1069 CK_RV crv = CKR_OK;
1070 PLArenaPool *arena = NULL;
1071
1072 /* get a new arena to simplify cleanup */
1073 arena = PORT_NewArena(1024);
1074 if (!arena) {
1075 return CKR_HOST_MEMORY;
1076 }
1077
1078 /*
1079 * first handle the MACS
1080 */
1081 crv = sftk_updateMacs(arena, handle, id, newKey);
1082 if (crv != CKR_OK) {
1083 goto loser;
1084 }
1085
1086 if (handle->type == SFTK_KEYDB_TYPE) {
1087 crv = sftk_updateEncrypted(arena, handle, id, newKey);
1088 if (crv != CKR_OK) {
1089 goto loser;
1090 }
1091 }
1092
1093 /* free up our mess */
1094 /* NOTE: at this point we know we've cleared out any unencrypted data */
1095 PORT_FreeArena(arena, PR_FALSE);
1096 return CKR_OK;
1097
1098 loser:
1099 /* there may be unencrypted data, clear it out down */
1100 PORT_FreeArena(arena, PR_TRUE);
1101 return crv;
1102 }
1103
1104
1105 /*
1106 * must be called with the old key active.
1107 */
1108 CK_RV
1109 sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template,
1110 CK_ULONG count, SECItem *newKey)
1111 {
1112 SDBFind *find = NULL;
1113 CK_ULONG idCount = SFTK_MAX_IDS;
1114 CK_OBJECT_HANDLE ids[SFTK_MAX_IDS];
1115 CK_RV crv, crv2;
1116 int i;
1117
1118 crv = sftkdb_FindObjectsInit(handle, template, count, &find);
1119
1120 if (crv != CKR_OK) {
1121 return crv;
1122 }
1123 while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) {
1124 crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount);
1125 for (i=0; (crv == CKR_OK) && (i < idCount); i++) {
1126 crv = sftk_convertAttributes(handle, ids[i], newKey);
1127 }
1128 }
1129 crv2 = sftkdb_FindObjectsFinal(handle, find);
1130 if (crv == CKR_OK) crv = crv2;
1131
1132 return crv;
1133 }
1134
1135
1136 /*
1137 * change the database password.
1138 */
1139 SECStatus
1140 sftkdb_ChangePassword(SFTKDBHandle *keydb,
1141 char *oldPin, char *newPin, PRBool *tokenRemoved)
1142 {
1143 SECStatus rv = SECSuccess;
1144 SECItem plainText;
1145 SECItem newKey;
1146 SECItem *result = NULL;
1147 SECItem salt, value;
1148 SFTKDBHandle *certdb;
1149 unsigned char saltData[SDB_MAX_META_DATA_LEN];
1150 unsigned char valueData[SDB_MAX_META_DATA_LEN];
1151 CK_RV crv;
1152 SDB *db;
1153
1154 if (keydb == NULL) {
1155 return SECFailure;
1156 }
1157
1158 db = SFTK_GET_SDB(keydb);
1159 if (db == NULL) {
1160 return SECFailure;
1161 }
1162
1163 newKey.data = NULL;
1164
1165 /* make sure we have a valid old pin */
1166 crv = (*keydb->db->sdb_Begin)(keydb->db);
1167 if (crv != CKR_OK) {
1168 rv = SECFailure;
1169 goto loser;
1170 }
1171 salt.data = saltData;
1172 salt.len = sizeof(saltData);
1173 value.data = valueData;
1174 value.len = sizeof(valueData);
1175 crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
1176 if (crv == CKR_OK) {
1177 rv = sftkdb_CheckPassword(keydb, oldPin, tokenRemoved);
1178 if (rv == SECFailure) {
1179 goto loser;
1180 }
1181 } else {
1182 salt.len = SHA1_LENGTH;
1183 RNG_GenerateGlobalRandomBytes(salt.data,salt.len);
1184 }
1185
1186 rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
1187 if (rv != SECSuccess) {
1188 goto loser;
1189 }
1190
1191
1192 /*
1193 * convert encrypted entries here.
1194 */
1195 crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey);
1196 if (crv != CKR_OK) {
1197 rv = SECFailure;
1198 goto loser;
1199 }
1200 /* fix up certdb macs */
1201 certdb = keydb->peerDB;
1202 if (certdb) {
1203 CK_ATTRIBUTE objectType = { CKA_CLASS, 0, sizeof(CK_OBJECT_CLASS) };
1204 CK_OBJECT_CLASS myClass = CKO_NETSCAPE_TRUST;
1205
1206 objectType.pValue = &myClass;
1207 crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
1208 if (crv != CKR_OK) {
1209 rv = SECFailure;
1210 goto loser;
1211 }
1212 myClass = CKO_PUBLIC_KEY;
1213 crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
1214 if (crv != CKR_OK) {
1215 rv = SECFailure;
1216 goto loser;
1217 }
1218 }
1219
1220
1221 plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
1222 plainText.len = SFTK_PW_CHECK_LEN;
1223
1224 rv = sftkdb_EncryptAttribute(NULL, &newKey, &plainText, &result);
1225 if (rv != SECSuccess) {
1226 goto loser;
1227 }
1228 value.data = result->data;
1229 value.len = result->len;
1230 crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value);
1231 if (crv != CKR_OK) {
1232 rv = SECFailure;
1233 goto loser;
1234 }
1235 crv = (*keydb->db->sdb_Commit)(keydb->db);
1236 if (crv != CKR_OK) {
1237 rv = SECFailure;
1238 goto loser;
1239 }
1240
1241 keydb->newKey = NULL;
1242
1243 sftkdb_switchKeys(keydb, &newKey);
1244
1245 loser:
1246 if (newKey.data) {
1247 PORT_ZFree(newKey.data,newKey.len);
1248 }
1249 if (result) {
1250 SECITEM_FreeItem(result, PR_FALSE);
1251 }
1252 if (rv != SECSuccess) {
1253 (*keydb->db->sdb_Abort)(keydb->db);
1254 }
1255
1256 return rv;
1257 }
1258
1259 /*
1260 * lose our cached password
1261 */
1262 SECStatus
1263 sftkdb_ClearPassword(SFTKDBHandle *keydb)
1264 {
1265 SECItem oldKey;
1266 oldKey.data = NULL;
1267 oldKey.len = 0;
1268 sftkdb_switchKeys(keydb, &oldKey);
1269 if (oldKey.data) {
1270 PORT_ZFree(oldKey.data, oldKey.len);
1271 }
1272 return SECSuccess;
1273 }
1274
1275
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)