Diff

Differences From Artifact [318588635a]:

To Artifact [3a0d4abad4]:


31
32
33
34
35
36
37




38
39
40
41
42
43
44
..
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
..
85
86
87
88
89
90
91

92
93
94
95
96
97
98
...
222
223
224
225
226
227
228

229
230
231
232
233
234
235
...
714
715
716
717
718
719
720








721
722
723
724
725
726
727
....
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
....
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
....
1741
1742
1743
1744
1745
1746
1747






1748
1749
1750
1751
1752
1753
1754
....
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439




2440
2441
2442
2443
2444
2445
2446
....
2550
2551
2552
2553
2554
2555
2556

2557
2558


2559
2560
2561
2562















































2563
2564
2565
2566
2567
2568
2569
....
2631
2632
2633
2634
2635
2636
2637

2638



2639
2640
2641
2642
2643
2644
2645
....
2651
2652
2653
2654
2655
2656
2657

2658



2659
2660
2661
2662
2663
2664
2665
....
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
....
2814
2815
2816
2817
2818
2819
2820
2821











2822
2823
2824
2825
2826
2827
2828
....
2886
2887
2888
2889
2890
2891
2892


2893
2894
2895
2896
2897
2898
2899
....
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
....
3037
3038
3039
3040
3041
3042
3043

































































































3044
3045
3046
3047
3048
3049
3050
....
4084
4085
4086
4087
4088
4089
4090





















































4091
4092
4093
4094
4095
4096
4097
....
4379
4380
4381
4382
4383
4384
4385

4386
4387
4388
4389
4390
4391
4392
....
4900
4901
4902
4903
4904
4905
4906
4907
4908





4909
4910
4911
4912
4913
4914
4915
4916
4917



4918


















































































































4919















4920
4921
4922
4923
4924
4925
4926
....
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
....
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
5332
5333
5334
5335
5336
#endif
#ifdef HAVE_LIMITS_H
#  include <limits.h>
#endif
#ifdef HAVE_STDIO_H
#  include <stdio.h>
#endif




#ifdef HAVE_ZLIB_H
#  ifdef HAVE_LIBZ
#    include <zlib.h>
#  endif
#else
#  ifdef HAVE_LIBZ
#    undef HAVE_LIBZ
................................................................................

#include "pkcs11.h"
#include "pkcs11n.h"
#include "asn1-x509.h"
#include "sha1.h"
#include "md5.h"

/*
 * Include these source files in this translation unit so that we can bind to
 * functions and not include any symbols in the output shared object.
 */
#include "asn1-x509.c"
#include "sha1.c"
#include "md5.c"

#ifndef CACKEY_CRYPTOKI_VERSION_CODE
#  define CACKEY_CRYPTOKI_VERSION_CODE 0x021e00
#endif

/* GSC-IS v2.1 Definitions */
/** Classes **/
#define GSCIS_CLASS_ISO7816           0x00
................................................................................
#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
................................................................................
#  define CACKEY_DEBUG_PRINTBUF(f, x, y) { \
	static char buf_user[4096] = {0}, *buf_user_p; \
	unsigned long buf_user_size; \
	unsigned char *TMPBUF; \
	unsigned long idx; \
	int snprintf_ret; \
	TMPBUF = (unsigned char *) (x); \

	buf_user_p = buf_user; \
	buf_user_size = sizeof(buf_user); \
	for (idx = 1; idx < (y); idx++) { \
		if (buf_user_size <= 0) { \
			break; \
		}; \
		snprintf_ret = snprintf(buf_user_p, buf_user_size, ", %02x", TMPBUF[idx]); \
................................................................................
#  define CACKEY_DEBUG_FUNC_TAG_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_OBJID_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_APPTYPE_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_ATTRIBUTE_TO_STR(x) "DEBUG_DISABLED"
#endif









typedef enum {
	CACKEY_ID_TYPE_CAC,
	CACKEY_ID_TYPE_PIV,
	CACKEY_ID_TYPE_CERT_ONLY
} cackey_pcsc_id_type;

struct cackey_pcsc_identity {
................................................................................
		CACKEY_DEBUG_PRINTF("Connection to PC/SC failed, returning in failure");

		return(CACKEY_PCSC_E_GENERIC);
	}

	/* Connect to reader, if needed */
	if (!slot->pcsc_card_connected) {
		CACKEY_DEBUG_PRINTF("SCardConnect(%s) called", slot->pcsc_reader);
		scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &slot->pcsc_card, &protocol);

		if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
			CACKEY_DEBUG_PRINTF("SCardConnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=0")
			scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &slot->pcsc_card, &protocol);

			if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
