Check-in [2d8b4030f7]
Overview
Comment:Updated PC/SC error messages to include text return value as well as numeric value

Minor reorganization

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2d8b4030f7aec2af6494d01cb9765ccadd671e8b
User & Date: rkeene on 2010-05-12 17:25:06
Other Links: manifest | tags
Context
2010-05-12
19:35
Updated ignores

Updated read_tlv to return a list

Added a free_tlv function

Updated value->str conversion functions to be more flexible/direct

Added sample code to select all PKI applets/files

Simplified TLV entity check-in: 330efa4f3b user: rkeene tags: trunk

17:25
Updated PC/SC error messages to include text return value as well as numeric value

Minor reorganization check-in: 2d8b4030f7 user: rkeene tags: trunk

14:52
Added test driver (from libssh-agent-pkcs11-provider)

Added basic ASN.1 X.509 BER decoder (from libssh-agent-pkcs11-provider)

Work towards updating CACKey to talk to CAC using PC/SC check-in: a3d727289c user: rkeene tags: trunk

Changes

Modified cackey.c from [c365c15fc9] to [d5b94d106d].

336
337
338
339
340
341
342
343
















































































































344
345
346
347
348
349
350

351
352
353
354
355
356
357

	if (retval == NULL) {
		retval = "UNKNOWN";
	}

	return(retval);
}

















































































































#  define malloc(x) CACKEY_DEBUG_FUNC_MALLOC(x, __func__)
#  define realloc(x, y) CACKEY_DEBUG_FUNC_REALLOC(x, y, __func__)
#else
#  define CACKEY_DEBUG_PRINTF(x...) /**/
#  define CACKEY_DEBUG_PRINTBUF(f, x, y) /**/
#  define CACKEY_DEBUG_PERROR(x) /**/
#  define CACKEY_DEBUG_FUNC_TAG_TO_STR(x) "DEBUG_DISABLED"

#endif

struct cackey_identity {
	CK_ATTRIBUTE *attributes;
	CK_ULONG attributes_count;
};









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







>







336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470

	if (retval == NULL) {
		retval = "UNKNOWN";
	}

	return(retval);
}

static const char *CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(LONG retcode) {
	const char *retval = NULL;

	switch (retcode) {
		case SCARD_S_SUCCESS:
			retval = "SCARD_S_SUCCESS";
			break;
		case SCARD_E_CANCELLED:
			retval = "SCARD_E_CANCELLED";
			break;
		case SCARD_E_CANT_DISPOSE:
			retval = "SCARD_E_CANT_DISPOSE";
			break;
		case SCARD_E_INSUFFICIENT_BUFFER:
			retval = "SCARD_E_INSUFFICIENT_BUFFER";
			break;
		case SCARD_E_INVALID_ATR:
			retval = "SCARD_E_INVALID_ATR";
			break;
		case SCARD_E_INVALID_HANDLE:
			retval = "SCARD_E_INVALID_HANDLE";
			break;
		case SCARD_E_INVALID_PARAMETER:
			retval = "SCARD_E_INVALID_PARAMETER";
			break;
		case SCARD_E_INVALID_TARGET:
			retval = "SCARD_E_INVALID_TARGET";
			break;
		case SCARD_E_INVALID_VALUE:
			retval = "SCARD_E_INVALID_VALUE";
			break;
		case SCARD_E_NO_MEMORY:
			retval = "SCARD_E_NO_MEMORY";
			break;
		case SCARD_E_UNKNOWN_READER:
			retval = "SCARD_E_UNKNOWN_READER";
			break;
		case SCARD_E_TIMEOUT:
			retval = "SCARD_E_TIMEOUT";
			break;
		case SCARD_E_SHARING_VIOLATION:
			retval = "SCARD_E_SHARING_VIOLATION";
			break;
		case SCARD_E_NO_SMARTCARD:
			retval = "SCARD_E_NO_SMARTCARD";
			break;
		case SCARD_E_UNKNOWN_CARD:
			retval = "SCARD_E_UNKNOWN_CARD";
			break;
		case SCARD_E_PROTO_MISMATCH:
			retval = "SCARD_E_PROTO_MISMATCH";
			break;
		case SCARD_E_NOT_READY:
			retval = "SCARD_E_NOT_READY";
			break;
		case SCARD_E_SYSTEM_CANCELLED:
			retval = "SCARD_E_SYSTEM_CANCELLED";
			break;
		case SCARD_E_NOT_TRANSACTED:
			retval = "SCARD_E_NOT_TRANSACTED";
			break;
		case SCARD_E_READER_UNAVAILABLE:
			retval = "SCARD_E_READER_UNAVAILABLE";
			break;
		case SCARD_W_UNSUPPORTED_CARD:
			retval = "SCARD_W_UNSUPPORTED_CARD";
			break;
		case SCARD_W_UNRESPONSIVE_CARD:
			retval = "SCARD_W_UNRESPONSIVE_CARD";
			break;
		case SCARD_W_UNPOWERED_CARD:
			retval = "SCARD_W_UNPOWERED_CARD";
			break;
		case SCARD_W_RESET_CARD:
			retval = "SCARD_W_RESET_CARD";
			break;
		case SCARD_W_REMOVED_CARD:
			retval = "SCARD_W_REMOVED_CARD";
			break;
		case SCARD_E_PCI_TOO_SMALL:
			retval = "SCARD_E_PCI_TOO_SMALL";
			break;
		case SCARD_E_READER_UNSUPPORTED:
			retval = "SCARD_E_READER_UNSUPPORTED";
			break;
		case SCARD_E_DUPLICATE_READER:
			retval = "SCARD_E_DUPLICATE_READER";
			break;
		case SCARD_E_CARD_UNSUPPORTED:
			retval = "SCARD_E_CARD_UNSUPPORTED";
			break;
		case SCARD_E_NO_SERVICE:
			retval = "SCARD_E_NO_SERVICE";
			break;
		case SCARD_E_SERVICE_STOPPED:
			retval = "SCARD_E_SERVICE_STOPPED";
			break;
		case SCARD_W_INSERTED_CARD:
			retval = "SCARD_W_INSERTED_CARD";
			break;
		case SCARD_E_UNSUPPORTED_FEATURE:
			retval = "SCARD_E_UNSUPPORTED_FEATURE";
			break;
	}

	if (retval == NULL) {
		retval = "UNKNOWN";
	}

	return(retval);
}

