Check-in [b9b26ebc73]
Overview
Comment:Updated to provide basic (and buggy) PIV functionality
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | piv
Files: files | file ages | folders
SHA1: b9b26ebc73b6732401883ad4bd58a42c6d5771d5
User & Date: rkeene on 2013-01-10 04:59:42
Other Links: branch diff | manifest | tags
Context
2013-01-10
05:00
Cleaned up debug messages check-in: cfa10c1ef8 user: rkeene tags: piv
04:59
Updated to provide basic (and buggy) PIV functionality check-in: b9b26ebc73 user: rkeene tags: piv
01:00
Began adding PIV support check-in: 1494008def user: rkeene tags: piv
Changes

Modified cackey.c from [e326e231e2] to [d2a004aade].

154
155
156
157
158
159
160

161
162
163
164
165
166
167
#define GSCIS_TAG_EXPIRE_DATE         0x53
#define GSCIS_TAG_CARD_TYPE           0x54
#define GSCIS_TAG_SECURITY_CODE       0x57
#define GSCIS_TAG_CARDID_AID          0x58

/*** PIV Codes ***/
#define NISTSP800_73_3_INSTR_GET_DATA 0xCB


/*** PKI Information - EF 7000 ***/
#define GSCIS_TAG_CERTIFICATE         0x70
#define GSCIS_TAG_CERT_ISSUE_DATE     0x71
#define GSCIS_TAG_CERT_EXPIRE_DATE    0x72

/** Applet IDs **/







>







154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#define GSCIS_TAG_EXPIRE_DATE         0x53
#define GSCIS_TAG_CARD_TYPE           0x54
#define GSCIS_TAG_SECURITY_CODE       0x57
#define GSCIS_TAG_CARDID_AID          0x58

/*** PIV Codes ***/
#define NISTSP800_73_3_INSTR_GET_DATA 0xCB
#define NISTSP800_73_3_INSTR_GENAUTH  0x87

/*** PKI Information - EF 7000 ***/
#define GSCIS_TAG_CERTIFICATE         0x70
#define GSCIS_TAG_CERT_ISSUE_DATE     0x71
#define GSCIS_TAG_CERT_EXPIRE_DATE    0x72

/** Applet IDs **/
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
 *     cackey_pcsc_connect() if needed.
 *
 *     It will connect to the card in the reader attached to the slot
 *     specified.  It will reconnect to the card if the connection
 *     goes away.
 *
 */