................................................................................
			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);
................................................................................
		CACKEY_DEBUG_PRINTF("outbuffer_len_p is NULL.  Returning in failure.");

		return(NULL);
	}

	buffer_len = *outbuffer_len_p;
	outbuffer_len = *outbuffer_len_p;







	buffer_p = buffer;
	if (buffer_p[0] != tag) {
		CACKEY_DEBUG_PRINTF("Tag found was not tag expected.  Tag = %02x, Expected = %02x.  Returning in failure.", (unsigned int) buffer_p[0], tag);

		return(NULL);
	}
................................................................................
 */
static struct cackey_pcsc_identity *cackey_read_certs(struct cackey_slot *slot, struct cackey_pcsc_identity *certs, unsigned long *count) {
	struct cackey_pcsc_identity *curr_id;
	struct cackey_tlv_entity *ccc_tlv, *ccc_curr, *app_tlv, *app_curr;
	unsigned char ccc_aid[] = {GSCIS_AID_CCC}, piv_aid[] = {NISTSP800_73_3_PIV_AID};
	unsigned char *piv_oid, piv_oid_pivauth[] = {NISTSP800_73_3_OID_PIVAUTH}, piv_oid_signature[] = {NISTSP800_73_3_OID_SIGNATURE}, piv_oid_keymgt[] = {NISTSP800_73_3_OID_KEYMGT};
	unsigned char curr_aid[7];
	unsigned char buffer[8192], *buffer_p;
	unsigned long outidx = 0;
	char *piv_label;
	cackey_ret transaction_ret;
	ssize_t read_ret;
	size_t buffer_len;
	int certs_resizable;
	int send_ret, select_ret;
	int piv_key, piv = 0;
	int idx;





	CACKEY_DEBUG_PRINTF("Called.");

	if (count == NULL) {
		CACKEY_DEBUG_PRINTF("count is NULL, returning in failure");

		return(NULL);
................................................................................
			curr_id->certificate = malloc(curr_id->certificate_len);

			buffer_len = sizeof(buffer);
			buffer_p = cackey_read_bertlv_tag(buffer, &buffer_len, 0x70, curr_id->certificate, &curr_id->certificate_len);

			if (buffer_p == NULL) {
				CACKEY_DEBUG_PRINTF("Reading certificate from BER-TLV response failed, skipping key %i", idx);

				free(curr_id->certificate);



				outidx--;

				continue;
			}















































		}
	} else {
		/* Read all the applets from the CCC's TLV */
		ccc_tlv = cackey_read_tlv(slot);

		/* Look for CARDURLs that coorespond to PKI applets */
		for (ccc_curr = ccc_tlv; ccc_curr; ccc_curr = ccc_curr->_next) {
................................................................................

				curr_id->certificate = malloc(curr_id->certificate_len);
				memcpy(curr_id->certificate, app_curr->value, curr_id->certificate_len);

				if (outidx >= *count) {
					if (certs_resizable) {
						*count *= 2;

						certs = realloc(certs, sizeof(*certs) * (*count));



					} else {
						break;
					}
				}
			}

			cackey_free_tlv(app_tlv);
................................................................................

		cackey_free_tlv(ccc_tlv);
	}

	*count = outidx;

	if (certs_resizable) {

		certs = realloc(certs, sizeof(*certs) * (*count));



	}

	slot->cached_certs = cackey_copy_certs(NULL, certs, *count);
	slot->cached_certs_count = *count;

	/* Terminate SmartCard Transaction */
	cackey_end_transaction(slot);