#  define malloc(x) CACKEY_DEBUG_FUNC_MALLOC(x, __func__)
#  define realloc(x, y) CACKEY_DEBUG_FUNC_REALLOC(x, y, __func__)
#else
#  define CACKEY_DEBUG_PRINTF(x...) /**/
#  define CACKEY_DEBUG_PRINTBUF(f, x, y) /**/
#  define CACKEY_DEBUG_PERROR(x) /**/
#  define CACKEY_DEBUG_FUNC_TAG_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(x) "DEBUG_DISABLED"
#endif

struct cackey_identity {
	CK_ATTRIBUTE *attributes;
	CK_ULONG attributes_count;
};

391
392
393
394
395
396
397



398
399
400
401
402

403
404
405
406
407
408
409
	int active;

	char *pcsc_reader;

	int pcsc_card_connected;
	SCARDHANDLE pcsc_card;
};




struct cackey_tlv_entity {
	uint8_t tag;
	size_t length;
	unsigned char *value_buf; /* Raw buffer */

};

/* CACKEY Global Handles */
static void *cackey_biglock = NULL;
static struct cackey_session cackey_sessions[128];
static struct cackey_slot cackey_slots[128];
static int cackey_initialized = 0;







>
>
>





>







504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
	int active;

	char *pcsc_reader;

	int pcsc_card_connected;
	SCARDHANDLE pcsc_card;
};

struct cackey_tlv_cardurl {
};

struct cackey_tlv_entity {
	uint8_t tag;
	size_t length;
	unsigned char *value_buf; /* Raw buffer */
	void *value;
};

/* CACKEY Global Handles */
static void *cackey_biglock = NULL;
static struct cackey_session cackey_sessions[128];
static struct cackey_slot cackey_slots[128];
static int cackey_initialized = 0;
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519

			return(-1);
		}

		CACKEY_DEBUG_PRINTF("SCardEstablishContext() called");
		scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, cackey_pcsc_handle);
		if (scard_est_context_ret != SCARD_S_SUCCESS) {
			CACKEY_DEBUG_PRINTF("Call to SCardEstablishContext failed (returned %li), returning in failure", (long) scard_est_context_ret);

			free(cackey_pcsc_handle);

			cackey_slots_disconnect_all();

			return(-1);
		}
	}

#ifdef HAVE_SCARDISVALIDCONTEXT
	CACKEY_DEBUG_PRINTF("SCardIsValidContext() called");
	scard_isvalid_ret = SCardIsValidContext(*cackey_pcsc_handle);
	if (scard_isvalid_ret != SCARD_S_SUCCESS) {
		CACKEY_DEBUG_PRINTF("Handle has become invalid (SCardIsValidContext = %li), trying to re-establish...", (long) scard_isvalid_ret);

		CACKEY_DEBUG_PRINTF("SCardEstablishContext() called");
		scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, cackey_pcsc_handle);
		if (scard_est_context_ret != SCARD_S_SUCCESS) {
			CACKEY_DEBUG_PRINTF("Call to SCardEstablishContext failed (returned %li), returning in failure", (long) scard_est_context_ret);

			free(cackey_pcsc_handle);

			cackey_slots_disconnect_all();

			return(-1);
		}