static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned char lc, unsigned char *data, unsigned char le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) {
	uint8_t major_rc, minor_rc;
	size_t bytes_to_copy, tmp_respdata_len;
	LPCSCARD_IO_REQUEST pioSendPci;
	DWORD protocol;
	DWORD xmit_len, recv_len;
	LONG scard_xmit_ret, scard_reconn_ret;
	BYTE xmit_buf[1024], recv_buf[1024];







|







1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
 *     cackey_pcsc_connect() if needed.
 *
 *     It will connect to the card in the reader attached to the slot
 *     specified.  It will reconnect to the card if the connection
 *     goes away.
 *
 */
static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned int lc, unsigned char *data, unsigned int le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) {
	uint8_t major_rc, minor_rc;
	size_t bytes_to_copy, tmp_respdata_len;
	LPCSCARD_IO_REQUEST pioSendPci;
	DWORD protocol;
	DWORD xmit_len, recv_len;
	LONG scard_xmit_ret, scard_reconn_ret;
	BYTE xmit_buf[1024], recv_buf[1024];
1425
1426
1427
1428
1429
1430
1431





1432

1433
1434
1435
1436
1437
1438







1439

1440
1441
1442
1443
1444
1445
1446
	/* Transmit */
	xmit_len = 0;
	xmit_buf[xmit_len++] = class;
	xmit_buf[xmit_len++] = instruction;
	xmit_buf[xmit_len++] = p1;
	xmit_buf[xmit_len++] = p2;
	if (data) {





		xmit_buf[xmit_len++] = lc;

		for (idx = 0; idx < lc; idx++) {
			xmit_buf[xmit_len++] = data[idx];
		}
	}

	if (le != 0x00) {







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







>
>
>
>
>
|
>






>
>
>
>
>
>
>
|
>







1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
	/* Transmit */
	xmit_len = 0;
	xmit_buf[xmit_len++] = class;
	xmit_buf[xmit_len++] = instruction;
	xmit_buf[xmit_len++] = p1;
	xmit_buf[xmit_len++] = p2;
	if (data) {
		if (lc > 256) {
			xmit_buf[xmit_len++] = 0x80; /* XXX UNTESTED */
			xmit_buf[xmit_len++] = (lc & 0xff00) >> 8;
			xmit_buf[xmit_len++] = lc & 0xff;
		} else {
			xmit_buf[xmit_len++] = lc;
		}
		for (idx = 0; idx < lc; idx++) {
			xmit_buf[xmit_len++] = data[idx];
		}
	}

	if (le != 0x00) {
		if (le > 256) {
			xmit_buf[xmit_len++] = 0x80; /* XXX UNTESTED */
			xmit_buf[xmit_len++] = (le & 0xff00) >> 8;
			xmit_buf[xmit_len++] = le & 0xff;
		} else if (le == 256) {
			xmit_buf[xmit_len++] = 0x00;
		} else {
			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>>");
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296

2297
2298
2299
2300
2301
2302
2303
 *     ...
 *
 */
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_pivauth[] = {NISTSP800_73_3_OID_PIVAUTH};
	unsigned char curr_aid[7];
	unsigned char buffer[8192];
	unsigned long outidx = 0;
	cackey_ret transaction_ret;
	ssize_t read_ret;
	int certs_resizable;
	int send_ret, select_ret;
	int piv = 0;


	CACKEY_DEBUG_PRINTF("Called.");

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

		return(NULL);







|







|
>







2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
 *     ...
 *
 */
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];
	unsigned long outidx = 0;
	cackey_ret transaction_ret;
	ssize_t read_ret;
	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);
2368
2369
2370
2371
2372
2373
2374
















2375
2376




2377
2378
2379
2380
2381
2382
2383
2384
2385
2386



2387
2388
2389
2390
2391
2392
2393
			cackey_end_transaction(slot);

			return(NULL);
		}
	}

	if (piv) {
















		read_ret = cackey_get_data(slot, buffer, sizeof(buffer), piv_oid_pivauth);





		curr_id = &certs[outidx];
		outidx++;

		curr_id->keysize = -1;
		curr_id->file = 0xFFFF;
		curr_id->applet[0] = NISTSP800_78_3_KEY_PIVAUTH;

		curr_id->certificate_len = read_ret;
		curr_id->certificate = malloc(curr_id->certificate_len);
		memcpy(curr_id->certificate, buffer + 4, curr_id->certificate_len - 4); /* XXX TODO PIV */



	} 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) {
			CACKEY_DEBUG_PRINTF("Found tag: %s ... ", CACKEY_DEBUG_FUNC_TAG_TO_STR(ccc_curr->tag));







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

>
>
>
>
|
|

|
|
|

|
|
|
>
>
>







2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
			cackey_end_transaction(slot);

			return(NULL);
		}
	}

	if (piv) {
		for (idx = 0; idx < 3; idx++) {
			switch (idx) {
				case 0:
					piv_oid = piv_oid_pivauth;
					piv_key = NISTSP800_78_3_KEY_PIVAUTH;
					break;
				case 1:
					piv_oid = piv_oid_signature;
					piv_key = NISTSP800_78_3_KEY_SIGNATURE;
					break;
				case 2:
					piv_oid = piv_oid_keymgt;
					piv_key = NISTSP800_78_3_KEY_KEYMGT;
					break;
			}

			read_ret = cackey_get_data(slot, buffer, sizeof(buffer), piv_oid);

			if (read_ret <= 0) {
				continue;
			}

			curr_id = &certs[outidx];
			outidx++;

			curr_id->keysize = -1;
			curr_id->file = 0xFFFF;
			curr_id->applet[0] = piv_key;

			curr_id->certificate_len = read_ret;
			curr_id->certificate = malloc(curr_id->certificate_len);
			memcpy(curr_id->certificate, buffer + 4, curr_id->certificate_len - 4); /* XXX TODO PIV (-4 header, -5 trailer == why ?) */
			curr_id->certificate_len -= 4;
			curr_id->certificate_len -= 5;
		}
	} 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) {
			CACKEY_DEBUG_PRINTF("Found tag: %s ... ", CACKEY_DEBUG_FUNC_TAG_TO_STR(ccc_curr->tag));
2500
2501
2502
2503
2504
2505
2506

2507
2508
2509
2510
2511
2512
2513
2514
2515
 *     ...
 *
 * 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) {

	unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s;
	unsigned char bytes_to_send, p1;
	unsigned char blocktype;
	cackey_ret send_ret;
	uint16_t respcode;
	ssize_t retval = 0, unpadoffset;
	size_t tmpbuflen, padlen, tmpoutbuflen;
	int free_tmpbuf = 0;
	int le;







>

|







2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
 *     ...
 *
 * 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) {
	unsigned char dyn_auth_template[10];
	unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s;
	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;
	int free_tmpbuf = 0;
	int le;
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
2636



2637

2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
		free_tmpbuf = 0;
		padlen = 0;
	}

	/* Begin transaction */
	cackey_begin_transaction(slot);

	/* Select correct applet */
	if (identity->pcsc_identity->file == 0xFFFF) {
		piv = 1;
	} else {
		piv = 0;
	}


	if (piv) {
		CACKEY_DEBUG_PRINTF("Sign/Decrypt not implemented XXX TODO PIV");
		cackey_end_transaction(slot);
		return(-1);
	} else {
		CACKEY_DEBUG_PRINTF("Selecting applet found at %p ...", identity->pcsc_identity->applet);
		cackey_select_applet(slot, identity->pcsc_identity->applet, sizeof(identity->pcsc_identity->applet));

		/* Select correct file */
		cackey_select_file(slot, identity->pcsc_identity->file);















		tmpbuf_s = tmpbuf;
		outbuf_s = outbuf;
		while (tmpbuflen) {
			if (tmpbuflen > 245) {
				bytes_to_send = 245;




				p1 = 0x80;
				le = 0x00;

			} else {
				bytes_to_send = tmpbuflen;




				p1 = 0x00;
				le = 0x00;
			}


			tmpoutbuflen = outbuflen;




			send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, p1, 0x00, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);

			if (send_ret != CACKEY_PCSC_S_OK) {
				CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error.");

				if (free_tmpbuf) {
					if (tmpbuf_s) {
						free(tmpbuf_s);
					}
				}

				/* End transaction */
				cackey_end_transaction(slot);

				if (respcode == 0x6982) {
					CACKEY_DEBUG_PRINTF("Security status not satisified.  Returning NEEDLOGIN");

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

					return(CACKEY_PCSC_E_TOKENABSENT);
				}

				return(-1);
			}

			tmpbuf += bytes_to_send;
			tmpbuflen -= bytes_to_send;

			outbuf += tmpoutbuflen;
			outbuflen -= tmpoutbuflen;
			retval += tmpoutbuflen;
		}
	}

	if (free_tmpbuf) {
		if (tmpbuf_s) {
			free(tmpbuf_s);
		}
	}







