Check-in [b5ecb7c2d6]
Overview
Comment:Added support for updating the PIN
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b5ecb7c2d6bcf1626969f443a67d31f5b7b6ed4e
User & Date: rkeene on 2015-07-15 20:05:35
Other Links: manifest | tags
Context
2015-07-16
16:18
Updated to retry login if it fails with a 6D 00 (wrong instruction) check-in: 4e30511f94 user: rkeene tags: trunk
16:06
Reset the card and rescan for certificates if we get the ISO 7816 error 6D 00 (Wrong instruction) error from the card when trying to verify. Closed-Leaf check-in: 52569c3e74 user: rkeene tags: piv-reset-on-wronginstruction
2015-07-15
20:10
Merged in trunk Leaf check-in: 38771da1e8 user: rkeene tags: require-login-if-needed
20:08
Merged in trunk Closed-Leaf check-in: bab332232a user: rkeene tags: protected-auth-path
20:05
Added support for updating the PIN check-in: b5ecb7c2d6 user: rkeene tags: trunk
18:47
Updated KPS CA Certs check-in: efe7692225 user: rkeene tags: trunk
Changes

Modified cackey.c from [65139610e9] to [3a0d4abad4].

81
82
83
84
85
86
87

88
89
90
91
92
93
94
....
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
....
3137
3138
3139
3140
3141
3142
3143

































































































3144
3145
3146
3147
3148
3149
3150
....
4170
4171
4172
4173
4174
4175
4176





















































4177
4178
4179
4180
4181
4182
4183
....
4987
4988
4989
4990
4991
4992
4993
4994
4995





4996
4997
4998
4999
5000
5001
5002
5003
5004



5005


















































































































5006















5007
5008
5009
5010
5011
5012
5013
....
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
....
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
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
#define GSCIS_INSTR_READ_BINARY       0xB0
#define GSCIS_INSTR_UPDATE_BINARY     0xD6
#define GSCIS_INSTR_SELECT            0xA4
#define GSCIS_INSTR_EXTERNAL_AUTH     0x82
#define GSCIS_INSTR_GET_CHALLENGE     0x84
#define GSCIS_INSTR_INTERNAL_AUTH     0x88
#define GSCIS_INSTR_VERIFY            0x20

#define GSCIS_INSTR_SIGN              0x2A
#define GSCIS_INSTR_GET_PROP          0x56
#define GSCIS_INSTR_GET_ACR           0x4C
#define GSCIS_INSTR_READ_BUFFER       0x52
#define GSCIS_INSTR_SIGNDECRYPT       0x42

#define GSCIS_PARAM_SELECT_APPLET     0x04
................................................................................
			xmit_buf[xmit_len++] = le;
		}
	}

	/* Begin Smartcard Transaction */
	cackey_begin_transaction(slot);

	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00) {
		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
	} else {
		CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);
	}

	recv_len = sizeof(recv_buf);
	scard_xmit_ret = SCardTransmit(slot->pcsc_card, pioSendPci, xmit_buf, xmit_len, NULL, recv_buf, &recv_len);
................................................................................
 *
 * RETURN VALUE
 *     ...
 *
 * NOTES
 *     ...
 *

































































































 */
static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) {
	struct cackey_pcsc_identity *pcsc_identities;
	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	unsigned long num_certs;
	uint16_t response_code;
	int tries_remaining;
................................................................................
		return(identities);
	}


	*ids_found = 0;
	return(NULL);
}






















































CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) {
	CK_C_INITIALIZE_ARGS CK_PTR args;
	uint32_t idx, highest_slot;
	int mutex_init_ret;
	int include_dod_certs;

................................................................................
	}

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

	return(CKR_TOKEN_WRITE_PROTECTED);
}

/* We don't support this method. */
CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewPinLen) {





	CACKEY_DEBUG_PRINTF("Called.");

	if (!cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");

		return(CKR_CRYPTOKI_NOT_INITIALIZED);
	}

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






















































































































	return(CKR_FUNCTION_NOT_SUPPORTED);















}

CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession) {
	unsigned long idx;
	int mutex_retval;
	int found_session = 0;

................................................................................
	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;

	CACKEY_DEBUG_PRINTF("Called.");

	if (!cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");

		return(CKR_CRYPTOKI_NOT_INITIALIZED);
................................................................................
		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 == -1 && errno == ECHILD) {
			CACKEY_DEBUG_PRINTF("Notice.  pclose() indicated it could not get the status of the child, assuming it succeeeded !");

			pclose_ret = 0;
		}

		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) {







>







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<

>
>
>
>
>








<
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|



<







 







|
<
<
<




|
<
>
|
>





<
<



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
....
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
....
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
....
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
....
5138
5139
5140
5141
5142
5143
5144

5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158

5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
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
....
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584

5585
5586
5587
5588
5589
5590
5591
....
5640
5641
5642
5643
5644
5645
5646
5647



5648
5649
5650
5651
5652

5653
5654
5655
5656
5657
5658
5659
5660


5661
5662
5663








































5664
5665
5666
5667
5668
5669
5670
#define GSCIS_INSTR_READ_BINARY       0xB0
#define GSCIS_INSTR_UPDATE_BINARY     0xD6
#define GSCIS_INSTR_SELECT            0xA4
#define GSCIS_INSTR_EXTERNAL_AUTH     0x82
#define GSCIS_INSTR_GET_CHALLENGE     0x84
#define GSCIS_INSTR_INTERNAL_AUTH     0x88
#define GSCIS_INSTR_VERIFY            0x20
#define GSCIS_INSTR_CHANGE_REFERENCE  0x24
#define GSCIS_INSTR_SIGN              0x2A
#define GSCIS_INSTR_GET_PROP          0x56
#define GSCIS_INSTR_GET_ACR           0x4C
#define GSCIS_INSTR_READ_BUFFER       0x52
#define GSCIS_INSTR_SIGNDECRYPT       0x42

#define GSCIS_PARAM_SELECT_APPLET     0x04
................................................................................
			xmit_buf[xmit_len++] = le;
		}
	}

	/* Begin Smartcard Transaction */
	cackey_begin_transaction(slot);

	if (class == GSCIS_CLASS_ISO7816 && (instruction == GSCIS_INSTR_VERIFY || instruction == GSCIS_INSTR_CHANGE_REFERENCE) && p1 == 0x00) {
		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
	} else {
		CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);
	}

	recv_len = sizeof(recv_buf);
	scard_xmit_ret = SCardTransmit(slot->pcsc_card, pioSendPci, xmit_buf, xmit_len, NULL, recv_buf, &recv_len);
................................................................................
 *
 * RETURN VALUE
 *     ...
 *
 * NOTES
 *     ...
 *
 */