|













|




|







603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636

			return(-1);
		}

		CACKEY_DEBUG_PRINTF("SCardEstablishContext() called");
		scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, cackey_pcsc_handle);
		if (scard_est_context_ret != SCARD_S_SUCCESS) {
			CACKEY_DEBUG_PRINTF("Call to SCardEstablishContext failed (returned %s/%li), returning in failure", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_est_context_ret), (long) scard_est_context_ret);

			free(cackey_pcsc_handle);

			cackey_slots_disconnect_all();

			return(-1);
		}
	}

#ifdef HAVE_SCARDISVALIDCONTEXT
	CACKEY_DEBUG_PRINTF("SCardIsValidContext() called");
	scard_isvalid_ret = SCardIsValidContext(*cackey_pcsc_handle);
	if (scard_isvalid_ret != SCARD_S_SUCCESS) {
		CACKEY_DEBUG_PRINTF("Handle has become invalid (SCardIsValidContext = %s/%li), trying to re-establish...", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_isvalid_ret), (long) scard_isvalid_ret);

		CACKEY_DEBUG_PRINTF("SCardEstablishContext() called");
		scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, cackey_pcsc_handle);
		if (scard_est_context_ret != SCARD_S_SUCCESS) {
			CACKEY_DEBUG_PRINTF("Call to SCardEstablishContext failed (returned %s/%li), returning in failure", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_est_context_ret), (long) scard_est_context_ret);

			free(cackey_pcsc_handle);

			cackey_slots_disconnect_all();

			return(-1);
		}
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570

	/* 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, &slot->pcsc_card, &protocol);

		if (scard_conn_ret != SCARD_S_SUCCESS) {
			CACKEY_DEBUG_PRINTF("Connection to card failed, returning in failure (SCardConnect() = %li)", (long) scard_conn_ret);

			return(-1);
		}

		slot->pcsc_card_connected = 1;
	}








|







673
674
675
676
677
678
679
680
681
682
683
684
685
686
687

	/* 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, &slot->pcsc_card, &protocol);

		if (scard_conn_ret != SCARD_S_SUCCESS) {
			CACKEY_DEBUG_PRINTF("Connection to card failed, returning in failure (SCardConnect() = %s/%li)", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_conn_ret), (long) scard_conn_ret);

			return(-1);
		}

		slot->pcsc_card_connected = 1;
	}

586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
	}

	CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);

	recv_len = sizeof(recv_buf);
	scard_xmit_ret = SCardTransmit(slot->pcsc_card, SCARD_PCI_T0, xmit_buf, xmit_len, SCARD_PCI_T1, recv_buf, &recv_len);
	if (scard_xmit_ret != SCARD_S_SUCCESS) {
		CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %lx)", (unsigned long) scard_xmit_ret);

		if (scard_xmit_ret == SCARD_W_RESET_CARD) {
			CACKEY_DEBUG_PRINTF("Reset required, please hold...");

			scard_reconn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &protocol);
			if (scard_reconn_ret == SCARD_S_SUCCESS) {
				CACKEY_DEBUG_PRINTF("Reset successful, retransmitting");
				scard_xmit_ret = SCardTransmit(slot->pcsc_card, SCARD_PCI_T0, xmit_buf, xmit_len, SCARD_PCI_T0, recv_buf, &recv_len);

				if (scard_xmit_ret != SCARD_S_SUCCESS) {
					CACKEY_DEBUG_PRINTF("Retransmit failed, returning in failure after disconnecting the card");

					SCardDisconnect(slot->pcsc_card, SCARD_RESET_CARD);
					slot->pcsc_card_connected = 0;

					return(-1);
				}
			} else {







|










|







703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
	}

	CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);

	recv_len = sizeof(recv_buf);
	scard_xmit_ret = SCardTransmit(slot->pcsc_card, SCARD_PCI_T0, xmit_buf, xmit_len, SCARD_PCI_T1, recv_buf, &recv_len);
	if (scard_xmit_ret != SCARD_S_SUCCESS) {
		CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx)", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret);

		if (scard_xmit_ret == SCARD_W_RESET_CARD) {
			CACKEY_DEBUG_PRINTF("Reset required, please hold...");

			scard_reconn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &protocol);
			if (scard_reconn_ret == SCARD_S_SUCCESS) {
				CACKEY_DEBUG_PRINTF("Reset successful, retransmitting");
				scard_xmit_ret = SCardTransmit(slot->pcsc_card, SCARD_PCI_T0, xmit_buf, xmit_len, SCARD_PCI_T0, recv_buf, &recv_len);

				if (scard_xmit_ret != SCARD_S_SUCCESS) {
					CACKEY_DEBUG_PRINTF("Retransmit failed, returning in failure after disconnecting the card (SCardTransmit = %s/%li)", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (long) scard_xmit_ret);

					SCardDisconnect(slot->pcsc_card, SCARD_RESET_CARD);
					slot->pcsc_card_connected = 0;

					return(-1);
				}
			} else {
775
776
777
778
779
780
781






















782
783
784
785
786
787
788
		return(-1);
	}

	CACKEY_DEBUG_PRINTF("Successfully selected file");

	return(0);
}























static int cackey_read_tlv(struct cackey_slot *slot, int follow_url) {
	struct cackey_tlv_entity curr_entity;
	unsigned char tlen_buf[2], tval_buf[1024], *tval;
	unsigned char vlen_buf[2], vval_buf[8192], *vval;
	ssize_t tlen, vlen;
	ssize_t read_ret;







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







892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
		return(-1);
	}

	CACKEY_DEBUG_PRINTF("Successfully selected file");

	return(0);
}

static int cackey_select_file(struct cackey_slot *slot, uint16_t ef) {
	unsigned char fid_buf[2];
	int send_ret;

	CACKEY_DEBUG_PRINTF("Called");

	/* Open the elementary file */
	fid_buf[0] = (ef >> 8) & 0xff;
	fid_buf[1] = ef & 0xff;

	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_SELECT, 0x02, 0x0C, sizeof(fid_buf), fid_buf, 0x00, NULL, NULL, NULL);
	if (send_ret < 0) {
		CACKEY_DEBUG_PRINTF("Failed to open file, returning in failure");

		return(-1);
	}

	CACKEY_DEBUG_PRINTF("Successfully selected file");

	return(0);
}

