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 * This file deals with PKCS #11 passwords and authentication.
6 */
7 #include "seccomon.h"
8 #include "secmod.h"
9 #include "secmodi.h"
10 #include "secmodti.h"
11 #include "pkcs11t.h"
12 #include "pk11func.h"
13 #include "secitem.h"
14 #include "secerr.h"
15
16 #include "pkim.h"
17
18 /*************************************************************
19 * local static and global data
20 *************************************************************/
21 /*
22 * This structure keeps track of status that spans all the Slots.
23 * NOTE: This is a global data structure. It semantics expect thread crosstalk
24 * be very careful when you see it used.
25 * It's major purpose in life is to allow the user to log in one PER
26 * Tranaction, even if a transaction spans threads. The problem is the user
27 * may have to enter a password one just to be able to look at the
28 * personalities/certificates (s)he can use. Then if Auth every is one, they
29 * may have to enter the password again to use the card. See PK11_StartTransac
30 * and PK11_EndTransaction.
31 */
32 static struct PK11GlobalStruct {
33 int transaction;
34 PRBool inTransaction;
35 char *(PR_CALLBACK *getPass)(PK11SlotInfo *, PRBool, void *);
36 PRBool(PR_CALLBACK *verifyPass)(PK11SlotInfo *, void *);
37 PRBool(PR_CALLBACK *isLoggedIn)(PK11SlotInfo *, void *);
38 } PK11_Global = { 1, PR_FALSE, NULL, NULL, NULL };
39
40 /***********************************************************
41 * Password Utilities
42 ***********************************************************/
43 /*
44 * Check the user's password. Log into the card if it's correct.
45 * succeed if the user is already logged in.
46 */
47 static SECStatus
pk11_CheckPassword(PK11SlotInfo * slot,CK_SESSION_HANDLE session,char * pw,PRBool alreadyLocked,PRBool contextSpecific)48 pk11_CheckPassword(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
49 char *pw, PRBool alreadyLocked, PRBool contextSpecific)
50 {
51 int len = 0;
52 CK_RV crv;
53 SECStatus rv;
54 PRTime currtime = PR_Now();
55 PRBool mustRetry;
56 int retry = 0;
57
58 if (slot->protectedAuthPath) {
59 len = 0;
60 pw = NULL;
61 } else if (pw == NULL) {
62 PORT_SetError(SEC_ERROR_INVALID_ARGS);
63 return SECFailure;
64 } else {
65 len = PORT_Strlen(pw);
66 }
67
68 do {
69 if (!alreadyLocked)
70 PK11_EnterSlotMonitor(slot);
71 crv = PK11_GETTAB(slot)->C_Login(session,
72 contextSpecific ? CKU_CONTEXT_SPECIFIC : CKU_USER,
73 (unsigned char *)pw, len);
74 slot->lastLoginCheck = 0;
75 mustRetry = PR_FALSE;
76 if (!alreadyLocked)
77 PK11_ExitSlotMonitor(slot);
78 switch (crv) {
79 /* if we're already logged in, we're good to go */
80 case CKR_OK:
81 /* TODO If it was for CKU_CONTEXT_SPECIFIC should we do this */
82 slot->authTransact = PK11_Global.transaction;
83 /* Fall through */
84 case CKR_USER_ALREADY_LOGGED_IN:
85 slot->authTime = currtime;
86 rv = SECSuccess;
87 break;
88 case CKR_PIN_INCORRECT:
89 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
90 rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
91 break;
92 /* someone called reset while we fetched the password, try again once
93 * if the token is still there. */
94 case CKR_SESSION_HANDLE_INVALID:
95 case CKR_SESSION_CLOSED:
96 if (session != slot->session) {
97 /* don't bother retrying, we were in a middle of an operation,
98 * which is now lost. Just fail. */
99 PORT_SetError(PK11_MapError(crv));
100 rv = SECFailure;
101 break;
102 }
103 if (retry++ == 0) {
104 rv = PK11_InitToken(slot, PR_FALSE);
105 if (rv == SECSuccess) {
106 if (slot->session != CK_INVALID_HANDLE) {
107 session = slot->session; /* we should have
108 * a new session now */
109 mustRetry = PR_TRUE;
110 } else {
111 PORT_SetError(PK11_MapError(crv));
112 rv = SECFailure;
113 }
114 }
115 break;
116 }
117 /* Fall through */
118 default:
119 PORT_SetError(PK11_MapError(crv));
120 rv = SECFailure; /* some failure we can't fix by retrying */
121 }
122 } while (mustRetry);
123 return rv;
124 }
125
126 /*
127 * Check the user's password. Logout before hand to make sure that
128 * we are really checking the password.
129 */
130 SECStatus
PK11_CheckUserPassword(PK11SlotInfo * slot,const char * pw)131 PK11_CheckUserPassword(PK11SlotInfo *slot, const char *pw)
132 {
133 int len = 0;
134 CK_RV crv;
135 SECStatus rv;
136 PRTime currtime = PR_Now();
137
138 if (slot->protectedAuthPath) {
139 len = 0;
140 pw = NULL;
141 } else if (pw == NULL) {
142 PORT_SetError(SEC_ERROR_INVALID_ARGS);
143 return SECFailure;
144 } else {
145 len = PORT_Strlen(pw);
146 }
147
148 /*
149 * If the token doesn't need a login, don't try to relogin because the
150 * effect is undefined. It's not clear what it means to check a non-empty
151 * password with such a token, so treat that as an error.
152 */
153 if (!slot->needLogin) {
154 if (len == 0) {
155 rv = SECSuccess;
156 } else {
157 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
158 rv = SECFailure;
159 }
160 return rv;
161 }
162
163 /* force a logout */
164 PK11_EnterSlotMonitor(slot);
165 PK11_GETTAB(slot)->C_Logout(slot->session);
166
167 crv = PK11_GETTAB(slot)->C_Login(slot->session, CKU_USER,
168 (unsigned char *)pw, len);
169 slot->lastLoginCheck = 0;
170 PK11_ExitSlotMonitor(slot);
171 switch (crv) {
172 /* if we're already logged in, we're good to go */
173 case CKR_OK:
174 slot->authTransact = PK11_Global.transaction;
175 slot->authTime = currtime;
176 rv = SECSuccess;
177 break;
178 case CKR_PIN_INCORRECT:
179 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
180 rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
181 break;
182 default:
183 PORT_SetError(PK11_MapError(crv));
184 rv = SECFailure; /* some failure we can't fix by retrying */
185 }
186 return rv;
187 }
188
189 SECStatus
PK11_Logout(PK11SlotInfo * slot)190 PK11_Logout(PK11SlotInfo *slot)
191 {
192 CK_RV crv;
193
194 /* force a logout */
195 PK11_EnterSlotMonitor(slot);
196 crv = PK11_GETTAB(slot)->C_Logout(slot->session);
197 slot->lastLoginCheck = 0;
198 PK11_ExitSlotMonitor(slot);
199 if (crv != CKR_OK) {
200 PORT_SetError(PK11_MapError(crv));
201 return SECFailure;
202 }
203 return SECSuccess;
204 }
205
206 /*
207 * transaction stuff is for when we test for the need to do every
208 * time auth to see if we already did it for this slot/transaction
209 */
210 void
PK11_StartAuthTransaction(void)211 PK11_StartAuthTransaction(void)
212 {
213 PK11_Global.transaction++;
214 PK11_Global.inTransaction = PR_TRUE;
215 }
216
217 void
PK11_EndAuthTransaction(void)218 PK11_EndAuthTransaction(void)
219 {
220 PK11_Global.transaction++;
221 PK11_Global.inTransaction = PR_FALSE;
222 }
223
224 /*
225 * before we do a private key op, we check to see if we
226 * need to reauthenticate.
227 */
228 void
PK11_HandlePasswordCheck(PK11SlotInfo * slot,void * wincx)229 PK11_HandlePasswordCheck(PK11SlotInfo *slot, void *wincx)
230 {
231 int askpw = slot->askpw;
232 PRBool NeedAuth = PR_FALSE;
233
234 if (!slot->needLogin)
235 return;
236
237 if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
238 PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
239
240 if (def_slot) {
241 askpw = def_slot->askpw;
242 PK11_FreeSlot(def_slot);
243 }
244 }
245
246 /* timeouts are handled by isLoggedIn */
247 if (!PK11_IsLoggedIn(slot, wincx)) {
248 NeedAuth = PR_TRUE;
249 } else if (askpw == -1) {
250 if (!PK11_Global.inTransaction ||
251 (PK11_Global.transaction != slot->authTransact)) {
252 PK11_EnterSlotMonitor(slot);
253 PK11_GETTAB(slot)->C_Logout(slot->session);
254 slot->lastLoginCheck = 0;
255 PK11_ExitSlotMonitor(slot);
256 NeedAuth = PR_TRUE;
257 }
258 }
259 if (NeedAuth)
260 PK11_DoPassword(slot, slot->session, PR_TRUE,
261 wincx, PR_FALSE, PR_FALSE);
262 }
263
264 void
PK11_SlotDBUpdate(PK11SlotInfo * slot)265 PK11_SlotDBUpdate(PK11SlotInfo *slot)
266 {
267 SECMOD_UpdateModule(slot->module);
268 }
269
270 /*
271 * set new askpw and timeout values
272 */
273 void
PK11_SetSlotPWValues(PK11SlotInfo * slot,int askpw,int timeout)274 PK11_SetSlotPWValues(PK11SlotInfo *slot, int askpw, int timeout)
275 {
276 slot->askpw = askpw;
277 slot->timeout = timeout;
278 slot->defaultFlags |= PK11_OWN_PW_DEFAULTS;
279 PK11_SlotDBUpdate(slot);
280 }
281
282 /*
283 * Get the askpw and timeout values for this slot
284 */
285 void
PK11_GetSlotPWValues(PK11SlotInfo * slot,int * askpw,int * timeout)286 PK11_GetSlotPWValues(PK11SlotInfo *slot, int *askpw, int *timeout)
287 {
288 *askpw = slot->askpw;
289 *timeout = slot->timeout;
290
291 if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
292 PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
293
294 if (def_slot) {
295 *askpw = def_slot->askpw;
296 *timeout = def_slot->timeout;
297 PK11_FreeSlot(def_slot);
298 }
299 }
300 }
301
302 /*
303 * Returns true if the token is needLogin and isn't logged in.
304 * This function is used to determine if authentication is needed
305 * before attempting a potentially privelleged operation.
306 */
307 PRBool
pk11_LoginStillRequired(PK11SlotInfo * slot,void * wincx)308 pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx)
309 {
310 return slot->needLogin && !PK11_IsLoggedIn(slot, wincx);
311 }
312
313 /*
314 * make sure a slot is authenticated...
315 * This function only does the authentication if it is needed.
316 */
317 SECStatus
PK11_Authenticate(PK11SlotInfo * slot,PRBool loadCerts,void * wincx)318 PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
319 {
320 if (!slot) {
321 return SECFailure;
322 }
323 if (pk11_LoginStillRequired(slot, wincx)) {
324 return PK11_DoPassword(slot, slot->session, loadCerts, wincx,
325 PR_FALSE, PR_FALSE);
326 }
327 return SECSuccess;
328 }
329
330 /*
331 * Authenticate to "unfriendly" tokens (tokens which need to be logged
332 * in to find the certs.
333 */
334 SECStatus
pk11_AuthenticateUnfriendly(PK11SlotInfo * slot,PRBool loadCerts,void * wincx)335 pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
336 {
337 SECStatus rv = SECSuccess;
338 if (!PK11_IsFriendly(slot)) {
339 rv = PK11_Authenticate(slot, loadCerts, wincx);
340 }
341 return rv;
342 }
343
344 /*
345 * NOTE: this assumes that we are logged out of the card before hand
346 */
347 SECStatus
PK11_CheckSSOPassword(PK11SlotInfo * slot,char * ssopw)348 PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw)
349 {
350 CK_SESSION_HANDLE rwsession;
351 CK_RV crv;
352 SECStatus rv = SECFailure;
353 int len = 0;
354
355 /* get a rwsession */
356 rwsession = PK11_GetRWSession(slot);
357 if (rwsession == CK_INVALID_HANDLE) {
358 PORT_SetError(SEC_ERROR_BAD_DATA);
359 return rv;
360 }
361
362 if (slot->protectedAuthPath) {
363 len = 0;
364 ssopw = NULL;
365 } else if (ssopw == NULL) {
366 PORT_SetError(SEC_ERROR_INVALID_ARGS);
367 return SECFailure;
368 } else {
369 len = PORT_Strlen(ssopw);
370 }
371
372 /* check the password */
373 crv = PK11_GETTAB(slot)->C_Login(rwsession, CKU_SO,
374 (unsigned char *)ssopw, len);
375 slot->lastLoginCheck = 0;
376 switch (crv) {
377 /* if we're already logged in, we're good to go */
378 case CKR_OK:
379 rv = SECSuccess;
380 break;
381 case CKR_PIN_INCORRECT:
382 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
383 rv = SECWouldBlock; /* everything else is ok, only the pin is bad */
384 break;
385 default:
386 PORT_SetError(PK11_MapError(crv));
387 rv = SECFailure; /* some failure we can't fix by retrying */
388 }
389 PK11_GETTAB(slot)->C_Logout(rwsession);
390 slot->lastLoginCheck = 0;
391
392 /* release rwsession */
393 PK11_RestoreROSession(slot, rwsession);
394 return rv;
395 }
396
397 /*
398 * make sure the password conforms to your token's requirements.
399 */
400 SECStatus
PK11_VerifyPW(PK11SlotInfo * slot,char * pw)401 PK11_VerifyPW(PK11SlotInfo *slot, char *pw)
402 {
403 int len = PORT_Strlen(pw);
404
405 if ((slot->minPassword > len) || (slot->maxPassword < len)) {
406 PORT_SetError(SEC_ERROR_BAD_DATA);
407 return SECFailure;
408 }
409 return SECSuccess;
410 }
411
412 /*
413 * initialize a user PIN Value
414 */
415 SECStatus
PK11_InitPin(PK11SlotInfo * slot,const char * ssopw,const char * userpw)416 PK11_InitPin(PK11SlotInfo *slot, const char *ssopw, const char *userpw)
417 {
418 CK_SESSION_HANDLE rwsession = CK_INVALID_HANDLE;
419 CK_RV crv;
420 SECStatus rv = SECFailure;
421 int len;
422 int ssolen;
423
424 if (userpw == NULL)
425 userpw = "";
426 if (ssopw == NULL)
427 ssopw = "";
428
429 len = PORT_Strlen(userpw);
430 ssolen = PORT_Strlen(ssopw);
431
432 /* get a rwsession */
433 rwsession = PK11_GetRWSession(slot);
434 if (rwsession == CK_INVALID_HANDLE) {
435 PORT_SetError(SEC_ERROR_BAD_DATA);
436 slot->lastLoginCheck = 0;
437 return rv;
438 }
439
440 if (slot->protectedAuthPath) {
441 len = 0;
442 ssolen = 0;
443 ssopw = NULL;
444 userpw = NULL;
445 }
446
447 /* check the password */
448 crv = PK11_GETTAB(slot)->C_Login(rwsession, CKU_SO,
449 (unsigned char *)ssopw, ssolen);
450 slot->lastLoginCheck = 0;
451 if (crv != CKR_OK) {
452 PORT_SetError(PK11_MapError(crv));
453 goto done;
454 }
455
456 crv = PK11_GETTAB(slot)->C_InitPIN(rwsession, (unsigned char *)userpw, len);
457 if (crv != CKR_OK) {
458 PORT_SetError(PK11_MapError(crv));
459 } else {
460 rv = SECSuccess;
461 }
462
463 done:
464 PK11_GETTAB(slot)->C_Logout(rwsession);
465 slot->lastLoginCheck = 0;
466 PK11_RestoreROSession(slot, rwsession);
467 if (rv == SECSuccess) {
468 /* update our view of the world */
469 PK11_InitToken(slot, PR_TRUE);
470 if (slot->needLogin) {
471 PK11_EnterSlotMonitor(slot);
472 PK11_GETTAB(slot)->C_Login(slot->session, CKU_USER,
473 (unsigned char *)userpw, len);
474 slot->lastLoginCheck = 0;
475 PK11_ExitSlotMonitor(slot);
476 }
477 }
478 return rv;
479 }
480
481 /*
482 * Change an existing user password
483 */
484 SECStatus
PK11_ChangePW(PK11SlotInfo * slot,const char * oldpw,const char * newpw)485 PK11_ChangePW(PK11SlotInfo *slot, const char *oldpw, const char *newpw)
486 {
487 CK_RV crv;
488 SECStatus rv = SECFailure;
489 int newLen = 0;
490 int oldLen = 0;
491 CK_SESSION_HANDLE rwsession;
492
493 /* use NULL values to trigger the protected authentication path */
494 if (!slot->protectedAuthPath) {
495 if (newpw == NULL)
496 newpw = "";
497 if (oldpw == NULL)
498 oldpw = "";
499 }
500 if (newpw)
501 newLen = PORT_Strlen(newpw);
502 if (oldpw)
503 oldLen = PORT_Strlen(oldpw);
504
505 /* get a rwsession */
506 rwsession = PK11_GetRWSession(slot);
507 if (rwsession == CK_INVALID_HANDLE) {
508 PORT_SetError(SEC_ERROR_BAD_DATA);
509 return rv;
510 }
511
512 crv = PK11_GETTAB(slot)->C_SetPIN(rwsession,
513 (unsigned char *)oldpw, oldLen, (unsigned char *)newpw, newLen);
514 if (crv == CKR_OK) {
515 rv = SECSuccess;
516 } else {
517 PORT_SetError(PK11_MapError(crv));
518 }
519
520 PK11_RestoreROSession(slot, rwsession);
521
522 /* update our view of the world */
523 PK11_InitToken(slot, PR_TRUE);
524 return rv;
525 }
526
527 static char *
pk11_GetPassword(PK11SlotInfo * slot,PRBool retry,void * wincx)528 pk11_GetPassword(PK11SlotInfo *slot, PRBool retry, void *wincx)
529 {
530 if (PK11_Global.getPass == NULL)
531 return NULL;
532 return (*PK11_Global.getPass)(slot, retry, wincx);
533 }
534
535 void
PK11_SetPasswordFunc(PK11PasswordFunc func)536 PK11_SetPasswordFunc(PK11PasswordFunc func)
537 {
538 PK11_Global.getPass = func;
539 }
540
541 void
PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func)542 PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func)
543 {
544 PK11_Global.verifyPass = func;
545 }
546
547 void
PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func)548 PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func)
549 {
550 PK11_Global.isLoggedIn = func;
551 }
552
553 /*
554 * authenticate to a slot. This loops until we can't recover, the user
555 * gives up, or we succeed. If we're already logged in and this function
556 * is called we will still prompt for a password, but we will probably
557 * succeed no matter what the password was (depending on the implementation
558 * of the PKCS 11 module.
559 */
560 SECStatus
PK11_DoPassword(PK11SlotInfo * slot,CK_SESSION_HANDLE session,PRBool loadCerts,void * wincx,PRBool alreadyLocked,PRBool contextSpecific)561 PK11_DoPassword(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
562 PRBool loadCerts, void *wincx, PRBool alreadyLocked,
563 PRBool contextSpecific)
564 {
565 SECStatus rv = SECFailure;
566 char *password;
567 PRBool attempt = PR_FALSE;
568
569 if (PK11_NeedUserInit(slot)) {
570 PORT_SetError(SEC_ERROR_IO);
571 return SECFailure;
572 }
573
574 /*
575 * Central server type applications which control access to multiple
576 * slave applications to single crypto devices need to virtuallize the
577 * login state. This is done by a callback out of PK11_IsLoggedIn and
578 * here. If we are actually logged in, then we got here because the
579 * higher level code told us that the particular client application may
580 * still need to be logged in. If that is the case, we simply tell the
581 * server code that it should now verify the clients password and tell us
582 * the results.
583 */
584 if (PK11_IsLoggedIn(slot, NULL) &&
585 (PK11_Global.verifyPass != NULL)) {
586 if (!PK11_Global.verifyPass(slot, wincx)) {
587 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
588 return SECFailure;
589 }
590 return SECSuccess;
591 }
592
593 /* get the password. This can drop out of the while loop
594 * for the following reasons:
595 * (1) the user refused to enter a password.
596 * (return error to caller)
597 * (2) the token user password is disabled [usually due to
598 * too many failed authentication attempts].
599 * (return error to caller)
600 * (3) the password was successful.
601 */
602 while ((password = pk11_GetPassword(slot, attempt, wincx)) != NULL) {
603 /* if the token has a protectedAuthPath, the application may have
604 * already issued the C_Login as part of it's pk11_GetPassword call.
605 * In this case the application will tell us what the results were in
606 * the password value (retry or the authentication was successful) so
607 * we can skip our own C_Login call (which would force the token to
608 * try to login again).
609 *
610 * Applications that don't know about protectedAuthPath will return a
611 * password, which we will ignore and trigger the token to
612 * 'authenticate' itself anyway. Hopefully the blinking display on
613 * the reader, or the flashing light under the thumbprint reader will
614 * attract the user's attention */
615 attempt = PR_TRUE;
616 if (slot->protectedAuthPath) {
617 /* application tried to authenticate and failed. it wants to try
618 * again, continue looping */
619 if (strcmp(password, PK11_PW_RETRY) == 0) {
620 rv = SECWouldBlock;
621 PORT_Free(password);
622 continue;
623 }
624 /* applicaton tried to authenticate and succeeded we're done */
625 if (strcmp(password, PK11_PW_AUTHENTICATED) == 0) {
626 rv = SECSuccess;
627 PORT_Free(password);
628 break;
629 }
630 }
631 rv = pk11_CheckPassword(slot, session, password,
632 alreadyLocked, contextSpecific);
633 PORT_Memset(password, 0, PORT_Strlen(password));
634 PORT_Free(password);
635 if (rv != SECWouldBlock)
636 break;
637 }
638 if (rv == SECSuccess) {
639 if (!contextSpecific && !PK11_IsFriendly(slot)) {
640 nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain,
641 slot->nssToken);
642 }
643 } else if (!attempt)
644 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
645 return rv;
646 }
647
648 void
PK11_LogoutAll(void)649 PK11_LogoutAll(void)
650 {
651 SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
652 SECMODModuleList *modList;
653 SECMODModuleList *mlp = NULL;
654 int i;
655
656 /* NSS is not initialized, there are not tokens to log out */
657 if (lock == NULL) {
658 return;
659 }
660
661 SECMOD_GetReadLock(lock);
662 modList = SECMOD_GetDefaultModuleList();
663 /* find the number of entries */
664 for (mlp = modList; mlp != NULL; mlp = mlp->next) {
665 for (i = 0; i < mlp->module->slotCount; i++) {
666 PK11_Logout(mlp->module->slots[i]);
667 }
668 }
669
670 SECMOD_ReleaseReadLock(lock);
671 }
672
673 int
PK11_GetMinimumPwdLength(PK11SlotInfo * slot)674 PK11_GetMinimumPwdLength(PK11SlotInfo *slot)
675 {
676 return ((int)slot->minPassword);
677 }
678
679 /* Does this slot have a protected pin path? */
680 PRBool
PK11_ProtectedAuthenticationPath(PK11SlotInfo * slot)681 PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot)
682 {
683 return slot->protectedAuthPath;
684 }
685
686 /*
687 * we can initialize the password if 1) The toke is not inited
688 * (need login == true and see need UserInit) or 2) the token has
689 * a NULL password. (slot->needLogin = false & need user Init = false).
690 */
691 PRBool
PK11_NeedPWInitForSlot(PK11SlotInfo * slot)692 PK11_NeedPWInitForSlot(PK11SlotInfo *slot)
693 {
694 if (slot->needLogin && PK11_NeedUserInit(slot)) {
695 return PR_TRUE;
696 }
697 if (!slot->needLogin && !PK11_NeedUserInit(slot)) {
698 return PR_TRUE;
699 }
700 return PR_FALSE;
701 }
702
703 PRBool
PK11_NeedPWInit()704 PK11_NeedPWInit()
705 {
706 PK11SlotInfo *slot = PK11_GetInternalKeySlot();
707 PRBool ret = PR_FALSE;
708 if (slot) {
709 ret = PK11_NeedPWInitForSlot(slot);
710 PK11_FreeSlot(slot);
711 }
712 return ret;
713 }
714
715 PRBool
pk11_InDelayPeriod(PRIntervalTime lastTime,PRIntervalTime delayTime,PRIntervalTime * retTime)716 pk11_InDelayPeriod(PRIntervalTime lastTime, PRIntervalTime delayTime,
717 PRIntervalTime *retTime)
718 {
719 PRIntervalTime time;
720
721 *retTime = time = PR_IntervalNow();
722 return (PRBool)(lastTime) && ((time - lastTime) < delayTime);
723 }
724
725 /*
726 * Determine if the token is logged in. We have to actually query the token,
727 * because it's state can change without intervention from us.
728 */
729 PRBool
PK11_IsLoggedIn(PK11SlotInfo * slot,void * wincx)730 PK11_IsLoggedIn(PK11SlotInfo *slot, void *wincx)
731 {
732 CK_SESSION_INFO sessionInfo;
733 int askpw = slot->askpw;
734 int timeout = slot->timeout;
735 CK_RV crv;
736 PRIntervalTime curTime;
737 static PRIntervalTime login_delay_time = 0;
738
739 if (login_delay_time == 0) {
740 login_delay_time = PR_SecondsToInterval(1);
741 }
742
743 /* If we don't have our own password default values, use the system
744 * ones */
745 if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) {
746 PK11SlotInfo *def_slot = PK11_GetInternalKeySlot();
747
748 if (def_slot) {
749 askpw = def_slot->askpw;
750 timeout = def_slot->timeout;
751 PK11_FreeSlot(def_slot);
752 }
753 }
754
755 if ((wincx != NULL) && (PK11_Global.isLoggedIn != NULL) &&
756 (*PK11_Global.isLoggedIn)(slot, wincx) == PR_FALSE) {
757 return PR_FALSE;
758 }
759
760 /* forget the password if we've been inactive too long */
761 if (askpw == 1) {
762 PRTime currtime = PR_Now();
763 PRTime result;
764 PRTime mult;
765
766 LL_I2L(result, timeout);
767 LL_I2L(mult, 60 * 1000 * 1000);
768 LL_MUL(result, result, mult);
769 LL_ADD(result, result, slot->authTime);
770 if (LL_CMP(result, <, currtime)) {
771 PK11_EnterSlotMonitor(slot);
772 PK11_GETTAB(slot)->C_Logout(slot->session);
773 slot->lastLoginCheck = 0;
774 PK11_ExitSlotMonitor(slot);
775 } else {
776 slot->authTime = currtime;
777 }
778 }
779
780 PK11_EnterSlotMonitor(slot);
781 if (pk11_InDelayPeriod(slot->lastLoginCheck, login_delay_time, &curTime)) {
782 sessionInfo.state = slot->lastState;
783 crv = CKR_OK;
784 } else {
785 crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
786 if (crv == CKR_OK) {
787 slot->lastState = sessionInfo.state;
788 slot->lastLoginCheck = curTime;
789 }
790 }
791 PK11_ExitSlotMonitor(slot);
792 /* if we can't get session info, something is really wrong */
793 if (crv != CKR_OK) {
794 slot->session = CK_INVALID_HANDLE;
795 return PR_FALSE;
796 }
797
798 switch (sessionInfo.state) {
799 case CKS_RW_PUBLIC_SESSION:
800 case CKS_RO_PUBLIC_SESSION:
801 default:
802 break; /* fail */
803 case CKS_RW_USER_FUNCTIONS:
804 case CKS_RW_SO_FUNCTIONS:
805 case CKS_RO_USER_FUNCTIONS:
806 return PR_TRUE;
807 }
808 return PR_FALSE;
809 }
810