................................................................................
 *
 * NOTES
 *     ...
 *
 */
static ssize_t cackey_signdecrypt(struct cackey_slot *slot, struct cackey_identity *identity, unsigned char *buf, size_t buflen, unsigned char *outbuf, size_t outbuflen, int padInput, int unpadOutput) {
	cackey_pcsc_id_type id_type;
	unsigned char dyn_auth_template[10];
	unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s, *outbuf_p;
	unsigned char bytes_to_send, p1, class;
	unsigned char blocktype;
	cackey_ret send_ret;
	uint16_t respcode;
	ssize_t retval = 0, unpadoffset;
	size_t tmpbuflen, padlen, tmpoutbuflen, outbuf_len;
................................................................................
			dyn_auth_template[4] = 0x82;
			dyn_auth_template[5] = 0x00;
			dyn_auth_template[6] = 0x81;
			dyn_auth_template[7] = 0x82;
			dyn_auth_template[8] = (tmpbuflen & 0xff00) >> 8;
			dyn_auth_template[9] = tmpbuflen & 0x00ff;

			send_ret = cackey_send_apdu(slot, 0x10, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->card.piv.key_id, sizeof(dyn_auth_template), dyn_auth_template, 0x00, NULL, NULL, NULL);











			break;
		case CACKEY_ID_TYPE_CERT_ONLY:
			break;
	}

	tmpbuf_s = tmpbuf;
	outbuf_s = outbuf;
................................................................................
					CACKEY_DEBUG_PRINTF("Got \"WRONG CLASS\", this means we are talking to the wrong object (likely because the card went away) -- resetting");
				} else {
					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");

				cackey_mark_slot_reset(slot);
................................................................................
			}

			retval = outbuf_len;

			outbuf_len = retval;
			outbuf_p = cackey_read_bertlv_tag(outbuf, &outbuf_len, 0x82, NULL,  &outbuf_len);
			if (outbuf_p == NULL) {
				CACKEY_DEBUG_PRINTF("Response from PIV for GENERATE AUTHENTICATION was not a 0x82 with then 0x7C tag, returning in failure");

				return(-1);
			}

			retval = outbuf_len;

			break;
................................................................................
	}


	CACKEY_DEBUG_PRINTF("Returning in success, retval = %li (bytes)", (long) retval);

	return(retval);
}


































































