|






>
|
<
<
<
<





>
>
>
>
>
>
>
>
>
>
>

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


>
|
|
>
>
>
>



|
>
|

>
>
>

>
|
|

|
|
|
|
|

|
|

|
|

|
|

|
|

|
|

|

|
|

|
|

|
|

|
|
|
<







2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652




2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740

2741
2742
2743
2744
2745
2746
2747
		free_tmpbuf = 0;
		padlen = 0;
	}

	/* Begin transaction */
	cackey_begin_transaction(slot);

	/* Determine type of transaction */
	if (identity->pcsc_identity->file == 0xFFFF) {
		piv = 1;
	} else {
		piv = 0;
	}

	/* Select correct applet */
	if (!piv) {




		CACKEY_DEBUG_PRINTF("Selecting applet found at %p ...", identity->pcsc_identity->applet);
		cackey_select_applet(slot, identity->pcsc_identity->applet, sizeof(identity->pcsc_identity->applet));

		/* Select correct file */
		cackey_select_file(slot, identity->pcsc_identity->file);
	} else {
		dyn_auth_template[0] = 0x7C;
		dyn_auth_template[1] = 0x82;
		dyn_auth_template[2] = ((tmpbuflen + 6) & 0xff00) >> 8;
		dyn_auth_template[3] = (tmpbuflen + 6) & 0x00ff;
		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->applet[0], sizeof(dyn_auth_template), dyn_auth_template, 0x00, NULL, NULL, NULL);
	}

	tmpbuf_s = tmpbuf;
	outbuf_s = outbuf;
	while (tmpbuflen) {
		if (tmpbuflen > 245) {
			bytes_to_send = 245;
			if (piv) {
				class = 0x10;
				le = 0x00;
			} else {
				p1 = 0x80;
				le = 0x00;
			}
		} else {
			bytes_to_send = tmpbuflen;
			if (piv) {
				class = GSCIS_CLASS_ISO7816;
				le = 256;
			} else {
				p1 = 0x00;
				le = 0x00;
			}
		}

		tmpoutbuflen = outbuflen;

		if (piv) {
			send_ret = cackey_send_apdu(slot, class, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->applet[0], bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);
		} else {
			send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, p1, 0x00, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);
		}
		if (send_ret != CACKEY_PCSC_S_OK) {
			CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error.");

			if (free_tmpbuf) {
				if (tmpbuf_s) {
					free(tmpbuf_s);
				}
			}

			/* End transaction */
			cackey_end_transaction(slot);

			if (respcode == 0x6982) {
				CACKEY_DEBUG_PRINTF("Security status not satisified.  Returning NEEDLOGIN");

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

				return(CACKEY_PCSC_E_TOKENABSENT);
			}

			return(-1);
		}

		tmpbuf += bytes_to_send;
		tmpbuflen -= bytes_to_send;

		outbuf += tmpoutbuflen;
		outbuflen -= tmpoutbuflen;
		retval += tmpoutbuflen;

	}

	if (free_tmpbuf) {
		if (tmpbuf_s) {
			free(tmpbuf_s);
		}
	}
