Check-in [3e5963d5d9]
Overview
Comment:Merged in PIV support
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:3e5963d5d9cfa5bcfef7407795b3db3653b6f021
User & Date: rkeene on 2013-10-17 20:29:39
Other Links: manifest | tags
Context
2013-10-17
20:32
CACKey 0.7.0 check-in: d6a874f3b5 user: rkeene tags: trunk, 0.7.0
20:29
Merged in PIV support check-in: 3e5963d5d9 user: rkeene tags: trunk
20:29
Updated to deal with 6E00 and added support for win32 build options check-in: 6ba1dff55a user: rkeene tags: piv
2013-08-14
04:40
Updated to allow compilation excluding DoD certificates check-in: b6863060d8 user: rkeene tags: trunk
Changes

Added build/ask-pass/cackey-askpass version [5c6636f8ba].

            1  +#! /usr/bin/env bash
            2  +
            3  +ZENITY="$(which 'zenity' 2>/dev/null)"
            4  +GDIALOG="$(which 'gdialog' 2>/dev/null)"
            5  +ASKPASS="$(which 'ssh-askpass' 'x11-ssh-askpass' '/usr/libexec/x11-ssh-askpass' 2>/dev/null | head -n 1)"
            6  +DIALOG="$(which 'dialog' 2>/dev/null)"
            7  +XTERM="$(which 'xterm' 2>/dev/null)"
            8  +
            9  +if [ -x "${ZENITY}" ]; then
           10  +	# XXX: TODO: Zenity
           11  +	true
           12  +fi
           13  +
           14  +if [ -x "${GDIALOG}" ]; then
           15  +	# XXX: TODO: Gdialog
           16  +	true
           17  +fi
           18  +
           19  +if [ -x "${ASKPASS}" ]; then
           20  +	exec "${ASKPASS}" "$@"
           21  +	exit 1
           22  +fi
           23  +
           24  +if [ -x "${DIALOG}" -a -x "${XTERM}" ]; then
           25  +	# XXX: TODO: dialog
           26  +	true
           27  +fi
           28  +
           29  +if [ -x "${XTERM}" ]; then
           30  +	# XXX: TODO: xterm
           31  +	true
           32  +fi
           33  +
           34  +exit 1

Added build/builtin-certs-update version [6d290a2094].

            1  +#! /bin/bash
            2  +
            3  +ourdir="$(dirname "$(which "$0")")"
            4  +cd "${outdir}" || exit 1
            5  +
            6  +make -C certs/dod distclean all
            7  +make -C certs/federal distclean all
            8  +
            9  +./certs-to-c certs/*/*.crt > ../cackey_builtin_certs.h

Modified build/cackey_osx_build/Template_pmbuild/index.xml.in from [e98adc8605] to [7d02eca4b2].

    30     30   {\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
    31     31   {\colortbl;\red255\green255\blue255;}
    32     32   \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
    33     33   
    34     34   \f0\fs26 \cf0 Release information:\
    35     35       pkg: CACKey\
    36     36    author: US Army Corps of Engineers\
    37         -Mac build contact: Kenneth Van Alstyne <kenneth.vanalstyne@hq.dhs.gov>\
           37  +Mac build contact: Kenneth Van Alstyne <DC1SAN_SUPPORT@hq.dhs.gov>\
    38     38                      US Department of Homeland Security\
    39         -contact: Roy Keene <roy.s.keene@usace.army.mil>\
           39  +contact: Roy Keene <DC1-UNIX@hq.dhs.gov>\
    40     40   ------------------------------------------------\
    41     41   \
    42     42   The PKCS11.tokend connector module included in this package is licensed under\
    43     43   the APSL. See: http://devel.kvanals.org/PKCS11_Tokend\
    44     44   \
    45     45   The following files in the source directory are the intellectual property of the\
    46     46   Free Software Foundation and are licensed under the terms of the GNU General\

Modified build/cackey_osx_build/build_osx.sh from [7f1f41f856] to [c66d1aadeb].

     1      1   #!/bin/bash
     2      2   # Shell Script to make Mac OS X Releases of CACKey
     3      3   # Kenneth Van Alstyne
     4         -# kenneth.vanalstyne@associates.hq.dhs.gov
            4  +# DC1SAN_SUPPORT@hq.dhs.gov
     5      5   CACKEY_VERSION=`cat configure.ac | grep AC_INIT | cut -d " " -f 2 | sed 's_)__'`
     6      6   
     7      7   # Check to see if we're building on Mac OS X 10.7 "Lion"
     8      8   if [ "`uname -r | cut -d . -f 1`" = "11" ]; then
     9      9   	LIONBUILD=1
    10     10   fi
    11     11   

Modified build/cackey_win32_build/build.sh from [716f40add4] to [fbfa3a5bbe].

     1      1   #! /bin/bash
     2      2   
     3      3   make distclean
     4      4   
     5         -./configure --with-pcsc-headers="$(pwd)/build/cackey_win32_build/include" --with-pcsc-libs="-L$(pwd)/build/cackey_win32_build/lib -lwinscard" --host=i586-mingw32msvc  CPPFLAGS="-I$(pwd)/build/cackey_win32_build/include" || exit 1
            5  +./configure --with-pcsc-headers="$(pwd)/build/cackey_win32_build/include" --with-pcsc-libs="-L$(pwd)/build/cackey_win32_build/lib -lwinscard" --host=i586-mingw32msvc  CPPFLAGS="-I$(pwd)/build/cackey_win32_build/include" "$@" || exit 1
     6      6   
     7      7   make || exit 1
     8      8   
     9      9   exit 0

Modified build/certs-to-c from [c49efbf6f1] to [1cd87f2aca].

     7      7   
     8      8   		continue
     9      9   	fi
    10     10   
    11     11   	openssl x509 -in "${file}" -out tmpfile.x509 -inform pem -outform der
    12     12   
    13     13   	pubkeylen="$(openssl x509 -in tmpfile.x509 -inform der -text -noout | grep 'RSA Public Key:' | sed 's@^.*(\([0-9][0-9]*\) bit).*$@\1@')"
    14         -	certlen="$(stat -c '%s' tmpfile.x509)"
           14  +	certlen="$(cat tmpfile.x509 | wc -c)"
    15     15   	cert="$(( cat tmpfile.x509 | od -t x1 | cut -c 9- | tr "\n" ' '; echo ) | sed 's@ @@g;s@..@\\x&@g')"
    16     16   
    17     17   	cat << _EOF_
    18     18   	{
    19         -		{0},
    20         -		0,
    21         -		${certlen},
    22         -		(unsigned char *) "${cert}",
    23         -		${pubkeylen}
           19  +		CACKEY_ID_TYPE_CERT_ONLY, /* id_type */
           20  +		${certlen}, /* certificate_len */
           21  +		(unsigned char *) "${cert}", /* certificate */
           22  +		${pubkeylen} /* keysize */
    24     23   	},
    25     24   _EOF_
    26     25   done
    27     26   
    28     27   rm -f tmpfile.x509

Added build/certs/dod/Makefile version [678511107e].

            1  +all: cert-0.crt
            2  +
            3  +rel3_dodroot_2048.cac:
            4  +	wget -O "$@.new" http://dodpki.c3pki.chamb.disa.mil/rel3_dodroot_2048.cac
            5  +	mv "$@.new" "$@"
            6  +
            7  +cert-%.crt: rel3_dodroot_2048.cac
            8  +	idx=0; \
            9  +	( \
           10  +		openssl pkcs7 -in rel3_dodroot_2048.cac -inform DER -print_certs -text; \
           11  +	) | while IFS='' read -r line; do \
           12  +		if [ -z "$${line}" ]; then \
           13  +			continue; \
           14  +		fi; \
           15  +		echo "$${line}" >> "cert-$${idx}.crt"; \
           16  +		if [ "$${line}" == "-----END CERTIFICATE-----" ]; then \
           17  +			idx=$$[$$idx + 1]; \
           18  +		fi; \
           19  +	done
           20  +
           21  +clean:
           22  +	rm -f cert-*.crt
           23  +	rm -f rel3_dodroot_2048.cac.new
           24  +
           25  +distclean: clean
           26  +	rm -f rel3_dodroot_2048.cac

Added build/certs/federal/Makefile version [7088ba1ceb].

            1  +all: cert-1.crt CPCA_TRCA.crt CommonPolicy.crt
            2  +	grep -l 'Issuer: C=US, O=U.S. Government, OU=FPKI, CN=Federal Bridge CA' *.crt | xargs rm -f
            3  +	grep -l 'Subject: C=US, O=U.S. Government, OU=FPKI, CN=Federal Common Policy CA' *.crt  | xargs grep -H 'Issuer:' | grep -v 'Issuer: C=us, O=U.S. Government, OU=FBCA, CN=Common Policy' | cut -f 1 -d : | xargs rm -f
            4  +
            5  +CPCA_TRCA.crt:
            6  +	wget -O - --no-check-certificate https://pki.treas.gov/CPCA_TRCA.cer | openssl x509 -text > "$@.new"
            7  +	mv "$@.new" "$@"
            8  +
            9  +caCertsIssuedTofcpca.p7c:
           10  +	wget -O "$@.new" http://http.fpki.gov/fcpca/caCertsIssuedTofcpca.p7c
           11  +	mv "$@.new" "$@"
           12  +
           13  +root_sia.p7b:
           14  +	wget -O "$@.new" --no-check-certificate https://pki.treas.gov/root_sia.p7b
           15  +	mv "$@.new" "$@"
           16  +
           17  +CommonPolicy.crt:
           18  +	wget -O - http://fpkia.gsa.gov/CommonPolicy/CommonPolicy.crt | openssl x509 -inform der -text > "$@.new"
           19  +	mv "$@.new" "$@"
           20  +
           21  +cert-%.crt: root_sia.p7b caCertsIssuedTofcpca.p7c
           22  +	idx=0; \
           23  +	( \
           24  +		openssl pkcs7 -in root_sia.p7b -inform DER -print_certs -text; \
           25  +		openssl pkcs7 -in caCertsIssuedTofcpca.p7c -inform DER -print_certs -text; \
           26  +	) | while IFS='' read -r line; do \
           27  +		if [ -z "$${line}" ]; then \
           28  +			continue; \
           29  +		fi; \
           30  +		echo "$${line}" >> "cert-$${idx}.crt"; \
           31  +		if [ "$${line}" == "-----END CERTIFICATE-----" ]; then \
           32  +			idx=$$[$$idx + 1]; \
           33  +		fi; \
           34  +	done
           35  +
           36  +clean:
           37  +	rm -f cert-*.crt
           38  +	rm -f CPCA_TRCA.crt.new root_sia.p7b.new caCertsIssuedTofcpca.p7c.new CommonPolicy.crt.new
           39  +
           40  +distclean: clean
           41  +	rm -f CPCA_TRCA.crt root_sia.p7b caCertsIssuedTofcpca.p7c CommonPolicy.crt

