Changes On Branch 5f8f3e59a7e878f2

Changes In Branch protected-auth-path Through [5f8f3e59a7] Excluding Merge-Ins

This is equivalent to a diff from 2e1e0bfc20 to 5f8f3e59a7

2014-01-17
13:42
Merged in trunk check-in: b5af3ab373 user: rkeene tags: protected-auth-path
2013-10-17
20:29
Updated to deal with 6E00 and added support for win32 build options check-in: 6ba1dff55a user: rkeene tags: piv
2013-09-14
04:11
Merged in changes from piv check-in: 5f8f3e59a7 user: rkeene tags: protected-auth-path
02:50
Updated to treat a return code of 0x6E00 (wrong instruction class) the same as 0x6982 (security status not satisified) check-in: 2e1e0bfc20 user: rkeene tags: piv
2013-08-19
03:33
Updated to exclude USG certificates slot if compiled without it check-in: eba8a2346a user: rkeene tags: piv
2013-08-14
06:29
Updated to not dead-lock when prompting for PIN during a signing operation check-in: 27d18fd03a user: rkeene tags: protected-auth-path

Modified cackey.c from [c06e51ee9b] to [5ad2713a20].

1113
1114
1115
1116
1117
1118
1119

1120



1121
1122
1123
1124
1125
1126
1127

	if (slot->pcsc_card_connected) {
		SCardDisconnect(slot->pcsc_card, SCARD_LEAVE_CARD);
	}

	slot->slot_reset = 1;
	slot->pcsc_card_connected = 0;

	slot->token_flags = CKF_LOGIN_REQUIRED;




	CACKEY_DEBUG_PRINTF("Returning.");

	return;
}

/*







>
|
>
>
>







1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131

	if (slot->pcsc_card_connected) {
		SCardDisconnect(slot->pcsc_card, SCARD_LEAVE_CARD);
	}

	slot->slot_reset = 1;
	slot->pcsc_card_connected = 0;
	if (cackey_pin_command == NULL) {
		slot->token_flags = CKF_LOGIN_REQUIRED;
	} else {
		slot->token_flags = 0;
	}

	CACKEY_DEBUG_PRINTF("Returning.");

	return;
}

/*
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
			/* End transaction */
			cackey_end_transaction(slot);

			if (respcode == 0x6982 || respcode == 0x6e00) {
				CACKEY_DEBUG_PRINTF("Security status not satisified (respcode = 0x%04x).  Returning NEEDLOGIN", (int) respcode);

				cackey_mark_slot_reset(slot);
				slot->token_flags = CKF_LOGIN_REQUIRED;

				return(CACKEY_PCSC_E_NEEDLOGIN);
			}

			if (send_ret == CACKEY_PCSC_E_TOKENABSENT) {
				CACKEY_DEBUG_PRINTF("Token absent.  Returning TOKENABSENT");








<







2872
2873
2874
2875
2876
2877
2878

2879
2880
2881
2882
2883
2884
2885
			/* End transaction */
			cackey_end_transaction(slot);

			if (respcode == 0x6982 || respcode == 0x6e00) {
				CACKEY_DEBUG_PRINTF("Security status not satisified (respcode = 0x%04x).  Returning NEEDLOGIN", (int) respcode);

				cackey_mark_slot_reset(slot);


				return(CACKEY_PCSC_E_NEEDLOGIN);
			}

			if (send_ret == CACKEY_PCSC_E_TOKENABSENT) {
				CACKEY_DEBUG_PRINTF("Token absent.  Returning TOKENABSENT");

4432
4433
4434
4435
4436
4437
4438

4439



4440
4441
4442
4443
4444
4445
4446
						if (slot_reset) {
							cackey_slots[currslot].active = 1;
							cackey_slots[currslot].internal = 0;
							cackey_slots[currslot].pcsc_reader = strdup(pcsc_readers);
							cackey_slots[currslot].pcsc_card_connected = 0;
							cackey_slots[currslot].transaction_depth = 0;
							cackey_slots[currslot].transaction_need_hw_lock = 0;

							cackey_slots[currslot].token_flags = CKF_LOGIN_REQUIRED;



							cackey_slots[currslot].label = NULL;

							cackey_mark_slot_reset(&cackey_slots[currslot]);
						}
					} else {
						/* Artificially increase the number of active slots by what will become active */
						slot_count++;







>
|
>
>
>







4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
						if (slot_reset) {
							cackey_slots[currslot].active = 1;
							cackey_slots[currslot].internal = 0;
							cackey_slots[currslot].pcsc_reader = strdup(pcsc_readers);
							cackey_slots[currslot].pcsc_card_connected = 0;
							cackey_slots[currslot].transaction_depth = 0;
							cackey_slots[currslot].transaction_need_hw_lock = 0;
							if (cackey_pin_command == NULL) {
								cackey_slots[currslot].token_flags = CKF_LOGIN_REQUIRED;
							} else {
								cackey_slots[currslot].token_flags = 0;
							}
							cackey_slots[currslot].label = NULL;

							cackey_mark_slot_reset(&cackey_slots[currslot]);
						}
					} else {
						/* Artificially increase the number of active slots by what will become active */
						slot_count++;
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
	}

	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);

	return(CKR_FUNCTION_NOT_SUPPORTED);
}

CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) {
	CK_SLOT_ID slotID;
	FILE *pinfd;
	char *pincmd, pinbuf[64], *fgets_ret;
	int mutex_retval;
	int tries_remaining;
	int login_ret;
	int pclose_ret;







|







5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
	}

	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);

	return(CKR_FUNCTION_NOT_SUPPORTED);
}

CK_DEFINE_FUNCTION(CK_RV, _C_LoginMutexArg)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, int lock_mutex) {
	CK_SLOT_ID slotID;
	FILE *pinfd;
	char *pincmd, pinbuf[64], *fgets_ret;
	int mutex_retval;
	int tries_remaining;
	int login_ret;
	int pclose_ret;
5206
5207
5208
5209
5210
5211
5212

5213
5214
5215
5216
5217

5218
5219
5220

5221

5222
5223
5224
5225
5226
5227
5228
5229
5230
5231




5232
5233
5234
5235
5236
5237
5238

5239

5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255

5256

5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271

5272

5273
5274
5275
5276
5277
5278
5279
5280
5281

5282

5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298

5299

5300
5301
5302
5303
5304
5305
5306

	if (userType != CKU_USER) {
		CACKEY_DEBUG_PRINTF("Error.  We only support USER mode, asked for %lu mode.", (unsigned long) userType)

		return(CKR_USER_TYPE_INVALID);
	}


	mutex_retval = cackey_mutex_lock(cackey_biglock);
	if (mutex_retval != 0) {
		CACKEY_DEBUG_PRINTF("Error.  Locking failed.");

		return(CKR_GENERAL_ERROR);

	}

	if (!cackey_sessions[hSession].active) {

		cackey_mutex_unlock(cackey_biglock);


		CACKEY_DEBUG_PRINTF("Error.  Session not active.");
		
		return(CKR_SESSION_HANDLE_INVALID);
	}

	slotID = cackey_sessions[hSession].slotID;

	if (slotID < 0 || slotID >= (sizeof(cackey_slots) / sizeof(cackey_slots[0]))) {
		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), outside of valid range", slotID);





		return(CKR_GENERAL_ERROR);
	}

	if (cackey_slots[slotID].active == 0) {
		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID);


		cackey_mutex_unlock(cackey_biglock);


		return(CKR_GENERAL_ERROR);
	}

	pincmd = cackey_pin_command;
	if (pincmd != NULL) {
		CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd);

		if (pPin != NULL) {
			CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?");
		}

		pinfd = popen(pincmd, "r");
		if (pinfd == NULL) {
			CACKEY_DEBUG_PRINTF("Error.  %s: Unable to run", pincmd);


			cackey_mutex_unlock(cackey_biglock);


			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd);
		if (fgets_ret == NULL) {
			pinbuf[0] = '\0';
		}

		pclose_ret = pclose(pinfd);
		if (pclose_ret != 0) {
			CACKEY_DEBUG_PRINTF("Error.  %s: exited with non-zero status of %i", pincmd, pclose_ret);


			cackey_mutex_unlock(cackey_biglock);


			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		if (strlen(pinbuf) < 1) {
			CACKEY_DEBUG_PRINTF("Error.  %s: returned no data", pincmd);


			cackey_mutex_unlock(cackey_biglock);


			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		if (pinbuf[strlen(pinbuf) - 1] == '\n') {
			pinbuf[strlen(pinbuf) - 1] = '\0';
		}

		pPin = (CK_UTF8CHAR_PTR) pinbuf;
		ulPinLen = strlen(pinbuf);
	}

	login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining);
	if (login_ret != CACKEY_PCSC_S_OK) {

		cackey_mutex_unlock(cackey_biglock);


		if (login_ret == CACKEY_PCSC_E_LOCKED) {
			CACKEY_DEBUG_PRINTF("Error.  Token is locked.");

			cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED;

			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_LOCKED (%i)", (int) CKR_PIN_LOCKED);







>
|
|
|

|
>



>
|
>










>
>
>
>







>
|
>
















>
|
>















>
|
>









>
|
>
















>
|
>







5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331

	if (userType != CKU_USER) {
		CACKEY_DEBUG_PRINTF("Error.  We only support USER mode, asked for %lu mode.", (unsigned long) userType)

		return(CKR_USER_TYPE_INVALID);
	}

	if (lock_mutex) {
		mutex_retval = cackey_mutex_lock(cackey_biglock);
		if (mutex_retval != 0) {
			CACKEY_DEBUG_PRINTF("Error.  Locking failed.");

			return(CKR_GENERAL_ERROR);
		}
	}

	if (!cackey_sessions[hSession].active) {
		if (lock_mutex) {
			cackey_mutex_unlock(cackey_biglock);
		}

		CACKEY_DEBUG_PRINTF("Error.  Session not active.");
		
		return(CKR_SESSION_HANDLE_INVALID);
	}

	slotID = cackey_sessions[hSession].slotID;

	if (slotID < 0 || slotID >= (sizeof(cackey_slots) / sizeof(cackey_slots[0]))) {
		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), outside of valid range", slotID);

		if (lock_mutex) {
			cackey_mutex_unlock(cackey_biglock);
		}

		return(CKR_GENERAL_ERROR);
	}

	if (cackey_slots[slotID].active == 0) {
		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID);

		if (lock_mutex) {
			cackey_mutex_unlock(cackey_biglock);
		}

		return(CKR_GENERAL_ERROR);
	}

	pincmd = cackey_pin_command;
	if (pincmd != NULL) {
		CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd);

		if (pPin != NULL) {
			CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?");
		}

		pinfd = popen(pincmd, "r");
		if (pinfd == NULL) {
			CACKEY_DEBUG_PRINTF("Error.  %s: Unable to run", pincmd);

			if (lock_mutex) {
				cackey_mutex_unlock(cackey_biglock);
			}

			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd);
		if (fgets_ret == NULL) {
			pinbuf[0] = '\0';
		}

		pclose_ret = pclose(pinfd);
		if (pclose_ret != 0) {
			CACKEY_DEBUG_PRINTF("Error.  %s: exited with non-zero status of %i", pincmd, pclose_ret);

			if (lock_mutex) {
				cackey_mutex_unlock(cackey_biglock);
			}

			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		if (strlen(pinbuf) < 1) {
			CACKEY_DEBUG_PRINTF("Error.  %s: returned no data", pincmd);

			if (lock_mutex) {
				cackey_mutex_unlock(cackey_biglock);
			}

			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		if (pinbuf[strlen(pinbuf) - 1] == '\n') {
			pinbuf[strlen(pinbuf) - 1] = '\0';
		}

		pPin = (CK_UTF8CHAR_PTR) pinbuf;
		ulPinLen = strlen(pinbuf);
	}

	login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining);
	if (login_ret != CACKEY_PCSC_S_OK) {
		if (lock_mutex) {
			cackey_mutex_unlock(cackey_biglock);
		}

		if (login_ret == CACKEY_PCSC_E_LOCKED) {
			CACKEY_DEBUG_PRINTF("Error.  Token is locked.");

			cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED;

			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_LOCKED (%i)", (int) CKR_PIN_LOCKED);
5325
5326
5327
5328
5329
5330
5331

5332
5333
5334
5335
5336

5337
5338
5339
5340
5341
5342




5343
5344
5345
5346
5347
5348
5349
		return(CKR_GENERAL_ERROR);
	}

	cackey_slots[slotID].token_flags &= ~(CKF_USER_PIN_LOCKED | CKF_USER_PIN_COUNT_LOW | CKF_LOGIN_REQUIRED | CKF_USER_PIN_FINAL_TRY);

	cackey_sessions[hSession].state = CKS_RO_USER_FUNCTIONS;


	mutex_retval = cackey_mutex_unlock(cackey_biglock);
	if (mutex_retval != 0) {
		CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");

		return(CKR_GENERAL_ERROR);

	}

	CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK);

	return(CKR_OK);
}





CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) {
	CK_SLOT_ID slotID;
	int mutex_retval;

	CACKEY_DEBUG_PRINTF("Called.");








>
|
|
|

|
>






>
>
>
>







5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
		return(CKR_GENERAL_ERROR);
	}

	cackey_slots[slotID].token_flags &= ~(CKF_USER_PIN_LOCKED | CKF_USER_PIN_COUNT_LOW | CKF_LOGIN_REQUIRED | CKF_USER_PIN_FINAL_TRY);

	cackey_sessions[hSession].state = CKS_RO_USER_FUNCTIONS;

	if (lock_mutex) {
		mutex_retval = cackey_mutex_unlock(cackey_biglock);
		if (mutex_retval != 0) {
			CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");

			return(CKR_GENERAL_ERROR);
		}
	}

	CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK);

	return(CKR_OK);
}

CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) {
	return(_C_LoginMutexArg(hSession, userType, pPin, ulPinLen, 1));
}

CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) {
	CK_SLOT_ID slotID;
	int mutex_retval;

	CACKEY_DEBUG_PRINTF("Called.");

5387
5388
5389
5390
5391
5392
5393


5394



5395
5396
5397
5398
5399
5400
5401

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_GENERAL_ERROR);
	}

	cackey_sessions[hSession].state = CKS_RO_PUBLIC_SESSION;


	cackey_slots[slotID].token_flags = CKF_LOGIN_REQUIRED;




	mutex_retval = cackey_mutex_unlock(cackey_biglock);
	if (mutex_retval != 0) {
		CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");

		return(CKR_GENERAL_ERROR);
	}







