Check-in [1494008def]
Overview
Comment:Began adding PIV support
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | piv
Files: files | file ages | folders
SHA1:1494008def42e5f06f88895da0f13fb36e8a741d
User & Date: rkeene on 2013-01-10 01:00:39
Other Links: manifest | tags
Context
2013-01-10
04:59
Updated to provide basic (and buggy) PIV functionality check-in: b9b26ebc73 user: rkeene tags: piv
01:00
Began adding PIV support check-in: 1494008def user: rkeene tags: piv
2012-07-30
16:02
Updated email address in CACKey for OSX Build Script check-in: 003e5de0f0 user: kvanals tags: trunk
Changes

Modified cackey.c from [3db9c71bd5] to [e326e231e2].

   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  +
   159    162   /*** PKI Information - EF 7000 ***/
   160    163   #define GSCIS_TAG_CERTIFICATE         0x70
   161    164   #define GSCIS_TAG_CERT_ISSUE_DATE     0x71
   162    165   #define GSCIS_TAG_CERT_EXPIRE_DATE    0x72
   163    166   
   164    167   /** Applet IDs **/
   165    168   #define GSCIS_AID_CCC                 0xA0, 0x00, 0x00, 0x01, 0x16, 0xDB, 0x00
          169  +#define NISTSP800_73_3_PIV_AID        0xA0, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00
          170  +
          171  +/* PIV IDs */
          172  +/** Key Identifiers (NIST SP 800-78-3, Table 6-1 **/
          173  +#define NISTSP800_78_3_KEY_PIVAUTH   0x9A
          174  +#define NISTSP800_78_3_KEY_SIGNATURE 0x9C
          175  +#define NISTSP800_78_3_KEY_KEYMGT    0x9D
          176  +#define NISTSP800_78_3_KEY_CARDAUTH  0x9E
          177  +
          178  +/** Algorithm Identifiers (NIST SP 800-78-3, Table 6-2 **/
          179  +#define NISTSP800_78_3_ALGO_RSA1024  0x06
          180  +#define NISTSP800_78_3_ALGO_RSA2048  0x07
          181  +
          182  +/** Object Identifiers (NIST SP 800-73-3 Part 1, Table 2) **/
          183  +#define NISTSP800_73_3_OID_PIVAUTH   0x5F, 0xC1, 0x05
          184  +#define NISTSP800_73_3_OID_SIGNATURE 0x5F, 0xC1, 0x0A
          185  +#define NISTSP800_73_3_OID_KEYMGT    0x5F, 0xC1, 0x0B
          186  +#define NISTSP800_73_3_OID_CARDAUTH  0x5F, 0xC1, 0x01
   166    187   
   167    188   /* Maximum size of data portion of APDUs */
   168    189   /** Do not set this above 250 **/
   169    190   #define CACKEY_APDU_MTU               250
   170    191   
   171    192   /* ATR If not available */
   172    193   #ifndef MAX_ATR_SIZE
................................................................................
  1417   1438   	if (le != 0x00) {
  1418   1439   		xmit_buf[xmit_len++] = le;
  1419   1440   	}
  1420   1441   
  1421   1442   	/* Begin Smartcard Transaction */
  1422   1443   	cackey_begin_transaction(slot);
  1423   1444   
  1424         -	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00 && p2 == 0x00) {
         1445  +	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00) {
  1425   1446   		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
  1426   1447   	} else {
  1427   1448   		CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);
  1428   1449   	}
  1429   1450   
  1430   1451   	recv_len = sizeof(recv_buf);
  1431   1452   	scard_xmit_ret = SCardTransmit(slot->pcsc_card, pioSendPci, xmit_buf, xmit_len, NULL, recv_buf, &recv_len);