static cackey_ret cackey_set_pin(struct cackey_slot *slot, unsigned char *old_pin, unsigned long old_pin_len, unsigned char *pin, unsigned long pin_len) {
	struct cackey_pcsc_identity *pcsc_identities;
	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	unsigned char old_cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	unsigned char pin_update[sizeof(cac_pin) + sizeof(old_cac_pin)];
	unsigned long num_certs;
	uint16_t response_code;
	int tries_remaining;
	int send_ret;
	int key_reference = 0x00;

	/* Apparently, CAC PINs are *EXACTLY* 8 bytes long -- pad with 0xFF if too short */
	if (pin_len >= 8) {
		memcpy(cac_pin, pin, 8);
	} else {
		memcpy(cac_pin, pin, pin_len);
	}

	if (old_pin_len >= 8) {
		memcpy(old_cac_pin, old_pin, 8);
	} else {
		memcpy(old_cac_pin, old_pin, old_pin_len);
	}

	/* Concatenate both PINs together to send as a single instruction */
	memcpy(pin_update, old_cac_pin, sizeof(old_cac_pin));
	memcpy(pin_update + sizeof(old_cac_pin), cac_pin, sizeof(cac_pin));

	/* Reject PINs which are too short */
	if (pin_len < 5) {
		CACKEY_DEBUG_PRINTF("Rejecting New PIN which is too short (length = %lu, must be atleast 5)", pin_len);

		return(CACKEY_PCSC_E_BADPIN);
	}

	if (old_pin_len < 5) {
		CACKEY_DEBUG_PRINTF("Rejecting Old PIN which is too short (length = %lu, must be atleast 5)", old_pin_len);

		return(CACKEY_PCSC_E_BADPIN);
	}

	/* PIV authentication uses a "key_reference" of 0x80 */
	pcsc_identities = cackey_read_certs(slot, NULL, &num_certs);
	if (num_certs > 0 && pcsc_identities != NULL) {
		switch (pcsc_identities[0].id_type) {
			case CACKEY_ID_TYPE_PIV:
				CACKEY_DEBUG_PRINTF("We have PIV card, so we will attempt to authenticate using the PIV Application key reference");

				key_reference = 0x80;
				break;
			default:
				break;
		}

		cackey_free_certs(pcsc_identities, num_certs, 1);
	}

	/* Issue a Set PIN (CHANGE REFERENCE) */
	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_CHANGE_REFERENCE, 0x00, key_reference, sizeof(pin_update), pin_update, 0x00, &response_code, NULL, NULL);

	if (send_ret != CACKEY_PCSC_S_OK) {
		if ((response_code & 0x63C0) == 0x63C0) {
			tries_remaining = (response_code & 0xF);

			CACKEY_DEBUG_PRINTF("PIN Verification failed, %i tries remaining", tries_remaining);

			return(CACKEY_PCSC_E_BADPIN);
		}

		if (response_code == 0x6983) {
			CACKEY_DEBUG_PRINTF("Unable to set PIN, device is locked or changing the PIN is disabled");

			return(CACKEY_PCSC_E_LOCKED);
		}

		return(CACKEY_PCSC_E_GENERIC);
	}

	CACKEY_DEBUG_PRINTF("PIN Change succeeded");

	return(CACKEY_PCSC_S_OK);
}

/*
 * SYNPOSIS
 *     ...
 *
 * ARGUMENTS
 *     ...
 *
 * RETURN VALUE
 *     ...
 *
 * NOTES
 *     ...
 *
 */
static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) {
	struct cackey_pcsc_identity *pcsc_identities;
	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	unsigned long num_certs;
	uint16_t response_code;
	int tries_remaining;
................................................................................
		return(identities);
	}


	*ids_found = 0;
	return(NULL);
}

static cackey_ret cackey_get_pin(char *pinbuf) {
	FILE *pinfd;
	char *fgets_ret;
	int pclose_ret;

	if (cackey_pin_command == NULL) {
		return(CACKEY_PCSC_E_GENERIC);
	}

	if (pinbuf == NULL) {
		return(CACKEY_PCSC_E_GENERIC);
	}

	CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", cackey_pin_command);

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

		return(CACKEY_PCSC_E_BADPIN);
	}

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

	pclose_ret = pclose(pinfd);
	if (pclose_ret == -1 && errno == ECHILD) {
		CACKEY_DEBUG_PRINTF("Notice.  pclose() indicated it could not get the status of the child, assuming it succeeeded !");

		pclose_ret = 0;
	}

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

		return(CACKEY_PCSC_E_BADPIN);
	}

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

		return(CACKEY_PCSC_E_BADPIN);
	}

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

	return(CACKEY_PCSC_S_OK);
}

CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) {
	CK_C_INITIALIZE_ARGS CK_PTR args;
	uint32_t idx, highest_slot;
	int mutex_init_ret;
	int include_dod_certs;

................................................................................
	}

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

	return(CKR_TOKEN_WRITE_PROTECTED);
}


CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewPinLen) {
	char oldpinbuf[64], newpinbuf[64];
	cackey_ret set_pin_ret, get_pin_ret;
	CK_SLOT_ID slotID;
	int mutex_retval;

	CACKEY_DEBUG_PRINTF("Called.");

	if (!cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");

		return(CKR_CRYPTOKI_NOT_INITIALIZED);
	}


	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);

		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);

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_GENERAL_ERROR);
	}

	if (cackey_pin_command != NULL) {
		/* Get old PIN */
		get_pin_ret = cackey_get_pin(oldpinbuf);

		if (get_pin_ret != CACKEY_PCSC_S_OK) {
			CACKEY_DEBUG_PRINTF("Error while getting Old PIN, returning CKR_PIN_INCORRECT.");

			cackey_mutex_unlock(cackey_biglock);
			
			return(CKR_PIN_INCORRECT);
		}

		pOldPin = (CK_UTF8CHAR_PTR) oldpinbuf;
		ulOldPinLen = strlen(oldpinbuf);

		/* Get new PIN */
		get_pin_ret = cackey_get_pin(newpinbuf);

		if (get_pin_ret != CACKEY_PCSC_S_OK) {
			CACKEY_DEBUG_PRINTF("Error while getting New PIN, returning CKR_PIN_INVALID.");

			cackey_mutex_unlock(cackey_biglock);
			
			return(CKR_PIN_INVALID);
		}

		pNewPin = (CK_UTF8CHAR_PTR) newpinbuf;
		ulNewPinLen = strlen(newpinbuf);
	}

	if (pOldPin == NULL) {
		CACKEY_DEBUG_PRINTF("Old PIN value is wrong (null).");

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_PIN_INCORRECT);
	}

	if (ulOldPinLen == 0 || ulOldPinLen > 8) {
		CACKEY_DEBUG_PRINTF("Old PIN length is wrong: %lu.", (unsigned long) ulOldPinLen);

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_PIN_INCORRECT);
	}

	if (pNewPin == NULL) {
		CACKEY_DEBUG_PRINTF("New PIN value is wrong (either NULL, or too long/short).");

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_PIN_INVALID);
	}

	if (ulNewPinLen < 5 || ulNewPinLen > 8) {
		CACKEY_DEBUG_PRINTF("New PIN length is wrong: %lu, must be atleast 5 and no more than 8.", (unsigned long) ulNewPinLen);

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_PIN_LEN_RANGE);
	}

	set_pin_ret = cackey_set_pin(&cackey_slots[slotID], pOldPin, ulOldPinLen, pNewPin, ulNewPinLen);

	if (set_pin_ret != CACKEY_PCSC_S_OK) {
		if (cackey_pin_command == NULL) {
			cackey_slots[slotID].token_flags |= CKF_LOGIN_REQUIRED;
		}

		if (set_pin_ret == CACKEY_PCSC_E_LOCKED) {
			cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED;
		}
	}

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

		return(CKR_GENERAL_ERROR);
	}

	switch (set_pin_ret) {
		case CACKEY_PCSC_S_OK:
			CACKEY_DEBUG_PRINTF("Successfully set PIN.");

			return(CKR_OK);
		case CACKEY_PCSC_E_BADPIN:
			CACKEY_DEBUG_PRINTF("PIN was invalid.");

			return(CKR_PIN_INVALID);
		case CACKEY_PCSC_E_LOCKED:
			CACKEY_DEBUG_PRINTF("Token is locked or this change is not permitted.");

			return(CKR_PIN_LOCKED);
		default:
			CACKEY_DEBUG_PRINTF("Something else went wrong changing the PIN: %i", set_pin_ret);

			return(CKR_GENERAL_ERROR);
	}

	return(CKR_GENERAL_ERROR);
}

CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession) {
	unsigned long idx;
	int mutex_retval;
	int found_session = 0;

................................................................................
	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;
	cackey_ret get_pin_ret;
	char pinbuf[64];
	int mutex_retval;
	int tries_remaining;
	int login_ret;


	CACKEY_DEBUG_PRINTF("Called.");

	if (!cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");

		return(CKR_CRYPTOKI_NOT_INITIALIZED);
................................................................................
		if (lock_mutex) {
			cackey_mutex_unlock(cackey_biglock);
		}

		return(CKR_GENERAL_ERROR);
	}

	if (cackey_pin_command != NULL) {



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

		get_pin_ret = cackey_get_pin(pinbuf);


		if (get_pin_ret != CACKEY_PCSC_S_OK) {
			CACKEY_DEBUG_PRINTF("cackey_get_pin() returned in failure, assuming the PIN was incorrect.");

			if (lock_mutex) {
				cackey_mutex_unlock(cackey_biglock);
			}



			return(CKR_PIN_INCORRECT);
		}









































		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) {