Modified cackey.c from [967c6f655f] to [e6fa629162].

   152    152   #define GSCIS_TAG_SERNO               0x51
   153    153   #define GSCIS_TAG_ISSUE_DATE          0x52
   154    154   #define GSCIS_TAG_EXPIRE_DATE         0x53
   155    155   #define GSCIS_TAG_CARD_TYPE           0x54
   156    156   #define GSCIS_TAG_SECURITY_CODE       0x57
   157    157   #define GSCIS_TAG_CARDID_AID          0x58
   158    158   
          159  +/*** PIV Codes ***/
          160  +#define NISTSP800_73_3_INSTR_GET_DATA 0xCB
          161  +#define NISTSP800_73_3_INSTR_GENAUTH  0x87
          162  +
   159    163   /*** PKI Information - EF 7000 ***/
   160    164   #define GSCIS_TAG_CERTIFICATE         0x70
   161    165   #define GSCIS_TAG_CERT_ISSUE_DATE     0x71
   162    166   #define GSCIS_TAG_CERT_EXPIRE_DATE    0x72
   163    167   
   164    168   /** Applet IDs **/
   165    169   #define GSCIS_AID_CCC                 0xA0, 0x00, 0x00, 0x01, 0x16, 0xDB, 0x00
          170  +#define NISTSP800_73_3_PIV_AID        0xA0, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00
          171  +
          172  +/* PIV IDs */
          173  +/** Key Identifiers (NIST SP 800-78-3, Table 6-1 **/
          174  +#define NISTSP800_78_3_KEY_PIVAUTH   0x9A
          175  +#define NISTSP800_78_3_KEY_SIGNATURE 0x9C
          176  +#define NISTSP800_78_3_KEY_KEYMGT    0x9D
          177  +#define NISTSP800_78_3_KEY_CARDAUTH  0x9E
          178  +
          179  +/** Algorithm Identifiers (NIST SP 800-78-3, Table 6-2 **/
          180  +#define NISTSP800_78_3_ALGO_RSA1024  0x06
          181  +#define NISTSP800_78_3_ALGO_RSA2048  0x07
          182  +
          183  +/** Object Identifiers (NIST SP 800-73-3 Part 1, Table 2) **/
          184  +#define NISTSP800_73_3_OID_PIVAUTH   0x5F, 0xC1, 0x05
          185  +#define NISTSP800_73_3_OID_SIGNATURE 0x5F, 0xC1, 0x0A
          186  +#define NISTSP800_73_3_OID_KEYMGT    0x5F, 0xC1, 0x0B
          187  +#define NISTSP800_73_3_OID_CARDAUTH  0x5F, 0xC1, 0x01
   166    188   
   167    189   /* Maximum size of data portion of APDUs */
   168    190   /** Do not set this above 250 **/
   169    191   #define CACKEY_APDU_MTU               250
   170    192   
   171    193   /* ATR If not available */
   172    194   #ifndef MAX_ATR_SIZE
................................................................................
   692    714   #  define CACKEY_DEBUG_FUNC_TAG_TO_STR(x) "DEBUG_DISABLED"
   693    715   #  define CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(x) "DEBUG_DISABLED"
   694    716   #  define CACKEY_DEBUG_FUNC_OBJID_TO_STR(x) "DEBUG_DISABLED"
   695    717   #  define CACKEY_DEBUG_FUNC_APPTYPE_TO_STR(x) "DEBUG_DISABLED"
   696    718   #  define CACKEY_DEBUG_FUNC_ATTRIBUTE_TO_STR(x) "DEBUG_DISABLED"
   697    719   #endif
   698    720   
          721  +typedef enum {
          722  +	CACKEY_ID_TYPE_CAC,
          723  +	CACKEY_ID_TYPE_PIV,
          724  +	CACKEY_ID_TYPE_CERT_ONLY
          725  +} cackey_pcsc_id_type;
          726  +
   699    727   struct cackey_pcsc_identity {
   700         -	unsigned char applet[7];
   701         -	uint16_t file;
          728  +	cackey_pcsc_id_type id_type;
   702    729   
   703    730   	size_t certificate_len;
   704    731   	unsigned char *certificate;
   705    732   
   706    733   	ssize_t keysize;
          734  +
          735  +	union {
          736  +		struct {
          737  +			unsigned char applet[7];
          738  +			uint16_t file;
          739  +		} cac;
          740  +
          741  +		struct {
          742  +			unsigned char key_id;
          743  +			char label[32];
          744  +		} piv;
          745  +	} card;
   707    746   };
   708    747   
   709    748   struct cackey_identity {
   710    749   	struct cackey_pcsc_identity *pcsc_identity;
   711    750   
   712    751   	CK_ATTRIBUTE *attributes;
   713    752   	CK_ULONG attributes_count;
................................................................................
   832    871   static int cackey_biglock_init = 0;
   833    872   CK_C_INITIALIZE_ARGS cackey_args;
   834    873   
   835    874   /** Extra certificates to include in token **/
   836    875   struct cackey_pcsc_identity extra_certs[] = {
   837    876   #include "cackey_builtin_certs.h"
   838    877   };
          878  +
          879  +/* Protected Authentication Path command */
          880  +#define CACKEY_PIN_COMMAND_DEFAULT_XSTR(str) CACKEY_PIN_COMMAND_DEFAULT_STR(str)
          881  +#define CACKEY_PIN_COMMAND_DEFAULT_STR(str) #str
          882  +static char *cackey_pin_command = NULL;
   839    883   
   840    884   /* PCSC Global Handles */
   841    885   static LPSCARDCONTEXT cackey_pcsc_handle = NULL;
   842    886   
   843    887   static unsigned long cackey_getversion(void) {
   844    888   	static unsigned long retval = 255;
   845    889   	unsigned long major = 0;
................................................................................
  1201   1245   
  1202   1246   		slot->pcsc_card_connected = 1;
  1203   1247   		slot->transaction_depth = 0;
  1204   1248   		slot->transaction_need_hw_lock = 0;
  1205   1249   		slot->protocol = protocol;
  1206   1250   	}
  1207   1251   
         1252  +	CACKEY_DEBUG_PRINTF("Returning in success");
         1253  +
  1208   1254   	return(CACKEY_PCSC_S_OK);
  1209   1255   }
  1210   1256   
  1211   1257   /*
  1212   1258    * SYNPOSIS
  1213   1259    *     cackey_ret cackey_begin_transaction(struct cackey_slot *slot);
  1214   1260    *
................................................................................
  1387   1433    *     cackey_pcsc_connect() if needed.
  1388   1434    *
  1389   1435    *     It will connect to the card in the reader attached to the slot
  1390   1436    *     specified.  It will reconnect to the card if the connection
  1391   1437    *     goes away.
  1392   1438    *
  1393   1439    */
  1394         -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) {
         1440  +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) {
  1395   1441   	uint8_t major_rc, minor_rc;
  1396   1442   	size_t bytes_to_copy, tmp_respdata_len;
  1397   1443   	LPCSCARD_IO_REQUEST pioSendPci;
  1398   1444   	DWORD protocol;
  1399   1445   	DWORD xmit_len, recv_len;
  1400   1446   	LONG scard_xmit_ret, scard_reconn_ret;
  1401   1447   	BYTE xmit_buf[1024], recv_buf[1024];
................................................................................
  1416   1462   
  1417   1463   		return(CACKEY_PCSC_E_GENERIC);
  1418   1464   	}
  1419   1465   
  1420   1466   	/* Determine which protocol to send using */
  1421   1467   	switch (slot->protocol) {
  1422   1468   		case SCARD_PROTOCOL_T0:
         1469  +			CACKEY_DEBUG_PRINTF("Protocol to send datagram is T=0");
         1470  +
  1423   1471   			pioSendPci = SCARD_PCI_T0;
  1424   1472   
  1425   1473   			break;
  1426   1474   		case SCARD_PROTOCOL_T1:
         1475  +			CACKEY_DEBUG_PRINTF("Protocol to send datagram is T=1");
         1476  +
  1427   1477   			pioSendPci = SCARD_PCI_T1;
  1428   1478   
  1429   1479   			break;
  1430   1480   		default:
  1431   1481   			CACKEY_DEBUG_PRINTF("Invalid protocol found, aborting.");
  1432   1482   
  1433   1483   			return(CACKEY_PCSC_E_GENERIC);
................................................................................
  1436   1486   	/* Transmit */
  1437   1487   	xmit_len = 0;
  1438   1488   	xmit_buf[xmit_len++] = class;
  1439   1489   	xmit_buf[xmit_len++] = instruction;
  1440   1490   	xmit_buf[xmit_len++] = p1;
  1441   1491   	xmit_buf[xmit_len++] = p2;
  1442   1492   	if (data) {
  1443         -		xmit_buf[xmit_len++] = lc;
         1493  +		if (lc > 255) {
         1494  +			CACKEY_DEBUG_PRINTF("CAUTION!  Using an Lc greater than 255 is untested.  Lc = %u", lc);
         1495  +
         1496  +			xmit_buf[xmit_len++] = 0x82; /* XXX UNTESTED */
         1497  +			xmit_buf[xmit_len++] = (lc & 0xff00) >> 8;
         1498  +			xmit_buf[xmit_len++] = lc & 0xff;
         1499  +		} else {
         1500  +			xmit_buf[xmit_len++] = lc;
         1501  +		}
  1444   1502   		for (idx = 0; idx < lc; idx++) {
  1445   1503   			xmit_buf[xmit_len++] = data[idx];
  1446   1504   		}
  1447   1505   	}
  1448   1506   
  1449   1507   	if (le != 0x00) {
  1450         -		xmit_buf[xmit_len++] = le;
         1508  +		if (le > 256) {
         1509  +			CACKEY_DEBUG_PRINTF("CAUTION!  Using an Le greater than 256 is untested.  Le = %u", le);
         1510  +
         1511  +			xmit_buf[xmit_len++] = 0x82; /* XXX UNTESTED */
         1512  +			xmit_buf[xmit_len++] = (le & 0xff00) >> 8;
         1513  +			xmit_buf[xmit_len++] = le & 0xff;
         1514  +		} else if (le == 256) {
         1515  +			xmit_buf[xmit_len++] = 0x00;
         1516  +		} else {
         1517  +			xmit_buf[xmit_len++] = le;
         1518  +		}
  1451   1519   	}
  1452   1520   
  1453   1521   	/* Begin Smartcard Transaction */
  1454   1522   	cackey_begin_transaction(slot);
  1455   1523   
  1456         -	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00 && p2 == 0x00) {
         1524  +	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00) {
  1457   1525   		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
  1458   1526   	} else {
  1459   1527   		CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);
  1460   1528   	}
  1461   1529   
  1462   1530   	recv_len = sizeof(recv_buf);
  1463   1531   	scard_xmit_ret = SCardTransmit(slot->pcsc_card, pioSendPci, xmit_buf, xmit_len, NULL, recv_buf, &recv_len);