................................................................................
  1611   1632   	}
  1612   1633   
  1613   1634   
  1614   1635   	CACKEY_DEBUG_PRINTF("APDU Returned an error, returning in failure");
  1615   1636   
  1616   1637   	return(CACKEY_PCSC_E_GENERIC);
  1617   1638   }
         1639  +
         1640  +/*
         1641  + * SYNPOSIS
         1642  + *     ssize_t cackey_get_data(struct cackey_slot *slot, unsigned char *buffer, size_t count, ....
         1643  + *
         1644  + * ARGUMENTS
         1645  + *     struct cackey_slot *slot
         1646  + *         Slot to send commands to
         1647  + *
         1648  + *     unsigned char *buffer
         1649  + *         [OUT] Buffer
         1650  + *
         1651  + *     size_t count
         1652  + *         Number of bytes to attempt to read
         1653  + *
         1654  + *     size_t initial_offset
         1655  + *         Specify the offset to begin the read from
         1656  + *
         1657  + *
         1658  + * RETURN VALUE
         1659  + *     This function returns the number of bytes actually read, or -1 on error.
         1660  + *
         1661  + * NOTES
         1662  + *     None
         1663  + *
         1664  + */
         1665  +static ssize_t cackey_get_data(struct cackey_slot *slot, unsigned char *buffer, size_t count, unsigned char oid[3]) {
         1666  +	unsigned char *buffer_p;
         1667  +	size_t init_count;
         1668  +
         1669  +	size_t offset = 0, max_offset, max_count, size;
         1670  +	unsigned char cmd[] = {0x5C, 0x03, 0x00, 0x00, 0x00};
         1671  +	uint16_t respcode;
         1672  +	int send_ret;
         1673  +	int idx;
         1674  +
         1675  +	CACKEY_DEBUG_PRINTF("Called.");
         1676  +
         1677  +	init_count = count;
         1678  +
         1679  +	max_offset = count;
         1680  +	max_count = CACKEY_APDU_MTU;
         1681  +
         1682  +	cmd[2] = oid[0];
         1683  +	cmd[3] = oid[1];
         1684  +	cmd[4] = oid[2];
         1685  +
         1686  +	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, NISTSP800_73_3_INSTR_GET_DATA, 0x3F, 0xFF, sizeof(cmd), cmd, count, &respcode, buffer, &count);
         1687  +
         1688  +	if (send_ret == CACKEY_PCSC_E_RETRY) {
         1689  +		CACKEY_DEBUG_PRINTF("ADPU Sending failed, retrying read buffer");
         1690  +
         1691  +		return(cackey_get_data(slot, buffer, init_count, oid));
         1692  +	}
         1693  +
         1694  +	if (send_ret != CACKEY_PCSC_S_OK) {
         1695  +		if (respcode == 0x6A86) {
         1696  +/* XXX TODO PIV */
         1697  +		}
         1698  +
         1699  +		CACKEY_DEBUG_PRINTF("cackey_send_apdu() failed, returning in failure");
         1700  +
         1701  +		return(-1);
         1702  +	}
         1703  +
         1704  +	offset += count;
         1705  +
         1706  +#ifdef CACKEY_PARANOID
         1707  +#  ifdef _POSIX_SSIZE_MAX
         1708  +	if (offset > _POSIX_SSIZE_MAX) {
         1709  +		CACKEY_DEBUG_PRINTF("Offset exceeds maximum value, returning in failure. (max = %li, offset = %lu)", (long) _POSIX_SSIZE_MAX, (unsigned long) offset);
         1710  +
         1711  +		return(-1);
         1712  +	}
         1713  +#  endif
         1714  +#endif
         1715  +
         1716  +	if (offset < 2) {
         1717  +		CACKEY_DEBUG_PRINTF("APDU GET DATA returned %lu bytes, which is too short for a BER-TLV response", (unsigned long) offset);
         1718  +
         1719  +		return(-1);
         1720  +	}
         1721  +
         1722  +	buffer_p = buffer;
         1723  +	if (*buffer_p != 0x53) {
         1724  +		CACKEY_DEBUG_PRINTF("APDU GET DATA did not return a BER-TLV with tag 53.  Tag = %02x", (unsigned int) *buffer_p);
         1725  +
         1726  +		return(-1);
         1727  +	}
         1728  +	buffer_p++;
         1729  +
         1730  +	if ((*buffer_p & 0x80) == 0x80) {
         1731  +		size = 0;
         1732  +		idx = (*buffer_p & 0x7f);
         1733  +
         1734  +		if (((buffer_p - buffer) + idx) >= offset) {
         1735  +			CACKEY_DEBUG_PRINTF("Malformed BER value -- not enough bytes available to read length");
         1736  +
         1737  +			return(-1);
         1738  +		}
         1739  +
         1740  +		for (; idx > 0; idx--) {
         1741  +			buffer_p++;
         1742  +			size <<= 8;
         1743  +			size |= *buffer_p;
         1744  +		}
         1745  +	} else {
         1746  +		size = *buffer_p;
         1747  +	}
         1748  +	buffer_p++;
         1749  +
         1750  +	if (((buffer_p - buffer) + size) != offset) {
         1751  +		CACKEY_DEBUG_PRINTF("Entire buffer is not consumed!");
         1752  +
         1753  +		if (((buffer_p - buffer) + size) > offset) {
         1754  +			CACKEY_DEBUG_PRINTF("Encoded size is greater than the amount of data read, dropping");
         1755  +
         1756  +			return(-1);
         1757  +		}
         1758  +	}
         1759  +
         1760  +	memmove(buffer, buffer_p, size);
         1761  +
         1762  +	CACKEY_DEBUG_PRINTBUF("GET DATA result", buffer, size);
         1763  +
         1764  +	CACKEY_DEBUG_PRINTF("Returning in success, read %lu bytes", (unsigned long) size);
         1765  +
         1766  +	return(size);
         1767  +}
  1618   1768   
  1619   1769   /*
  1620   1770    * SYNPOSIS
  1621   1771    *     ssize_t cackey_read_buffer(struct cackey_slot *slot, unsigned char *buffer, size_t count, unsigned char t_or_v, size_t initial_offset);
  1622   1772    *
  1623   1773    * ARGUMENTS
  1624   1774    *     struct cackey_slot *slot
................................................................................
  2130   2280    * NOTES
  2131   2281    *     ...
  2132   2282    *
  2133   2283    */
  2134   2284   static struct cackey_pcsc_identity *cackey_read_certs(struct cackey_slot *slot, struct cackey_pcsc_identity *certs, unsigned long *count) {
  2135   2285   	struct cackey_pcsc_identity *curr_id;
  2136   2286   	struct cackey_tlv_entity *ccc_tlv, *ccc_curr, *app_tlv, *app_curr;
  2137         -	unsigned char ccc_aid[] = {GSCIS_AID_CCC};
         2287  +	unsigned char ccc_aid[] = {GSCIS_AID_CCC}, piv_aid[] = {NISTSP800_73_3_PIV_AID};
         2288  +	unsigned char piv_oid_pivauth[] = {NISTSP800_73_3_OID_PIVAUTH};
  2138   2289   	unsigned char curr_aid[7];
         2290  +	unsigned char buffer[8192];
  2139   2291   	unsigned long outidx = 0;
  2140   2292   	cackey_ret transaction_ret;
         2293  +	ssize_t read_ret;
  2141   2294   	int certs_resizable;
  2142   2295   	int send_ret, select_ret;
         2296  +	int piv = 0;
  2143   2297   
  2144   2298   	CACKEY_DEBUG_PRINTF("Called.");
  2145   2299   
  2146   2300   	if (count == NULL) {
  2147   2301   		CACKEY_DEBUG_PRINTF("count is NULL, returning in failure");
  2148   2302   
  2149   2303   		return(NULL);
................................................................................
  2196   2350   	} else {
  2197   2351   		certs_resizable = 0;
  2198   2352   	}
  2199   2353   
  2200   2354   	/* Select the CCC Applet */
  2201   2355   	send_ret = cackey_select_applet(slot, ccc_aid, sizeof(ccc_aid));
  2202   2356   	if (send_ret != CACKEY_PCSC_S_OK) {
         2357  +		/* Try PIV application */
         2358  +		send_ret = cackey_select_applet(slot, piv_aid, sizeof(piv_aid));
         2359  +		if (send_ret == CACKEY_PCSC_S_OK) {
         2360  +			CACKEY_DEBUG_PRINTF("We have a PIV card, doing the needful");
         2361  +
         2362  +			piv = 1;
         2363  +		} else {
         2364  +
  2203   2365   		CACKEY_DEBUG_PRINTF("Unable to select CCC Applet, returning in failure");
  2204   2366   
  2205   2367   		/* Terminate SmartCard Transaction */
  2206   2368   		cackey_end_transaction(slot);
  2207   2369   
  2208   2370   		return(NULL);
  2209   2371   	}
         2372  +	}
  2210   2373   
         2374  +	if (piv) {
         2375  +		read_ret = cackey_get_data(slot, buffer, sizeof(buffer), piv_oid_pivauth);
         2376  +
         2377  +		curr_id = &certs[outidx];
         2378  +		outidx++;
         2379  +
         2380  +		curr_id->keysize = -1;
         2381  +		curr_id->file = 0xFFFF;
         2382  +		curr_id->applet[0] = NISTSP800_78_3_KEY_PIVAUTH;
         2383  +
         2384  +		curr_id->certificate_len = read_ret;
         2385  +		curr_id->certificate = malloc(curr_id->certificate_len);
         2386  +		memcpy(curr_id->certificate, buffer + 4, curr_id->certificate_len - 4); /* XXX TODO PIV */
         2387  +	} else {
  2211   2388   	/* Read all the applets from the CCC's TLV */
  2212   2389   	ccc_tlv = cackey_read_tlv(slot);
  2213   2390   
  2214   2391   	/* Look for CARDURLs that coorespond to PKI applets */
  2215   2392   	for (ccc_curr = ccc_tlv; ccc_curr; ccc_curr = ccc_curr->_next) {
  2216   2393   		CACKEY_DEBUG_PRINTF("Found tag: %s ... ", CACKEY_DEBUG_FUNC_TAG_TO_STR(ccc_curr->tag));
  2217   2394   
................................................................................
  2291   2468   
  2292   2469   		if (outidx >= *count) {
  2293   2470   			break;
  2294   2471   		}
  2295   2472   	}
  2296   2473   
  2297   2474   	cackey_free_tlv(ccc_tlv);
         2475  +	}
  2298   2476   
  2299   2477   	*count = outidx;
  2300   2478   
  2301   2479   	if (certs_resizable) {
  2302   2480   		certs = realloc(certs, sizeof(*certs) * (*count));
  2303   2481   	}
  2304   2482   
................................................................................
  2331   2509   	unsigned char blocktype;
  2332   2510   	cackey_ret send_ret;
  2333   2511   	uint16_t respcode;
  2334   2512   	ssize_t retval = 0, unpadoffset;
  2335   2513   	size_t tmpbuflen, padlen, tmpoutbuflen;
  2336   2514   	int free_tmpbuf = 0;
  2337   2515   	int le;
         2516  +	int piv;
  2338   2517   
  2339   2518   	CACKEY_DEBUG_PRINTF("Called.");
  2340   2519   
  2341   2520   	if (slot == NULL) {
  2342   2521   		CACKEY_DEBUG_PRINTF("Error.  slot is NULL");
  2343   2522   
  2344   2523   		return(-1);
................................................................................
  2419   2598   		padlen = 0;
  2420   2599   	}
  2421   2600   
  2422   2601   	/* Begin transaction */
  2423   2602   	cackey_begin_transaction(slot);
  2424   2603   
  2425   2604   	/* Select correct applet */
         2605  +	if (identity->pcsc_identity->file == 0xFFFF) {
         2606  +		piv = 1;
         2607  +	} else {
         2608  +		piv = 0;
         2609  +	}
         2610  +
         2611  +	if (piv) {
         2612  +		CACKEY_DEBUG_PRINTF("Sign/Decrypt not implemented XXX TODO PIV");
         2613  +		cackey_end_transaction(slot);
         2614  +		return(-1);
         2615  +	} else {
  2426   2616   	CACKEY_DEBUG_PRINTF("Selecting applet found at %p ...", identity->pcsc_identity->applet);
  2427   2617   	cackey_select_applet(slot, identity->pcsc_identity->applet, sizeof(identity->pcsc_identity->applet));
  2428   2618   
  2429   2619   	/* Select correct file */
  2430   2620   	cackey_select_file(slot, identity->pcsc_identity->file);
  2431   2621   
  2432   2622   	tmpbuf_s = tmpbuf;
................................................................................
  2480   2670   		tmpbuf += bytes_to_send;
  2481   2671   		tmpbuflen -= bytes_to_send;
  2482   2672   
  2483   2673   		outbuf += tmpoutbuflen;
  2484   2674   		outbuflen -= tmpoutbuflen;
  2485   2675   		retval += tmpoutbuflen;
  2486   2676   	}
         2677  +	}
  2487   2678   
  2488   2679   	if (free_tmpbuf) {
  2489   2680   		if (tmpbuf_s) {
  2490   2681   			free(tmpbuf_s);
  2491   2682   		}
  2492   2683   	}
  2493   2684   