/*
 * SYNPOSIS
 *     ...
 *
 * ARGUMENTS
 *     ...
................................................................................
		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;

................................................................................
		} else {
			
		}
	}

	/* Determine list of readers */
	pcsc_connect_ret = cackey_pcsc_connect();

	if (pcsc_connect_ret != CACKEY_PCSC_S_OK) {
		CACKEY_DEBUG_PRINTF("Connection to PC/SC failed, assuming no slots");

		slot_count = 0;
	} else {
		pcsc_readers_len = 0;

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

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







>
>
>
>







 







<
<
<
<
<
<
<
<







 







>







 







>







 







>
>
>
>
>
>
>
>







 







|







 







|







 







>
>
>
>
>
>







 







|




|




>
>
>
>







 







>


>
>




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







 







>
|
>
>
>







 







>
|
>
>
>







 







|







 







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







 







>
>







 







|







 







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







 







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







 







>







 







<

>
>
>
>
>








<
>
>
>

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







 







|
|



<







 







|
<
<
<




|
<
>
|
>





<
<



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







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
..
63
64
65
66
67
68
69








70
71
72
73
74
75
76
..
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
...
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
....
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
....
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
....
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
....
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
....
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
....
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
....
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
....
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
....
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
....
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
....
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
....
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
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
....
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
....
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
....
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
#endif
#ifdef HAVE_LIMITS_H
#  include <limits.h>
#endif
#ifdef HAVE_STDIO_H
#  include <stdio.h>
#endif
#define HAVE_ERRNO_H 1
#ifdef HAVE_ERRNO_H
#  include <errno.h>
#endif
#ifdef HAVE_ZLIB_H
#  ifdef HAVE_LIBZ
#    include <zlib.h>
#  endif
#else
#  ifdef HAVE_LIBZ
#    undef HAVE_LIBZ
................................................................................

#include "pkcs11.h"
#include "pkcs11n.h"
#include "asn1-x509.h"
#include "sha1.h"
#include "md5.h"









#ifndef CACKEY_CRYPTOKI_VERSION_CODE
#  define CACKEY_CRYPTOKI_VERSION_CODE 0x021e00
#endif

/* GSC-IS v2.1 Definitions */
/** Classes **/
#define GSCIS_CLASS_ISO7816           0x00
................................................................................
#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
................................................................................
#  define CACKEY_DEBUG_PRINTBUF(f, x, y) { \
	static char buf_user[4096] = {0}, *buf_user_p; \
	unsigned long buf_user_size; \
	unsigned char *TMPBUF; \
	unsigned long idx; \
	int snprintf_ret; \
	TMPBUF = (unsigned char *) (x); \
	buf_user[0] = 0; \
	buf_user_p = buf_user; \
	buf_user_size = sizeof(buf_user); \
	for (idx = 1; idx < (y); idx++) { \
		if (buf_user_size <= 0) { \
			break; \
		}; \
		snprintf_ret = snprintf(buf_user_p, buf_user_size, ", %02x", TMPBUF[idx]); \
................................................................................
#  define CACKEY_DEBUG_FUNC_TAG_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_OBJID_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_APPTYPE_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_ATTRIBUTE_TO_STR(x) "DEBUG_DISABLED"
#endif

/*
 * Include these source files in this translation unit so that we can bind to
 * functions and not include any symbols in the output shared object.
 */
#include "asn1-x509.c"
#include "sha1.c"
#include "md5.c"

typedef enum {
	CACKEY_ID_TYPE_CAC,
	CACKEY_ID_TYPE_PIV,
	CACKEY_ID_TYPE_CERT_ONLY
} cackey_pcsc_id_type;

struct cackey_pcsc_identity {
................................................................................
		CACKEY_DEBUG_PRINTF("Connection to PC/SC failed, returning in failure");

		return(CACKEY_PCSC_E_GENERIC);
	}

	/* Connect to reader, if needed */
	if (!slot->pcsc_card_connected) {
		CACKEY_DEBUG_PRINTF("SCardConnect(%s) called for slot %p", slot->pcsc_reader, slot);
		scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &slot->pcsc_card, &protocol);

		if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
			CACKEY_DEBUG_PRINTF("SCardConnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=0")
			scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &slot->pcsc_card, &protocol);

			if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
................................................................................
			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);
................................................................................
		CACKEY_DEBUG_PRINTF("outbuffer_len_p is NULL.  Returning in failure.");

		return(NULL);
	}

	buffer_len = *outbuffer_len_p;
	outbuffer_len = *outbuffer_len_p;

	if (buffer_len < 2) {
		CACKEY_DEBUG_PRINTF("buffer_len is less than 2, so we can't read any tag.  Returning in failure.");

		return(NULL);
	}

	buffer_p = buffer;
	if (buffer_p[0] != tag) {
		CACKEY_DEBUG_PRINTF("Tag found was not tag expected.  Tag = %02x, Expected = %02x.  Returning in failure.", (unsigned int) buffer_p[0], tag);

		return(NULL);
	}
................................................................................
 */