static int cackey_read_tlv(struct cackey_slot *slot, int follow_url) {
	struct cackey_tlv_entity curr_entity;
	unsigned char tlen_buf[2], tval_buf[1024], *tval;
	unsigned char vlen_buf[2], vval_buf[8192], *vval;
	ssize_t tlen, vlen;
	ssize_t read_ret;
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915

					cackey_read_tlv(slot, 0);
				}
				break;
		}
	}

	return(0);
}

static int cackey_select_file(struct cackey_slot *slot, uint16_t ef) {
	unsigned char fid_buf[2];
	int send_ret;

	CACKEY_DEBUG_PRINTF("Called");

	/* Open the elementary file */
	fid_buf[0] = (ef >> 8) & 0xff;
	fid_buf[1] = ef & 0xff;

	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_SELECT, 0x02, 0x0C, sizeof(fid_buf), fid_buf, 0x00, NULL, NULL, NULL);
	if (send_ret < 0) {
		CACKEY_DEBUG_PRINTF("Failed to open file, returning in failure");

		return(-1);
	}

	CACKEY_DEBUG_PRINTF("Successfully selected file");

	return(0);
}

/* Returns 1 if a token is in the specified slot, 0 otherwise */
static int cackey_token_present(struct cackey_slot *slot) {
	unsigned char ccc_aid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00};
	int send_ret;







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







1019
1020
1021
1022
1023
1024
1025






















1026
1027
1028
1029
1030
1031
1032

					cackey_read_tlv(slot, 0);
				}
				break;
		}
	}























	return(0);
}

/* Returns 1 if a token is in the specified slot, 0 otherwise */
static int cackey_token_present(struct cackey_slot *slot) {
	unsigned char ccc_aid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00};
	int send_ret;
1596
1597
1598
1599
1600
1601
1602


1603
1604
1605


1606
1607
1608
1609
1610
1611
1612

					pcsc_readers += curr_reader_len + 1;
				}

				if (currslot > 0) {
					slot_count = currslot;
				}


			}

			free(pcsc_readers_s);


		}
	}

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








>
>



>
>







1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733

					pcsc_readers += curr_reader_len + 1;
				}

				if (currslot > 0) {
					slot_count = currslot;
				}
			} else {
				CACKEY_DEBUG_PRINTF("Second call to SCardListReaders failed, return %s/%li", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_listreaders_ret), (long) scard_listreaders_ret);
			}

			free(pcsc_readers_s);
		} else {
			CACKEY_DEBUG_PRINTF("First call to SCardListReaders failed, return %s/%li", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_listreaders_ret), (long) scard_listreaders_ret);
		}
	}

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