................................................................................
  2601   2792    *
  2602   2793    */
  2603   2794   static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) {
  2604   2795   	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  2605   2796   	uint16_t response_code;
  2606   2797   	int tries_remaining;
  2607   2798   	int send_ret;
         2799  +	int key_reference = 0x00;
  2608   2800   
  2609   2801   	/* Indicate that we do not know about how many tries are remaining */
  2610   2802   	if (tries_remaining_p) {
  2611   2803   		*tries_remaining_p = -1;
  2612   2804   	}
  2613   2805   
  2614   2806   	/* Apparently, CAC PINs are *EXACTLY* 8 bytes long -- pad with 0xFF if too short */
................................................................................
  2615   2807   	if (pin_len >= 8) {
  2616   2808   		memcpy(cac_pin, pin, 8);
  2617   2809   	} else {
  2618   2810   		memcpy(cac_pin, pin, pin_len);
  2619   2811   	}
  2620   2812   
  2621   2813   	/* Issue PIN Verify */
  2622         -	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_VERIFY, 0x00, 0x00, sizeof(cac_pin), cac_pin, 0x00, &response_code, NULL, NULL);
         2814  +	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);
         2815  +	if (send_ret != CACKEY_PCSC_S_OK && response_code == 0x6A88) {
         2816  +		key_reference = 0x80;
         2817  +
         2818  +		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);
         2819  +	}
         2820  +
  2623   2821   	if (send_ret != CACKEY_PCSC_S_OK) {
  2624   2822   		if ((response_code & 0x63C0) == 0x63C0) {
  2625   2823   			tries_remaining = (response_code & 0xF);
  2626   2824   
  2627   2825   			CACKEY_DEBUG_PRINTF("PIN Verification failed, %i tries remaining", tries_remaining);
  2628   2826   
  2629   2827   			if (tries_remaining_p) {