................................................................................
  1643   1711   	}
  1644   1712   
  1645   1713   
  1646   1714   	CACKEY_DEBUG_PRINTF("APDU Returned an error, returning in failure");
  1647   1715   
  1648   1716   	return(CACKEY_PCSC_E_GENERIC);
  1649   1717   }
         1718  +
         1719  +static unsigned char *cackey_read_bertlv_tag(unsigned char *buffer, size_t *buffer_len_p, unsigned char tag, unsigned char *outbuffer, size_t *outbuffer_len_p) {
         1720  +	unsigned char *buffer_p;
         1721  +	size_t outbuffer_len, buffer_len;
         1722  +	size_t size;
         1723  +	int idx;
         1724  +
         1725  +	CACKEY_DEBUG_PRINTF("Called.");
         1726  +
         1727  +	if (buffer_len_p == NULL) {
         1728  +		CACKEY_DEBUG_PRINTF("buffer_len_p is NULL.  Returning in failure.");
         1729  +
         1730  +		return(NULL);
         1731  +	}
         1732  +
         1733  +	if (outbuffer_len_p == NULL) {
         1734  +		CACKEY_DEBUG_PRINTF("outbuffer_len_p is NULL.  Returning in failure.");
         1735  +
         1736  +		return(NULL);
         1737  +	}
         1738  +
         1739  +	buffer_len = *outbuffer_len_p;
         1740  +	outbuffer_len = *outbuffer_len_p;
         1741  +
         1742  +	buffer_p = buffer;
         1743  +	if (buffer_p[0] != tag) {
         1744  +		CACKEY_DEBUG_PRINTF("Tag found was not tag expected.  Tag = %02x, Expected = %02x.  Returning in failure.", (unsigned int) buffer_p[0], tag);
         1745  +
         1746  +		return(NULL);
         1747  +	}
         1748  +
         1749  +	buffer_p++;
         1750  +	buffer_len--;
         1751  +
         1752  +	if ((buffer_p[0] & 0x80) == 0x80) {
         1753  +		size = 0;
         1754  +		idx = (buffer_p[0] & 0x7f);
         1755  +
         1756  +		if (idx > buffer_len) {
         1757  +			CACKEY_DEBUG_PRINTF("Malformed BER value -- not enough bytes available to read length (idx = %i, buffer_len = %lu)", idx, (unsigned long) buffer_len);
         1758  +
         1759  +			return(NULL);
         1760  +		}
         1761  +
         1762  +		for (; idx > 0; idx--) {
         1763  +			buffer_p++;
         1764  +			buffer_len--;
         1765  +
         1766  +			size <<= 8;
         1767  +			size |= buffer_p[0];
         1768  +		}
         1769  +	} else {
         1770  +		size = buffer_p[0];
         1771  +	}
         1772  +
         1773  +	buffer_p++;
         1774  +	buffer_len--;
         1775  +
         1776  +	if (size > outbuffer_len) {
         1777  +		CACKEY_DEBUG_PRINTF("Unable to copy value buffer to outbuffer, not enough room.  Value buffer length = %lu, out buffer length = %lu", (unsigned long) size, (unsigned long) outbuffer_len);
         1778  +
         1779  +		return(NULL);
         1780  +	}
         1781  +
         1782  +	*outbuffer_len_p = size;
         1783  +	if (outbuffer) {
         1784  +		memcpy(outbuffer, buffer_p, size);
         1785  +		buffer_p += size;
         1786  +		buffer_len -= size;
         1787  +
         1788  +		*buffer_len_p = buffer_len;
         1789  +
         1790  +		CACKEY_DEBUG_PRINTBUF("BER-TLV results:", outbuffer, size);
         1791  +	} else {
         1792  +		memmove(buffer, buffer_p, size);
         1793  +		buffer_p = buffer;
         1794  +
         1795  +		CACKEY_DEBUG_PRINTBUF("BER-TLV results:", buffer, size);
         1796  +	}
         1797  +
         1798  +	CACKEY_DEBUG_PRINTF("Returning in success.  Size of contents for tag %02x is %lu", (unsigned int) tag, (unsigned long) size);
         1799  +
         1800  +	return(buffer_p);
         1801  +}
         1802  +
         1803  +/*
         1804  + * SYNPOSIS
         1805  + *     ssize_t cackey_get_data(struct cackey_slot *slot, unsigned char *buffer, size_t buffer_len, unsigned char oid[3]);
         1806  + *
         1807  + * ARGUMENTS
         1808  + *     struct cackey_slot *slot
         1809  + *         Slot to send commands to
         1810  + *
         1811  + *     unsigned char *buffer
         1812  + *         [OUT] Buffer
         1813  + *
         1814  + *     size_t buffer_len
         1815  + *         Number of bytes to attempt to read
         1816  + *
         1817  + *     unsigned char oid[3]
         1818  + *         3-byte OID to read
         1819  + *
         1820  + *
         1821  + * RETURN VALUE
         1822  + *     This function returns the number of bytes actually read, or -1 on error.
         1823  + *
         1824  + * NOTES
         1825  + *     None
         1826  + *
         1827  + */
         1828  +static ssize_t cackey_get_data(struct cackey_slot *slot, unsigned char *buffer, size_t buffer_len, unsigned char oid[3]) {
         1829  +	unsigned char cmd[] = {0x5C, 0x03, 0x00, 0x00, 0x00};
         1830  +	unsigned char *buffer_p;
         1831  +	size_t init_buffer_len, size;
         1832  +	uint16_t respcode;
         1833  +	int send_ret;
         1834  +
         1835  +	CACKEY_DEBUG_PRINTF("Called.");
         1836  +
         1837  +	init_buffer_len = buffer_len;
         1838  +
         1839  +	cmd[2] = oid[0];
         1840  +	cmd[3] = oid[1];
         1841  +	cmd[4] = oid[2];
         1842  +
         1843  +	/* 256 to indicate the largest message size -- not clear if this will work with all messages */
         1844  +	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, NISTSP800_73_3_INSTR_GET_DATA, 0x3F, 0xFF, sizeof(cmd), cmd, 256, &respcode, buffer, &buffer_len);
         1845  +
         1846  +	if (send_ret == CACKEY_PCSC_E_RETRY) {
         1847  +		CACKEY_DEBUG_PRINTF("ADPU Sending failed, retrying read buffer");
         1848  +
         1849  +		return(cackey_get_data(slot, buffer, init_buffer_len, oid));
         1850  +	}
         1851  +
         1852  +	if (send_ret != CACKEY_PCSC_S_OK) {
         1853  +		CACKEY_DEBUG_PRINTF("cackey_send_apdu() failed, returning in failure");
         1854  +
         1855  +		return(-1);
         1856  +	}
         1857  +
         1858  +#ifdef CACKEY_PARANOID
         1859  +#  ifdef _POSIX_SSIZE_MAX
         1860  +	if (buffer_len > _POSIX_SSIZE_MAX) {
         1861  +		CACKEY_DEBUG_PRINTF("Read bytes (buffer_len) exceeds maximum value, returning in failure. (max = %li, buffer_len = %lu)", (long) _POSIX_SSIZE_MAX, (unsigned long) buffer_len);
         1862  +
         1863  +		return(-1);
         1864  +	}
         1865  +#  endif
         1866  +#endif
         1867  +
         1868  +	if (buffer_len < 2) {
         1869  +		CACKEY_DEBUG_PRINTF("APDU GET DATA returned %lu bytes, which is too short for a BER-TLV response", (unsigned long) buffer_len);
         1870  +
         1871  +		return(-1);
         1872  +	}
         1873  +
         1874  +	size = buffer_len;
         1875  +	buffer_p = cackey_read_bertlv_tag(buffer, &buffer_len, 0x53, NULL, &size);
         1876  +
         1877  +	if (buffer_p == NULL) {
         1878  +		CACKEY_DEBUG_PRINTF("Tag decoding failed, returning in error.");
         1879  +
         1880  +		return(-1);
         1881  +	}
         1882  +
         1883  +	CACKEY_DEBUG_PRINTBUF("GET DATA result", buffer, size);
         1884  +
         1885  +	CACKEY_DEBUG_PRINTF("Returning in success, read %lu bytes", (unsigned long) size);
         1886  +
         1887  +	return(size);
         1888  +}
  1650   1889   
  1651   1890   /*
  1652   1891    * SYNPOSIS
  1653   1892    *     ssize_t cackey_read_buffer(struct cackey_slot *slot, unsigned char *buffer, size_t count, unsigned char t_or_v, size_t initial_offset);
  1654   1893    *
  1655   1894    * ARGUMENTS
  1656   1895    *     struct cackey_slot *slot
................................................................................
  2133   2372   	}
  2134   2373   
  2135   2374   	if (dest == NULL) {
  2136   2375   		dest = malloc(sizeof(*dest) * count);
  2137   2376   	}
  2138   2377   
  2139   2378   	for (idx = 0; idx < count; idx++) {
  2140         -		memcpy(dest[idx].applet, start[idx].applet, sizeof(dest[idx].applet));
  2141         -		dest[idx].file = start[idx].file;
         2379  +		dest[idx].id_type = start[idx].id_type;
         2380  +
         2381  +		switch (dest[idx].id_type) {
         2382  +			case CACKEY_ID_TYPE_CAC:
         2383  +				memcpy(dest[idx].card.cac.applet, start[idx].card.cac.applet, sizeof(dest[idx].card.cac.applet));
         2384  +				dest[idx].card.cac.file = start[idx].card.cac.file;
         2385  +				break;
         2386  +			case CACKEY_ID_TYPE_PIV:
         2387  +				dest[idx].card.piv.key_id = start[idx].card.piv.key_id;
         2388  +				memcpy(dest[idx].card.piv.label, start[idx].card.piv.label, sizeof(dest[idx].card.piv.label));
         2389  +				break;
         2390  +			case CACKEY_ID_TYPE_CERT_ONLY:
         2391  +				break;
         2392  +		}
  2142   2393   		dest[idx].certificate_len = start[idx].certificate_len;
  2143   2394   		dest[idx].keysize = start[idx].keysize;
  2144   2395   
  2145   2396   		dest[idx].certificate = malloc(dest[idx].certificate_len);
  2146   2397   		memcpy(dest[idx].certificate, start[idx].certificate, dest[idx].certificate_len);
  2147   2398   	}
  2148   2399   
................................................................................
  2162   2413    * NOTES
  2163   2414    *     ...
  2164   2415    *
  2165   2416    */
  2166   2417   static struct cackey_pcsc_identity *cackey_read_certs(struct cackey_slot *slot, struct cackey_pcsc_identity *certs, unsigned long *count) {
  2167   2418   	struct cackey_pcsc_identity *curr_id;
  2168   2419   	struct cackey_tlv_entity *ccc_tlv, *ccc_curr, *app_tlv, *app_curr;
  2169         -	unsigned char ccc_aid[] = {GSCIS_AID_CCC};
         2420  +	unsigned char ccc_aid[] = {GSCIS_AID_CCC}, piv_aid[] = {NISTSP800_73_3_PIV_AID};
         2421  +	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};
  2170   2422   	unsigned char curr_aid[7];
         2423  +	unsigned char buffer[8192], *buffer_p;
  2171   2424   	unsigned long outidx = 0;
         2425  +	char *piv_label;
  2172   2426   	cackey_ret transaction_ret;
         2427  +	ssize_t read_ret;
         2428  +	size_t buffer_len;
  2173   2429   	int certs_resizable;
  2174   2430   	int send_ret, select_ret;
         2431  +	int piv_key, piv = 0;
         2432  +	int idx;
  2175   2433   
  2176   2434   	CACKEY_DEBUG_PRINTF("Called.");
  2177   2435   
  2178   2436   	if (count == NULL) {
  2179   2437   		CACKEY_DEBUG_PRINTF("count is NULL, returning in failure");
  2180   2438   
  2181   2439   		return(NULL);
................................................................................
  2190   2448   	}
  2191   2449   
  2192   2450   	if (!slot->slot_reset) {
  2193   2451   		if (slot->cached_certs) {
  2194   2452   			if (certs == NULL) {
  2195   2453   				certs = malloc(sizeof(*certs) * slot->cached_certs_count);
  2196   2454   				*count = slot->cached_certs_count;
  2197         -
  2198   2455   			} else {
  2199   2456   				if (*count > slot->cached_certs_count) {
  2200   2457   					*count = slot->cached_certs_count;
  2201   2458   				}
  2202   2459   			}
  2203   2460   
  2204   2461   			cackey_copy_certs(certs, slot->cached_certs, *count);
................................................................................
  2228   2485   	} else {
  2229   2486   		certs_resizable = 0;
  2230   2487   	}
  2231   2488   
  2232   2489   	/* Select the CCC Applet */
  2233   2490   	send_ret = cackey_select_applet(slot, ccc_aid, sizeof(ccc_aid));
  2234   2491   	if (send_ret != CACKEY_PCSC_S_OK) {
  2235         -		CACKEY_DEBUG_PRINTF("Unable to select CCC Applet, returning in failure");
  2236         -
  2237         -		/* Terminate SmartCard Transaction */
  2238         -		cackey_end_transaction(slot);
  2239         -
  2240         -		return(NULL);
  2241         -	}
  2242         -
  2243         -	/* Read all the applets from the CCC's TLV */
  2244         -	ccc_tlv = cackey_read_tlv(slot);
  2245         -
  2246         -	/* Look for CARDURLs that coorespond to PKI applets */
  2247         -	for (ccc_curr = ccc_tlv; ccc_curr; ccc_curr = ccc_curr->_next) {
  2248         -		CACKEY_DEBUG_PRINTF("Found tag: %s ... ", CACKEY_DEBUG_FUNC_TAG_TO_STR(ccc_curr->tag));
  2249         -
  2250         -		if (ccc_curr->tag != GSCIS_TAG_CARDURL) {
  2251         -			CACKEY_DEBUG_PRINTF("  ... skipping it (we only care about CARDURLs)");
  2252         -
  2253         -			continue;
  2254         -		}
  2255         -
  2256         -		if ((ccc_curr->value_cardurl->apptype & CACKEY_TLV_APP_PKI) != CACKEY_TLV_APP_PKI) {
  2257         -			CACKEY_DEBUG_PRINTF("  ... skipping it (we only care about PKI applets, this applet supports: %s/%02x)", CACKEY_DEBUG_FUNC_APPTYPE_TO_STR(ccc_curr->value_cardurl->apptype), (unsigned int) ccc_curr->value_cardurl->apptype);
  2258         -
  2259         -			continue;
  2260         -		}
  2261         -
  2262         -		CACKEY_DEBUG_PRINTBUF("RID:", ccc_curr->value_cardurl->rid, sizeof(ccc_curr->value_cardurl->rid));
  2263         -		CACKEY_DEBUG_PRINTF("AppID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(ccc_curr->value_cardurl->appid), (unsigned long) ccc_curr->value_cardurl->appid);
  2264         -		CACKEY_DEBUG_PRINTF("ObjectID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(ccc_curr->value_cardurl->objectid), (unsigned long) ccc_curr->value_cardurl->objectid);
  2265         -
  2266         -		memcpy(curr_aid, ccc_curr->value_cardurl->rid, sizeof(ccc_curr->value_cardurl->rid));
  2267         -		curr_aid[sizeof(curr_aid) - 2] = (ccc_curr->value_cardurl->appid >> 8) & 0xff;
  2268         -		curr_aid[sizeof(curr_aid) - 1] = ccc_curr->value_cardurl->appid & 0xff;
  2269         -
  2270         -		/* Select found applet ... */
  2271         -		select_ret = cackey_select_applet(slot, curr_aid, sizeof(curr_aid));
  2272         -		if (select_ret != CACKEY_PCSC_S_OK) {
  2273         -			CACKEY_DEBUG_PRINTF("Failed to select applet, skipping processing of this object");
  2274         -
  2275         -			continue;
  2276         -		}
  2277         -
  2278         -		/* ... and object (file) */
  2279         -		select_ret = cackey_select_file(slot, ccc_curr->value_cardurl->objectid);
  2280         -		if (select_ret != CACKEY_PCSC_S_OK) {
  2281         -			CACKEY_DEBUG_PRINTF("Failed to select file, skipping processing of this object");
  2282         -
  2283         -			continue;
  2284         -		}
  2285         -
  2286         -		/* Process this file's TLV looking for certificates */
  2287         -		app_tlv = cackey_read_tlv(slot);
  2288         -
  2289         -		for (app_curr = app_tlv; app_curr; app_curr = app_curr->_next) {
  2290         -			CACKEY_DEBUG_PRINTF("Found tag: %s", CACKEY_DEBUG_FUNC_TAG_TO_STR(app_curr->tag));
  2291         -			if (app_curr->tag != GSCIS_TAG_CERTIFICATE) {
  2292         -				CACKEY_DEBUG_PRINTF("  ... skipping it (we only care about CERTIFICATEs)");
  2293         -
         2492  +		/* Try PIV application */
         2493  +		send_ret = cackey_select_applet(slot, piv_aid, sizeof(piv_aid));
         2494  +		if (send_ret == CACKEY_PCSC_S_OK) {
         2495  +			CACKEY_DEBUG_PRINTF("We have a PIV card -- not using the CCC, pulling pre-selected keys");
         2496  +
         2497  +			piv = 1;
         2498  +		} else {
         2499  +			CACKEY_DEBUG_PRINTF("Unable to select CCC Applet, returning in failure");
         2500  +
         2501  +			/* Terminate SmartCard Transaction */
         2502  +			cackey_end_transaction(slot);
         2503  +
         2504  +			return(NULL);
         2505  +		}
         2506  +	}
         2507  +
         2508  +	if (piv) {
         2509  +		for (idx = 0; idx < 3; idx++) {
         2510  +			switch (idx) {
         2511  +				case 0:
         2512  +					piv_oid = piv_oid_pivauth;
         2513  +					piv_key = NISTSP800_78_3_KEY_PIVAUTH;
         2514  +					piv_label = "Authentication";
         2515  +					break;
         2516  +				case 1:
         2517  +					piv_oid = piv_oid_signature;
         2518  +					piv_key = NISTSP800_78_3_KEY_SIGNATURE;
         2519  +					piv_label = "Signature";
         2520  +					break;
         2521  +				case 2:
         2522  +					piv_oid = piv_oid_keymgt;
         2523  +					piv_key = NISTSP800_78_3_KEY_KEYMGT;
         2524  +					piv_label = "Key Management";
         2525  +					break;
         2526  +			}
         2527  +
         2528  +			read_ret = cackey_get_data(slot, buffer, sizeof(buffer), piv_oid);
         2529  +
         2530  +			if (read_ret <= 0) {
  2294   2531   				continue;
  2295   2532   			}
  2296   2533   
  2297   2534   			curr_id = &certs[outidx];
  2298   2535   			outidx++;
  2299   2536   
  2300         -			memcpy(curr_id->applet, curr_aid, sizeof(curr_id->applet));
  2301         -			curr_id->file = ccc_curr->value_cardurl->objectid;
  2302   2537   			curr_id->keysize = -1;
         2538  +			curr_id->id_type = CACKEY_ID_TYPE_PIV;
         2539  +			curr_id->card.piv.key_id = piv_key;
         2540  +			memcpy(curr_id->card.piv.label, piv_label, strlen(piv_label) + 1);
  2303   2541   
  2304         -			CACKEY_DEBUG_PRINTF("Filling curr_id->applet (%p) with %lu bytes:", curr_id->applet, (unsigned long) sizeof(curr_id->applet));
  2305         -			CACKEY_DEBUG_PRINTBUF("VAL:", curr_id->applet, sizeof(curr_id->applet));
  2306         -
  2307         -			curr_id->certificate_len = app_curr->length;
  2308         -
         2542  +			curr_id->certificate_len = read_ret;
  2309   2543   			curr_id->certificate = malloc(curr_id->certificate_len);
  2310         -			memcpy(curr_id->certificate, app_curr->value, curr_id->certificate_len);
         2544  +
         2545  +			buffer_len = sizeof(buffer);
         2546  +			buffer_p = cackey_read_bertlv_tag(buffer, &buffer_len, 0x70, curr_id->certificate, &curr_id->certificate_len);
         2547  +
         2548  +			if (buffer_p == NULL) {
         2549  +				CACKEY_DEBUG_PRINTF("Reading certificate from BER-TLV response failed, skipping key %i", idx);
         2550  +				free(curr_id->certificate);
         2551  +
         2552  +				outidx--;
         2553  +
         2554  +				continue;
         2555  +			}
         2556  +		}
         2557  +	} else {
         2558  +		/* Read all the applets from the CCC's TLV */
         2559  +		ccc_tlv = cackey_read_tlv(slot);
         2560  +
         2561  +		/* Look for CARDURLs that coorespond to PKI applets */
         2562  +		for (ccc_curr = ccc_tlv; ccc_curr; ccc_curr = ccc_curr->_next) {
         2563  +			CACKEY_DEBUG_PRINTF("Found tag: %s ... ", CACKEY_DEBUG_FUNC_TAG_TO_STR(ccc_curr->tag));
         2564  +
         2565  +			if (ccc_curr->tag != GSCIS_TAG_CARDURL) {
         2566  +				CACKEY_DEBUG_PRINTF("  ... skipping it (we only care about CARDURLs)");
         2567  +
         2568  +				continue;
         2569  +			}
         2570  +
         2571  +			if ((ccc_curr->value_cardurl->apptype & CACKEY_TLV_APP_PKI) != CACKEY_TLV_APP_PKI) {
         2572  +				CACKEY_DEBUG_PRINTF("  ... skipping it (we only care about PKI applets, this applet supports: %s/%02x)", CACKEY_DEBUG_FUNC_APPTYPE_TO_STR(ccc_curr->value_cardurl->apptype), (unsigned int) ccc_curr->value_cardurl->apptype);
         2573  +
         2574  +				continue;
         2575  +			}
         2576  +
         2577  +			CACKEY_DEBUG_PRINTBUF("RID:", ccc_curr->value_cardurl->rid, sizeof(ccc_curr->value_cardurl->rid));
         2578  +			CACKEY_DEBUG_PRINTF("AppID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(ccc_curr->value_cardurl->appid), (unsigned long) ccc_curr->value_cardurl->appid);
         2579  +			CACKEY_DEBUG_PRINTF("ObjectID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(ccc_curr->value_cardurl->objectid), (unsigned long) ccc_curr->value_cardurl->objectid);
         2580  +
         2581  +			memcpy(curr_aid, ccc_curr->value_cardurl->rid, sizeof(ccc_curr->value_cardurl->rid));
         2582  +			curr_aid[sizeof(curr_aid) - 2] = (ccc_curr->value_cardurl->appid >> 8) & 0xff;
         2583  +			curr_aid[sizeof(curr_aid) - 1] = ccc_curr->value_cardurl->appid & 0xff;
         2584  +
         2585  +			/* Select found applet ... */
         2586  +			select_ret = cackey_select_applet(slot, curr_aid, sizeof(curr_aid));
         2587  +			if (select_ret != CACKEY_PCSC_S_OK) {
         2588  +				CACKEY_DEBUG_PRINTF("Failed to select applet, skipping processing of this object");
         2589  +
         2590  +				continue;
         2591  +			}
         2592  +
         2593  +			/* ... and object (file) */
         2594  +			select_ret = cackey_select_file(slot, ccc_curr->value_cardurl->objectid);
         2595  +			if (select_ret != CACKEY_PCSC_S_OK) {
         2596  +				CACKEY_DEBUG_PRINTF("Failed to select file, skipping processing of this object");
         2597  +
         2598  +				continue;
         2599  +			}
         2600  +
         2601  +			/* Process this file's TLV looking for certificates */
         2602  +			app_tlv = cackey_read_tlv(slot);
         2603  +	
         2604  +			for (app_curr = app_tlv; app_curr; app_curr = app_curr->_next) {
         2605  +				CACKEY_DEBUG_PRINTF("Found tag: %s", CACKEY_DEBUG_FUNC_TAG_TO_STR(app_curr->tag));
         2606  +				if (app_curr->tag != GSCIS_TAG_CERTIFICATE) {
         2607  +					CACKEY_DEBUG_PRINTF("  ... skipping it (we only care about CERTIFICATEs)");
         2608  +
         2609  +					continue;
         2610  +				}
         2611  +
         2612  +				curr_id = &certs[outidx];
         2613  +				outidx++;
         2614  +
         2615  +				curr_id->id_type = CACKEY_ID_TYPE_CAC;
         2616  +				memcpy(curr_id->card.cac.applet, curr_aid, sizeof(curr_id->card.cac.applet));
         2617  +				curr_id->card.cac.file = ccc_curr->value_cardurl->objectid;
         2618  +				curr_id->keysize = -1;
         2619  +
         2620  +				CACKEY_DEBUG_PRINTF("Filling curr_id->card.cac.applet (%p) with %lu bytes:", curr_id->card.cac.applet, (unsigned long) sizeof(curr_id->card.cac.applet));
         2621  +				CACKEY_DEBUG_PRINTBUF("VAL:", curr_id->card.cac.applet, sizeof(curr_id->card.cac.applet));
         2622  +
         2623  +				curr_id->certificate_len = app_curr->length;
         2624  +
         2625  +				curr_id->certificate = malloc(curr_id->certificate_len);
         2626  +				memcpy(curr_id->certificate, app_curr->value, curr_id->certificate_len);
         2627  +
         2628  +				if (outidx >= *count) {
         2629  +					if (certs_resizable) {
         2630  +						*count *= 2;
         2631  +						certs = realloc(certs, sizeof(*certs) * (*count));
         2632  +					} else {
         2633  +						break;
         2634  +					}
         2635  +				}
         2636  +			}
         2637  +
         2638  +			cackey_free_tlv(app_tlv);
  2311   2639   
  2312   2640   			if (outidx >= *count) {
  2313         -				if (certs_resizable) {
  2314         -					*count *= 2;
  2315         -					certs = realloc(certs, sizeof(*certs) * (*count));
  2316         -				} else {
  2317         -					break;
  2318         -				}
         2641  +				break;
  2319   2642   			}
  2320   2643   		}
  2321   2644   
  2322         -		cackey_free_tlv(app_tlv);
  2323         -
  2324         -		if (outidx >= *count) {
  2325         -			break;
  2326         -		}
         2645  +		cackey_free_tlv(ccc_tlv);
  2327   2646   	}
  2328   2647   
  2329         -	cackey_free_tlv(ccc_tlv);
  2330         -
  2331   2648   	*count = outidx;
  2332   2649   
  2333   2650   	if (certs_resizable) {
  2334   2651   		certs = realloc(certs, sizeof(*certs) * (*count));
  2335   2652   	}
  2336   2653   
  2337   2654   	slot->cached_certs = cackey_copy_certs(NULL, certs, *count);
................................................................................
  2354   2671    *     ...
  2355   2672    *
  2356   2673    * NOTES
  2357   2674    *     ...
  2358   2675    *
  2359   2676    */
  2360   2677   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) {
  2361         -	unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s;
  2362         -	unsigned char bytes_to_send, p1;
         2678  +	cackey_pcsc_id_type id_type;
         2679  +	unsigned char dyn_auth_template[10];
         2680  +	unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s, *outbuf_p;
         2681  +	unsigned char bytes_to_send, p1, class;
  2363   2682   	unsigned char blocktype;
  2364   2683   	cackey_ret send_ret;
  2365   2684   	uint16_t respcode;
  2366   2685   	ssize_t retval = 0, unpadoffset;
  2367         -	size_t tmpbuflen, padlen, tmpoutbuflen;
         2686  +	size_t tmpbuflen, padlen, tmpoutbuflen, outbuf_len;
  2368   2687   	int free_tmpbuf = 0;
  2369   2688   	int le;
  2370   2689   
  2371   2690   	CACKEY_DEBUG_PRINTF("Called.");
  2372   2691   
  2373   2692   	if (slot == NULL) {
  2374   2693   		CACKEY_DEBUG_PRINTF("Error.  slot is NULL");
................................................................................
  2395   2714   	}
  2396   2715   
  2397   2716   	if (identity->pcsc_identity == NULL) {
  2398   2717   		CACKEY_DEBUG_PRINTF("Error.  identity->pcsc_identity is NULL");
  2399   2718   
  2400   2719   		return(-1);
  2401   2720   	}
         2721  +
         2722  +	id_type = identity->pcsc_identity->id_type;
         2723  +	if (id_type == CACKEY_ID_TYPE_CERT_ONLY) {
         2724  +		CACKEY_DEBUG_PRINTF("Error.  identity->pcsc_identity is CACKEY_ID_TYPE_CERT_ONLY, which cannot be used for sign/decrypt");
         2725  +
         2726  +		return(-1);
         2727  +	}
         2728  +
         2729  +	switch (id_type) {
         2730  +		case CACKEY_ID_TYPE_PIV:
         2731  +		case CACKEY_ID_TYPE_CAC:
         2732  +			break;
         2733  +		default:
         2734  +			CACKEY_DEBUG_PRINTF("Error.  identity->pcsc_identity is not a supported value. Type is: 0x%lx (PIV = 0x%lx, CAC = 0x%lx)", (unsigned long) id_type, (unsigned long) CACKEY_ID_TYPE_PIV, (unsigned long) CACKEY_ID_TYPE_CAC);
         2735  +
         2736  +			return(-1);
         2737  +	}
  2402   2738   
  2403   2739   	/* Determine identity Key size */
  2404   2740   	if (identity->pcsc_identity->keysize < 0) {
  2405   2741   		identity->pcsc_identity->keysize = x509_to_keysize(identity->pcsc_identity->certificate, identity->pcsc_identity->certificate_len);
  2406   2742   	}
  2407   2743   
  2408   2744   	/* Pad message to key size */
................................................................................
  2451   2787   		padlen = 0;
  2452   2788   	}
  2453   2789   
  2454   2790   	/* Begin transaction */
  2455   2791   	cackey_begin_transaction(slot);
  2456   2792   
  2457   2793   	/* Select correct applet */
  2458         -	CACKEY_DEBUG_PRINTF("Selecting applet found at %p ...", identity->pcsc_identity->applet);
  2459         -	cackey_select_applet(slot, identity->pcsc_identity->applet, sizeof(identity->pcsc_identity->applet));
         2794  +	switch (id_type) {
         2795  +		case CACKEY_ID_TYPE_CAC:
         2796  +			CACKEY_DEBUG_PRINTF("Selecting applet found at %p ...", identity->pcsc_identity->card.cac.applet);
         2797  +			cackey_select_applet(slot, identity->pcsc_identity->card.cac.applet, sizeof(identity->pcsc_identity->card.cac.applet));
  2460   2798   
  2461         -	/* Select correct file */
  2462         -	cackey_select_file(slot, identity->pcsc_identity->file);
         2799  +			/* Select correct file */
         2800  +			cackey_select_file(slot, identity->pcsc_identity->card.cac.file);
         2801  +			break;
         2802  +		case CACKEY_ID_TYPE_PIV:
         2803  +			dyn_auth_template[0] = 0x7C;
         2804  +			dyn_auth_template[1] = 0x82;
         2805  +			dyn_auth_template[2] = ((tmpbuflen + 6) & 0xff00) >> 8;
         2806  +			dyn_auth_template[3] = (tmpbuflen + 6) & 0x00ff;
         2807  +			dyn_auth_template[4] = 0x82;
         2808  +			dyn_auth_template[5] = 0x00;
         2809  +			dyn_auth_template[6] = 0x81;
         2810  +			dyn_auth_template[7] = 0x82;
         2811  +			dyn_auth_template[8] = (tmpbuflen & 0xff00) >> 8;
         2812  +			dyn_auth_template[9] = tmpbuflen & 0x00ff;
         2813  +
         2814  +			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);
         2815  +			break;
         2816  +		case CACKEY_ID_TYPE_CERT_ONLY:
         2817  +			break;
         2818  +	}
  2463   2819   
  2464   2820   	tmpbuf_s = tmpbuf;
  2465   2821   	outbuf_s = outbuf;
  2466   2822   	while (tmpbuflen) {
  2467         -		if (tmpbuflen > 245) {
  2468         -			bytes_to_send = 245;
  2469         -			p1 = 0x80;
  2470         -			le = 0x00;
         2823  +		tmpoutbuflen = outbuflen;
         2824  +
         2825  +		if (tmpbuflen > CACKEY_APDU_MTU) {
         2826  +			bytes_to_send = CACKEY_APDU_MTU;
  2471   2827   		} else {
  2472   2828   			bytes_to_send = tmpbuflen;
  2473         -			p1 = 0x00;
  2474         -			le = 0x00;
  2475   2829   		}
  2476   2830   
  2477         -		tmpoutbuflen = outbuflen;
         2831  +		send_ret = CACKEY_PCSC_E_GENERIC;
         2832  +		switch (id_type) {
         2833  +			case CACKEY_ID_TYPE_CAC:
         2834  +				if (tmpbuflen > CACKEY_APDU_MTU) {
         2835  +					p1 = 0x80;
         2836  +					le = 0x00;
         2837  +				} else {
         2838  +					p1 = 0x00;
         2839  +					le = 0x00;
         2840  +				}
  2478   2841   
  2479         -		send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, p1, 0x00, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);
         2842  +				send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, p1, 0x00, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);
         2843  +				break;
         2844  +			case CACKEY_ID_TYPE_PIV:
         2845  +				if (tmpbuflen > CACKEY_APDU_MTU) {
         2846  +					class = 0x10;
         2847  +					le = 0x00;
         2848  +				} else {
         2849  +					class = GSCIS_CLASS_ISO7816;
         2850  +					le = 256;
         2851  +				}
         2852  +
         2853  +				send_ret = cackey_send_apdu(slot, class, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->card.piv.key_id, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);
         2854  +				break;
         2855  +			case CACKEY_ID_TYPE_CERT_ONLY:
         2856  +				break;
         2857  +		}
         2858  +
  2480   2859   		if (send_ret != CACKEY_PCSC_S_OK) {
  2481   2860   			CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error.");
  2482   2861   
  2483   2862   			if (free_tmpbuf) {
  2484   2863   				if (tmpbuf_s) {
  2485   2864   					free(tmpbuf_s);
  2486   2865   				}
  2487   2866   			}
  2488   2867   
  2489   2868   			/* End transaction */
  2490   2869   			cackey_end_transaction(slot);
  2491   2870   
  2492         -			if (respcode == 0x6982) {
  2493         -				CACKEY_DEBUG_PRINTF("Security status not satisified.  Returning NEEDLOGIN");
         2871  +			if (respcode == 0x6982 || respcode == 0x6e00) {
         2872  +				CACKEY_DEBUG_PRINTF("Security status not satisified (respcode = 0x%04x).  Returning NEEDLOGIN", (int) respcode);
         2873  +
         2874  +				cackey_mark_slot_reset(slot);
         2875  +				slot->token_flags = CKF_LOGIN_REQUIRED;
         2876  +
         2877  +				return(CACKEY_PCSC_E_NEEDLOGIN);
         2878  +			}
         2879  +
         2880  +			if (respcode == 0x6E00) {
         2881  +				CACKEY_DEBUG_PRINTF("Got \"WRONG CLASS\", this means we are talking to the wrong object (likely because the card went away) -- resetting");
  2494   2882   
  2495   2883   				cackey_mark_slot_reset(slot);
  2496   2884   				slot->token_flags = CKF_LOGIN_REQUIRED;
  2497   2885   
  2498   2886   				return(CACKEY_PCSC_E_NEEDLOGIN);
  2499   2887   			}
  2500   2888   
................................................................................
  2533   2921   	if (outbuflen > _POSIX_SSIZE_MAX) {
  2534   2922   		CACKEY_DEBUG_PRINTF("Outbuflen exceeds maximum value, returning in failure. (max = %li, outbuflen = %lu)", (long) _POSIX_SSIZE_MAX, (unsigned long) outbuflen);
  2535   2923   
  2536   2924   		return(-1);
  2537   2925   	}
  2538   2926   #  endif
  2539   2927   #endif
         2928  +
         2929  +	/* We must remove the "7C" tag to get to the signature */
         2930  +	switch (id_type) {
         2931  +		case CACKEY_ID_TYPE_PIV:
         2932  +			outbuf_len = retval;
         2933  +			outbuf_p = cackey_read_bertlv_tag(outbuf, &outbuf_len, 0x7C, NULL,  &outbuf_len);
         2934  +			if (outbuf_p == NULL) {
         2935  +				CACKEY_DEBUG_PRINTF("Response from PIV for GENERATE AUTHENTICATION was not a 0x7C tag, returning in failure");
         2936  +
         2937  +				return(-1);
         2938  +			}
         2939  +
         2940  +			retval = outbuf_len;
         2941  +
         2942  +			outbuf_len = retval;
         2943  +			outbuf_p = cackey_read_bertlv_tag(outbuf, &outbuf_len, 0x82, NULL,  &outbuf_len);
         2944  +			if (outbuf_p == NULL) {
         2945  +				CACKEY_DEBUG_PRINTF("Response from PIV for GENERATE AUTHENTICATION was not a 0x82 with then 0x7C tag, returning in failure");
         2946  +
         2947  +				return(-1);
         2948  +			}
         2949  +
         2950  +			retval = outbuf_len;
         2951  +
         2952  +			break;
         2953  +		case CACKEY_ID_TYPE_CAC:
         2954  +		case CACKEY_ID_TYPE_CERT_ONLY:
         2955  +			break;
         2956  +	}
  2540   2957   
  2541   2958   	/* Unpad reply */
  2542   2959   	if (unpadOutput) {
  2543   2960   		if (retval < 3) {
  2544   2961   			CACKEY_DEBUG_PRINTF("Reply is too small, we are not able to unpad -- passing back and hoping for the best!");
  2545   2962   
  2546   2963   			CACKEY_DEBUG_PRINTF("Returning in success, retval = %li (bytes)", (long) retval);
................................................................................
  2629   3046    *     ...
  2630   3047    *
  2631   3048    * NOTES
  2632   3049    *     ...
  2633   3050    *
  2634   3051    */
  2635   3052   static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) {
         3053  +	struct cackey_pcsc_identity *pcsc_identities;
  2636   3054   	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
         3055  +	unsigned long num_certs;
  2637   3056   	uint16_t response_code;
  2638   3057   	int tries_remaining;
  2639   3058   	int send_ret;
         3059  +	int key_reference = 0x00;
  2640   3060   
  2641   3061   	/* Indicate that we do not know about how many tries are remaining */
  2642   3062   	if (tries_remaining_p) {
  2643   3063   		*tries_remaining_p = -1;
  2644   3064   	}
  2645   3065   
  2646   3066   	/* Apparently, CAC PINs are *EXACTLY* 8 bytes long -- pad with 0xFF if too short */
  2647   3067   	if (pin_len >= 8) {
  2648   3068   		memcpy(cac_pin, pin, 8);
  2649   3069   	} else {
  2650   3070   		memcpy(cac_pin, pin, pin_len);
  2651   3071   	}
         3072  +
         3073  +	/* Reject PINs which are too short */
         3074  +	if (pin_len < 5) {
         3075  +		CACKEY_DEBUG_PRINTF("Rejecting PIN which is too short (length = %lu, must be atleast 5)", pin_len);
         3076  +
         3077  +		return(CACKEY_PCSC_E_BADPIN);
         3078  +	}
         3079  +
         3080  +	/* PIV authentication uses a "key_reference" of 0x80 */
         3081  +	pcsc_identities = cackey_read_certs(slot, NULL, &num_certs);
         3082  +	if (num_certs > 0 && pcsc_identities != NULL) {
         3083  +		switch (pcsc_identities[0].id_type) {
         3084  +			case CACKEY_ID_TYPE_PIV:
         3085  +				CACKEY_DEBUG_PRINTF("We have PIV card, so we will attempt to authenticate using the PIV Application key reference");
         3086  +
         3087  +				key_reference = 0x80;
         3088  +				break;
         3089  +			default:
         3090  +				break;
         3091  +		}
         3092  +
         3093  +		cackey_free_certs(pcsc_identities, num_certs, 1);
         3094  +	}
  2652   3095   
  2653   3096   	/* Issue PIN Verify */
  2654         -	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_VERIFY, 0x00, 0x00, sizeof(cac_pin), cac_pin, 0x00, &response_code, NULL, NULL);
         3097  +	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_VERIFY, 0x00, key_reference, sizeof(cac_pin), cac_pin, 0x00, &response_code, NULL, NULL);
         3098  +
  2655   3099   	if (send_ret != CACKEY_PCSC_S_OK) {
  2656   3100   		if ((response_code & 0x63C0) == 0x63C0) {
  2657   3101   			tries_remaining = (response_code & 0xF);
  2658   3102   
  2659   3103   			CACKEY_DEBUG_PRINTF("PIN Verification failed, %i tries remaining", tries_remaining);
  2660   3104   
  2661   3105   			if (tries_remaining_p) {
................................................................................
  2710   3154   	pcsc_connect_ret = cackey_connect_card(slot);
  2711   3155   	if (pcsc_connect_ret != CACKEY_PCSC_S_OK) {
  2712   3156   		CACKEY_DEBUG_PRINTF("Unable to connect to card, returning token absent");
  2713   3157   
  2714   3158   		return(CACKEY_PCSC_E_TOKENABSENT);
  2715   3159   	}
  2716   3160   
         3161  +	CACKEY_DEBUG_PRINTF("Calling SCardStatus() to determine card status");
         3162  +
  2717   3163   	atr_len = sizeof(atr);
  2718   3164   	status_ret = SCardStatus(slot->pcsc_card, NULL, &reader_len, &state, &protocol, atr, &atr_len);
  2719   3165   
  2720   3166   	if (status_ret == SCARD_E_INVALID_HANDLE) {
  2721   3167   		CACKEY_DEBUG_PRINTF("SCardStatus() returned SCARD_E_INVALID_HANDLE, marking is not already connected and trying again");
  2722   3168   		cackey_mark_slot_reset(slot);
  2723   3169   
  2724   3170   		pcsc_connect_ret = cackey_connect_card(slot);
  2725   3171   		if (pcsc_connect_ret != CACKEY_PCSC_S_OK) {
  2726   3172   			CACKEY_DEBUG_PRINTF("Unable to connect to card, returning token absent");
  2727   3173   
  2728   3174   			return(CACKEY_PCSC_E_TOKENABSENT);
  2729   3175   		}
         3176  +
         3177  +		CACKEY_DEBUG_PRINTF("Calling SCardStatus() again");
  2730   3178   
  2731   3179   		atr_len = sizeof(atr);
  2732   3180   		status_ret = SCardStatus(slot->pcsc_card, NULL, &reader_len, &state, &protocol, atr, &atr_len);
  2733   3181   	}
  2734   3182   
  2735   3183   	if (status_ret != SCARD_S_SUCCESS) {
  2736   3184   		cackey_mark_slot_reset(slot);
................................................................................
  3068   3516   
  3069   3517   				CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen);
  3070   3518   
  3071   3519   				break;
  3072   3520   			case CKA_LABEL:
  3073   3521   				CACKEY_DEBUG_PRINTF("Requesting attribute CKA_LABEL (0x%08lx) ...", (unsigned long) curr_attr_type);
  3074   3522   
  3075         -				/* XXX: Determine name */
  3076         -				ulValueLen = snprintf((char *) ucTmpBuf, sizeof(ucTmpBuf), "Identity #%lu", (unsigned long) identity_num);
  3077         -				pValue = ucTmpBuf;
         3523  +				if (identity->id_type == CACKEY_ID_TYPE_PIV) {
         3524  +					pValue = identity->card.piv.label;
         3525  +					ulValueLen = strlen(pValue);
         3526  +				} else {
         3527  +					ulValueLen = snprintf((char *) ucTmpBuf, sizeof(ucTmpBuf), "Identity #%lu", (unsigned long) identity_num);
         3528  +					pValue = ucTmpBuf;
  3078   3529   
  3079         -				if (ulValueLen >= sizeof(ucTmpBuf)) {
  3080         -					ulValueLen = 0;
  3081         -					pValue = NULL;
         3530  +					if (ulValueLen >= sizeof(ucTmpBuf)) {
         3531  +						ulValueLen = 0;
         3532  +						pValue = NULL;
         3533  +					}
  3082   3534   				}
  3083   3535   
  3084   3536   				CACKEY_DEBUG_PRINTF(" ... returning (%p/%lu)", pValue, (unsigned long) ulValueLen);
  3085   3537   
  3086   3538   				break;
  3087   3539   			case CKA_VALUE:
  3088   3540   				CACKEY_DEBUG_PRINTF("Requesting attribute CKA_VALUE (0x%08lx) ...", (unsigned long) curr_attr_type);
................................................................................
  3612   4064   				memcpy(identities[id_idx].pcsc_identity->certificate, pcsc_identities[cert_idx].certificate, pcsc_identities[cert_idx].certificate_len);
  3613   4065   
  3614   4066   				id_idx++;
  3615   4067   			}
  3616   4068   		}
  3617   4069   
  3618   4070   		if (include_extra_certs) {
  3619         -			CACKEY_DEBUG_PRINTF("Including DoD Certificates on hardware slot");
         4071  +			CACKEY_DEBUG_PRINTF("Including US Government Certificates on hardware slot");
  3620   4072   
  3621   4073   			cackey_read_dod_identities(identities + id_idx, num_dod_certs);
  3622   4074   		}
  3623   4075   
  3624   4076   		cackey_free_certs(pcsc_identities, num_certs, 1);
  3625   4077   
  3626   4078   		*ids_found = num_ids;
................................................................................
  3633   4085   	return(NULL);
  3634   4086   }
  3635   4087   
  3636   4088   CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) {
  3637   4089   	CK_C_INITIALIZE_ARGS CK_PTR args;
  3638   4090   	uint32_t idx, highest_slot;
  3639   4091   	int mutex_init_ret;
         4092  +	int include_dod_certs;
  3640   4093   
  3641   4094   	CACKEY_DEBUG_PRINTF("Called.");
  3642   4095   
  3643   4096   	if (cackey_initialized) {
  3644   4097   		CACKEY_DEBUG_PRINTF("Error.  Already initialized.");
  3645   4098   
  3646   4099   		return(CKR_CRYPTOKI_ALREADY_INITIALIZED);
................................................................................
  3676   4129   		cackey_slots[idx].transaction_need_hw_lock = 0;
  3677   4130   		cackey_slots[idx].slot_reset = 0;
  3678   4131   		cackey_slots[idx].token_flags = 0;
  3679   4132   		cackey_slots[idx].label = NULL;
  3680   4133   		cackey_slots[idx].internal = 0;
  3681   4134   	}
  3682   4135   
         4136  +#ifdef CACKEY_NO_EXTRA_CERTS
         4137  +	if (getenv("CACKEY_EXTRA_CERTS") != NULL) {
         4138  +		include_dod_certs = 1;
         4139  +	} else {
         4140  +		include_dod_certs = 0;
         4141  +	}
         4142  +#else
  3683   4143   	if (getenv("CACKEY_NO_EXTRA_CERTS") != NULL) {
         4144  +		include_dod_certs = 0;
         4145  +	} else {
         4146  +		include_dod_certs = 1;
         4147  +	}
         4148  +#endif
         4149  +
         4150  +	if (include_dod_certs == 0) {
  3684   4151   		CACKEY_DEBUG_PRINTF("Asked not to include DoD certificates");
  3685   4152   	} else {
  3686   4153   		highest_slot = (sizeof(cackey_slots) / sizeof(cackey_slots[0])) - 1;
  3687   4154   
  3688   4155   		CACKEY_DEBUG_PRINTF("Including DoD certs in slot %lu", (unsigned long) highest_slot);
  3689   4156   
  3690   4157   		cackey_slots[highest_slot].active = 1;
  3691   4158   		cackey_slots[highest_slot].internal = 1;
  3692         -		cackey_slots[highest_slot].label = (unsigned char *) "DoD Certificates";
         4159  +		cackey_slots[highest_slot].label = (unsigned char *) "US Government Certificates";
  3693   4160   		cackey_slots[highest_slot].pcsc_reader = "CACKey";
  3694   4161   		cackey_slots[highest_slot].token_flags = 0;
  3695   4162   	}
  3696   4163   
  3697   4164   	cackey_initialized = 1;
  3698   4165   
  3699   4166   	if (!cackey_biglock_init) {
................................................................................
  3703   4170   			CACKEY_DEBUG_PRINTF("Error.  Mutex initialization failed.");
  3704   4171   
  3705   4172   			return(CKR_CANT_LOCK);
  3706   4173   		}
  3707   4174   
  3708   4175   		cackey_biglock_init = 1;
  3709   4176   	}
         4177  +
         4178  +	/* Define a command to prompt user for a PIN */
         4179  +#ifdef CACKEY_PIN_COMMAND_DEFAULT
         4180  +	cackey_pin_command = CACKEY_PIN_COMMAND_DEFAULT_XSTR(CACKEY_PIN_COMMAND_DEFAULT);
         4181  +#endif
         4182  +
         4183  +#ifdef CACKEY_PIN_COMMAND_XONLY_DEFAULT
         4184  +	if (getenv("DISPLAY") != NULL) {
         4185  +		cackey_pin_command = CACKEY_PIN_COMMAND_DEFAULT_XSTR(CACKEY_PIN_COMMAND_XONLY_DEFAULT);
         4186  +	}
         4187  +#endif
         4188  +
         4189  +	if (getenv("CACKEY_PIN_COMMAND") != NULL) {
         4190  +		cackey_pin_command = getenv("CACKEY_PIN_COMMAND");
         4191  +	}
         4192  +
         4193  +	if (getenv("CACKEY_PIN_COMMAND_XONLY") != NULL && getenv("DISPLAY") != NULL) {
         4194  +		cackey_pin_command = getenv("CACKEY_PIN_COMMAND_XONLY");
         4195  +	}
  3710   4196   
  3711   4197   	CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK);
  3712   4198   
  3713   4199   	return(CKR_OK);
  3714   4200   }
  3715   4201   
  3716   4202   CK_DEFINE_FUNCTION(CK_RV, C_Finalize)(CK_VOID_PTR pReserved) {
................................................................................
  4235   4721   	pInfo->hardwareVersion.major = (cackey_getversion() >> 16) & 0xff;
  4236   4722   	pInfo->hardwareVersion.minor = (cackey_getversion() >> 8) & 0xff;
  4237   4723   
  4238   4724   	pInfo->firmwareVersion.major = 0x00;
  4239   4725   	pInfo->firmwareVersion.minor = 0x00;
  4240   4726   
  4241   4727   	pInfo->flags = CKF_WRITE_PROTECTED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED | cackey_slots[slotID].token_flags;
         4728  +
         4729  +	if (cackey_pin_command != NULL) {
         4730  +		pInfo->flags |= CKF_PROTECTED_AUTHENTICATION_PATH;
         4731  +	}
  4242   4732   
  4243   4733   	pInfo->ulMaxSessionCount = (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])) - 1;
  4244   4734   	pInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
  4245   4735   	pInfo->ulMaxRwSessionCount = 0;
  4246   4736   	pInfo->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;
  4247   4737   	pInfo->ulMaxPinLen = 128;
  4248   4738   	pInfo->ulMinPinLen = 0;
................................................................................
  4698   5188   	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);
  4699   5189   
  4700   5190   	return(CKR_FUNCTION_NOT_SUPPORTED);
  4701   5191   }
  4702   5192   
  4703   5193   CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) {
  4704   5194   	CK_SLOT_ID slotID;
         5195  +	FILE *pinfd;
         5196  +	char *pincmd, pinbuf[64], *fgets_ret;
  4705   5197   	int mutex_retval;
  4706   5198   	int tries_remaining;
  4707   5199   	int login_ret;
         5200  +	int pclose_ret;
  4708   5201   
  4709   5202   	CACKEY_DEBUG_PRINTF("Called.");
  4710   5203   
  4711   5204   	if (!cackey_initialized) {
  4712   5205   		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");
  4713   5206   
  4714   5207   		return(CKR_CRYPTOKI_NOT_INITIALIZED);
................................................................................
  4752   5245   	if (cackey_slots[slotID].active == 0) {
  4753   5246   		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID);
  4754   5247   
  4755   5248   		cackey_mutex_unlock(cackey_biglock);
  4756   5249   
  4757   5250   		return(CKR_GENERAL_ERROR);
  4758   5251   	}
         5252  +
         5253  +	pincmd = cackey_pin_command;
         5254  +	if (pincmd != NULL) {
         5255  +		CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd);
         5256  +
         5257  +		if (pPin != NULL) {
         5258  +			CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?");
         5259  +		}
         5260  +
         5261  +		pinfd = popen(pincmd, "r");
         5262  +		if (pinfd == NULL) {
         5263  +			CACKEY_DEBUG_PRINTF("Error.  %s: Unable to run", pincmd);
         5264  +
         5265  +			cackey_mutex_unlock(cackey_biglock);
         5266  +
         5267  +			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
         5268  +
         5269  +			return(CKR_PIN_INCORRECT);
         5270  +		}
         5271  +
         5272  +		fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd);
         5273  +		if (fgets_ret == NULL) {
         5274  +			pinbuf[0] = '\0';
         5275  +		}
         5276  +
         5277  +		pclose_ret = pclose(pinfd);
         5278  +		if (pclose_ret != 0) {
         5279  +			CACKEY_DEBUG_PRINTF("Error.  %s: exited with non-zero status of %i", pincmd, pclose_ret);
         5280  +
         5281  +			cackey_mutex_unlock(cackey_biglock);
         5282  +
         5283  +			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
         5284  +
         5285  +			return(CKR_PIN_INCORRECT);
         5286  +		}
         5287  +
         5288  +		if (strlen(pinbuf) < 1) {
         5289  +			CACKEY_DEBUG_PRINTF("Error.  %s: returned no data", pincmd);
         5290  +
         5291  +			cackey_mutex_unlock(cackey_biglock);
         5292  +
         5293  +			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
         5294  +
         5295  +			return(CKR_PIN_INCORRECT);
         5296  +		}
         5297  +
         5298  +		if (pinbuf[strlen(pinbuf) - 1] == '\n') {
         5299  +			pinbuf[strlen(pinbuf) - 1] = '\0';
         5300  +		}
         5301  +
         5302  +		pPin = (CK_UTF8CHAR_PTR) pinbuf;
         5303  +		ulPinLen = strlen(pinbuf);
         5304  +	}
  4759   5305   
  4760   5306   	login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining);
  4761   5307   	if (login_ret != CACKEY_PCSC_S_OK) {
  4762   5308   		cackey_mutex_unlock(cackey_biglock);
  4763   5309   
  4764   5310   		if (login_ret == CACKEY_PCSC_E_LOCKED) {
  4765   5311   			CACKEY_DEBUG_PRINTF("Error.  Token is locked.");
  4766   5312   
  4767   5313   			cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED;
         5314  +
         5315  +			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_LOCKED (%i)", (int) CKR_PIN_LOCKED);
  4768   5316   
  4769   5317   			return(CKR_PIN_LOCKED);
  4770   5318   		} else if (login_ret == CACKEY_PCSC_E_BADPIN) {
  4771   5319   			CACKEY_DEBUG_PRINTF("Error.  Invalid PIN.");
  4772   5320   
  4773   5321   			cackey_slots[slotID].token_flags |= CKF_USER_PIN_COUNT_LOW;
  4774   5322   
  4775   5323   			if (tries_remaining == 1) {
  4776   5324   				cackey_slots[slotID].token_flags |= CKF_USER_PIN_FINAL_TRY;
  4777   5325   			}
         5326  +
         5327  +			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
  4778   5328   
  4779   5329   			return(CKR_PIN_INCORRECT);
  4780   5330   		}
  4781   5331   
  4782   5332   		CACKEY_DEBUG_PRINTF("Error.  Unknown error returned from cackey_login() (%i)", login_ret);
  4783   5333   
  4784   5334   		return(CKR_GENERAL_ERROR);

Modified cackey_builtin_certs.h from [093ba34f4f] to [954ba4d224].

cannot compute difference between binary files

Modified configure.ac from [b325ed9a06] to [8333de68f9].

   160    160   ], [
   161    161   	dodcerts=yes
   162    162   ])
   163    163   
   164    164   if test "${dodcerts}" = 'no'; then
   165    165   	AC_DEFINE(CACKEY_NO_EXTRA_CERTS, [1], [Specify that DoD certificates should not be made available])
   166    166   fi
          167  +
          168  +dnl Option to hard-code a command to run to request a PIN (enabling protected authentication path)
          169  +AC_ARG_WITH(pin-command, AC_HELP_STRING([--with-pin-command=<command>], [Specify a command to run to request a PIN from the user.  The user may override this with the CACKEY_PIN_COMMAND environment variable.]), [
          170  +	pincommand="${withval}"
          171  +], [
          172  +	pincommand="no"
          173  +])
          174  +
          175  +AC_ARG_WITH(pin-command-x, AC_HELP_STRING([--with-pin-command-x=<command>], [Same as --with-pin-command, but only sets Protected Authentication Path if the DISPLAY environment variable is set]), [
          176  +	pincommandxonly="${withval}"
          177  +], [
          178  +	pincommandxonly="no"
          179  +])
          180  +
          181  +if ! test "${pincommand}" = 'no'; then
          182  +	AC_DEFINE_UNQUOTED(CACKEY_PIN_COMMAND_DEFAULT, [$pincommand], [Command to run to prompt user for PIN])
          183  +fi
          184  +
          185  +if ! test "${pincommandxonly}" = 'no'; then
          186  +	AC_DEFINE_UNQUOTED(CACKEY_PIN_COMMAND_XONLY_DEFAULT, [$pincommandxonly], [Command to run to prompt user for PIN only if DISPLAY environment variable is set])
          187  +fi
   167    188   
   168    189   dnl Set version script, to limit the scope of symbols
   169    190   DC_SETVERSIONSCRIPT(libcackey.vers, libcackey.syms)
   170    191   
   171    192   dnl Upate LDFLAGS to include setting the run-time linker path to the same as our compile-time linker
   172    193   DC_SYNC_RPATH
   173    194   
   174    195   dnl If we updated LIBOBJS, update SHLIBOBJS -- must be last.
   175    196   DC_SYNC_SHLIBOBJS
   176    197   
   177    198   dnl Produce Makefile
   178    199   AC_OUTPUT(Makefile libcackey.syms)

Modified test.c from [86bd0fe2e2] to [47338c5b52].

   331    331   	chk_rv = C_OpenSession(slots[0], CKF_SERIAL_SESSION, NULL, NULL, &hSession);
   332    332   	if (chk_rv == CKR_OK) {
   333    333   		chk_rv = C_GetTokenInfo(slots[0], &tokenInfo);
   334    334   		if (chk_rv != CKR_OK) {
   335    335   			return(1);
   336    336   		}
   337    337   
   338         -		if ((tokenInfo.flags & CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED) {
          338  +		if ((tokenInfo.flags & CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED && (tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) {
   339    339   			fgets_ret = NULL;
   340    340   
   341    341   			while (fgets_ret == NULL) {
   342    342   				printf("** ENTER PIN: ");
   343    343   				fflush(stdout);
   344    344   
   345    345   				fgets_ret = fgets((char *) user_pin, sizeof(user_pin), stdin);