static struct cackey_pcsc_identity *cackey_read_certs(struct cackey_slot *slot, struct cackey_pcsc_identity *certs, unsigned long *count) {
	struct cackey_pcsc_identity *curr_id;
	struct cackey_tlv_entity *ccc_tlv, *ccc_curr, *app_tlv, *app_curr;
	unsigned char ccc_aid[] = {GSCIS_AID_CCC}, piv_aid[] = {NISTSP800_73_3_PIV_AID};
	unsigned char *piv_oid, piv_oid_pivauth[] = {NISTSP800_73_3_OID_PIVAUTH}, piv_oid_signature[] = {NISTSP800_73_3_OID_SIGNATURE}, piv_oid_keymgt[] = {NISTSP800_73_3_OID_KEYMGT};
	unsigned char curr_aid[7];
	unsigned char buffer[8192], *buffer_p, *tmpbuf;
	unsigned long outidx = 0;
	char *piv_label;
	cackey_ret transaction_ret;
	ssize_t read_ret;
	size_t buffer_len, tmpbuflen;
	int certs_resizable;
	int send_ret, select_ret;
	int piv_key, piv = 0;
	int idx;
#ifdef HAVE_LIBZ
	int uncompress_ret;
	z_stream gzip_stream;
#endif

	CACKEY_DEBUG_PRINTF("Called.");

	if (count == NULL) {
		CACKEY_DEBUG_PRINTF("count is NULL, returning in failure");

		return(NULL);
................................................................................
			curr_id->certificate = malloc(curr_id->certificate_len);

			buffer_len = sizeof(buffer);
			buffer_p = cackey_read_bertlv_tag(buffer, &buffer_len, 0x70, curr_id->certificate, &curr_id->certificate_len);

			if (buffer_p == NULL) {
				CACKEY_DEBUG_PRINTF("Reading certificate from BER-TLV response failed, skipping key %i", idx);

				free(curr_id->certificate);

				curr_id->certificate = NULL;

				outidx--;

				continue;
			}

#ifdef HAVE_LIBZ
			if (curr_id->certificate_len > 4) {
				if (memcmp(curr_id->certificate, "\x1f\x8b\x08\x00", 4) == 0) {
					tmpbuflen = curr_id->certificate_len * 2;
					tmpbuf = malloc(tmpbuflen);

					CACKEY_DEBUG_PRINTBUF("Attempting to decompress:", curr_id->certificate, curr_id->certificate_len);

					gzip_stream.zalloc = NULL;
					gzip_stream.zfree = NULL;
					gzip_stream.opaque = NULL;

					gzip_stream.next_in  = curr_id->certificate;
					gzip_stream.avail_in = curr_id->certificate_len;
					gzip_stream.next_out = tmpbuf;
					gzip_stream.avail_out = tmpbuflen;

					uncompress_ret = inflateInit(&gzip_stream);
					if (uncompress_ret == Z_OK) {
						uncompress_ret = inflateReset2(&gzip_stream, 31);
					}
					if (uncompress_ret == Z_OK) {
						uncompress_ret = inflate(&gzip_stream, 0);
					}
					if (uncompress_ret == Z_STREAM_END) {
						uncompress_ret = inflateEnd(&gzip_stream);
					} else {
						uncompress_ret = Z_DATA_ERROR;
					}
					if (uncompress_ret == Z_OK) {
						tmpbuflen = gzip_stream.total_out;

						CACKEY_DEBUG_PRINTBUF("Decompressed to:", tmpbuf, tmpbuflen);

						free(curr_id->certificate);

						curr_id->certificate = tmpbuf;
						curr_id->certificate_len = tmpbuflen;
					} else {
						CACKEY_DEBUG_PRINTF("Decompressing failed! uncompress() returned %i", uncompress_ret);

						free(tmpbuf);
					}
				}
			}
#endif
		}
	} else {
		/* Read all the applets from the CCC's TLV */
		ccc_tlv = cackey_read_tlv(slot);

		/* Look for CARDURLs that coorespond to PKI applets */
		for (ccc_curr = ccc_tlv; ccc_curr; ccc_curr = ccc_curr->_next) {
................................................................................

				curr_id->certificate = malloc(curr_id->certificate_len);
				memcpy(curr_id->certificate, app_curr->value, curr_id->certificate_len);

				if (outidx >= *count) {
					if (certs_resizable) {
						*count *= 2;
						if (*count != 0) {
							certs = realloc(certs, sizeof(*certs) * (*count));
						} else {
							certs = NULL;
						}
					} else {
						break;
					}
				}
			}

			cackey_free_tlv(app_tlv);
................................................................................

		cackey_free_tlv(ccc_tlv);
	}

	*count = outidx;

	if (certs_resizable) {
		if (*count != 0) {
			certs = realloc(certs, sizeof(*certs) * (*count));
		} else {
			certs = NULL;
		}
	}

	slot->cached_certs = cackey_copy_certs(NULL, certs, *count);
	slot->cached_certs_count = *count;

	/* Terminate SmartCard Transaction */
	cackey_end_transaction(slot);