2692
2693
2694
2695
2696
2697
2698














2699
2700
2701
2702
2703
2704
2705
	if (outbuflen > _POSIX_SSIZE_MAX) {
		CACKEY_DEBUG_PRINTF("Outbuflen exceeds maximum value, returning in failure. (max = %li, outbuflen = %lu)", (long) _POSIX_SSIZE_MAX, (unsigned long) outbuflen);

		return(-1);
	}
#  endif
#endif















	/* Unpad reply */
	if (unpadOutput) {
		if (retval < 3) {
			CACKEY_DEBUG_PRINTF("Reply is too small, we are not able to unpad -- passing back and hoping for the best!");

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







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







2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
	if (outbuflen > _POSIX_SSIZE_MAX) {
		CACKEY_DEBUG_PRINTF("Outbuflen exceeds maximum value, returning in failure. (max = %li, outbuflen = %lu)", (long) _POSIX_SSIZE_MAX, (unsigned long) outbuflen);

		return(-1);
	}
#  endif
#endif

	/* We must remove the "7C" tag to get to the signature */
	if (piv) {
		if (outbuf[0] != 0x7C) {
			CACKEY_DEBUG_PRINTF("Response from PIV for GENERATE AUTHENTICATION was not a 0x7C tag, returning in failure");


			return(-1);
		}

		/* XXX TODO PIV */
		memmove(outbuf, outbuf + 8, retval - 8);
		retval -= 8;
	}

	/* Unpad reply */
	if (unpadOutput) {
		if (retval < 3) {
			CACKEY_DEBUG_PRINTF("Reply is too small, we are not able to unpad -- passing back and hoping for the best!");

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