>
>
|
>
>
>







5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_GENERAL_ERROR);
	}

	cackey_sessions[hSession].state = CKS_RO_PUBLIC_SESSION;

	if (cackey_pin_command == NULL) {
		cackey_slots[slotID].token_flags = CKF_LOGIN_REQUIRED;
	} else {
		cackey_slots[slotID].token_flags = 0;
	}

	mutex_retval = cackey_mutex_unlock(cackey_biglock);
	if (mutex_retval != 0) {
		CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");

		return(CKR_GENERAL_ERROR);
	}
6311
6312
6313
6314
6315
6316
6317






6318
6319
6320
6321
6322
6323
6324
		return(CKR_GENERAL_ERROR);
	}

	switch (cackey_sessions[hSession].decrypt_mechanism) {
		case CKM_RSA_PKCS:
			/* Ask card to decrypt */
			buflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].decrypt_identity, pEncryptedPart, ulEncryptedPartLen, buf, sizeof(buf), 0, 1);







			if (buflen < 0) {
				/* Decryption failed. */
				if (buflen == CACKEY_PCSC_E_NEEDLOGIN) {
					retval = CKR_USER_NOT_LOGGED_IN;
				} else if (buflen == CACKEY_PCSC_E_TOKENABSENT) {
					retval = CKR_DEVICE_REMOVED;







>
>
>
>
>
>







6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
		return(CKR_GENERAL_ERROR);
	}

	switch (cackey_sessions[hSession].decrypt_mechanism) {
		case CKM_RSA_PKCS:
			/* Ask card to decrypt */
			buflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].decrypt_identity, pEncryptedPart, ulEncryptedPartLen, buf, sizeof(buf), 0, 1);

			if (buflen == CACKEY_PCSC_E_NEEDLOGIN && cackey_pin_command != NULL) {
				if (_C_LoginMutexArg(hSession, CKU_USER, NULL, 0, 0) == CKR_OK) {
					buflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].decrypt_identity, pEncryptedPart, ulEncryptedPartLen, buf, sizeof(buf), 0, 1);
				}
			}

			if (buflen < 0) {
				/* Decryption failed. */
				if (buflen == CACKEY_PCSC_E_NEEDLOGIN) {
					retval = CKR_USER_NOT_LOGGED_IN;
				} else if (buflen == CACKEY_PCSC_E_TOKENABSENT) {
					retval = CKR_DEVICE_REMOVED;
6822
6823
6824
6825
6826
6827
6828






6829
6830
6831
6832
6833
6834
6835
	}

	switch (cackey_sessions[hSession].sign_mechanism) {
		case CKM_RSA_PKCS:
			/* Ask card to sign */
			CACKEY_DEBUG_PRINTF("Asking to sign from identity %p in session %lu", (void *) cackey_sessions[hSession].sign_identity, (unsigned long) hSession);
			sigbuflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].sign_identity, cackey_sessions[hSession].sign_buf, cackey_sessions[hSession].sign_bufused, sigbuf, sizeof(sigbuf), 1, 0);







			if (sigbuflen < 0) {
				/* Signing failed. */
				if (sigbuflen == CACKEY_PCSC_E_NEEDLOGIN) {
					retval = CKR_USER_NOT_LOGGED_IN;
				} else if (sigbuflen == CACKEY_PCSC_E_TOKENABSENT) {
					retval = CKR_DEVICE_REMOVED;







>
>
>
>
>
>







6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
6877
6878
6879
6880
6881
6882
6883
	}

	switch (cackey_sessions[hSession].sign_mechanism) {
		case CKM_RSA_PKCS:
			/* Ask card to sign */
			CACKEY_DEBUG_PRINTF("Asking to sign from identity %p in session %lu", (void *) cackey_sessions[hSession].sign_identity, (unsigned long) hSession);
			sigbuflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].sign_identity, cackey_sessions[hSession].sign_buf, cackey_sessions[hSession].sign_bufused, sigbuf, sizeof(sigbuf), 1, 0);

			if (sigbuflen == CACKEY_PCSC_E_NEEDLOGIN && cackey_pin_command != NULL) {
				if (_C_LoginMutexArg(hSession, CKU_USER, NULL, 0, 0) == CKR_OK) {
					sigbuflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].sign_identity, cackey_sessions[hSession].sign_buf, cackey_sessions[hSession].sign_bufused, sigbuf, sizeof(sigbuf), 1, 0);
				}
			}

			if (sigbuflen < 0) {
				/* Signing failed. */
				if (sigbuflen == CACKEY_PCSC_E_NEEDLOGIN) {
					retval = CKR_USER_NOT_LOGGED_IN;
				} else if (sigbuflen == CACKEY_PCSC_E_TOKENABSENT) {
					retval = CKR_DEVICE_REMOVED;