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