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