................................................................................
 *
 * NOTES
 *     ...
 *
 */
static ssize_t cackey_signdecrypt(struct cackey_slot *slot, struct cackey_identity *identity, unsigned char *buf, size_t buflen, unsigned char *outbuf, size_t outbuflen, int padInput, int unpadOutput) {
	cackey_pcsc_id_type id_type;
	unsigned char dyn_auth_template[10], *dyn_auth_tmpbuf;
	unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s, *outbuf_p;
	unsigned char bytes_to_send, p1, class;
	unsigned char blocktype;
	cackey_ret send_ret;
	uint16_t respcode;
	ssize_t retval = 0, unpadoffset;
	size_t tmpbuflen, padlen, tmpoutbuflen, outbuf_len;
................................................................................
			dyn_auth_template[4] = 0x82;
			dyn_auth_template[5] = 0x00;
			dyn_auth_template[6] = 0x81;
			dyn_auth_template[7] = 0x82;
			dyn_auth_template[8] = (tmpbuflen & 0xff00) >> 8;
			dyn_auth_template[9] = tmpbuflen & 0x00ff;

			dyn_auth_tmpbuf = malloc(tmpbuflen + sizeof(dyn_auth_template));
			memcpy(dyn_auth_tmpbuf, dyn_auth_template, sizeof(dyn_auth_template));
			memcpy(dyn_auth_tmpbuf + sizeof(dyn_auth_template), tmpbuf, tmpbuflen);

			if (free_tmpbuf) {
				free(tmpbuf);
			}

			tmpbuflen += sizeof(dyn_auth_template);
			tmpbuf = dyn_auth_tmpbuf;
			free_tmpbuf = 1;

			break;
		case CACKEY_ID_TYPE_CERT_ONLY:
			break;
	}

	tmpbuf_s = tmpbuf;
	outbuf_s = outbuf;
................................................................................
					CACKEY_DEBUG_PRINTF("Got \"WRONG CLASS\", this means we are talking to the wrong object (likely because the card went away) -- resetting");
				} else {
					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");

				cackey_mark_slot_reset(slot);
................................................................................
			}

			retval = outbuf_len;

			outbuf_len = retval;
			outbuf_p = cackey_read_bertlv_tag(outbuf, &outbuf_len, 0x82, NULL,  &outbuf_len);
			if (outbuf_p == NULL) {
				CACKEY_DEBUG_PRINTF("Response from PIV for GENERATE AUTHENTICATION was not a 0x82 within a 0x7C tag, returning in failure");

				return(-1);
			}

			retval = outbuf_len;

			break;
................................................................................
	}


	CACKEY_DEBUG_PRINTF("Returning in success, retval = %li (bytes)", (long) retval);

	return(retval);
}

/*
 * SYNPOSIS
 *     ...
 *
 * ARGUMENTS
 *     ...
 *
 * 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(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;

................................................................................
		} else {
			
		}
	}

	/* Determine list of readers */
	pcsc_connect_ret = cackey_pcsc_connect();
/* XXX: CAN HANG HERE ! */
	if (pcsc_connect_ret != CACKEY_PCSC_S_OK) {
		CACKEY_DEBUG_PRINTF("Connection to PC/SC failed, assuming no slots");

		slot_count = 0;
	} else {
		pcsc_readers_len = 0;

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

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