ADDED build/certs/federal/Makefile Index: build/certs/federal/Makefile ================================================================== --- /dev/null +++ build/certs/federal/Makefile @@ -0,0 +1,36 @@ +all: cert-1.crt CPCA_TRCA.crt + +CPCA_TRCA.crt: + wget -O - --no-check-certificate https://pki.treas.gov/CPCA_TRCA.cer | openssl x509 -text > "$@.new" + mv "$@.new" "$@" + +caCertsIssuedTofcpca.p7c: + wget -O "$@.new" http://http.fpki.gov/fcpca/caCertsIssuedTofcpca.p7c + mv "$@.new" "$@" + +root_sia.p7b: + wget -O "$@.new" --no-check-certificate https://pki.treas.gov/root_sia.p7b + mv "$@.new" "$@" + +cert-%.crt: root_sia.p7b caCertsIssuedTofcpca.p7c + idx=0; \ + ( \ + openssl pkcs7 -in root_sia.p7b -inform DER -print_certs -text; \ + openssl pkcs7 -in caCertsIssuedTofcpca.p7c -inform DER -print_certs -text; \ + ) | while IFS='' read -r line; do \ + if [ -z "$${line}" ]; then \ + continue; \ + fi; \ + echo "$${line}" >> "cert-$${idx}.crt"; \ + if [ "$${line}" == "-----END CERTIFICATE-----" ]; then \ + idx=$$[$$idx + 1]; \ + fi; \ + done + grep -l 'Subject: C=US, O=U.S. Government, OU=Department of the Treasury, OU=Certification Authorities, OU=US Treasury Root CA' cert-*.crt | xargs rm -f + +clean: + rm -f cert-*.crt + rm -f CPCA_TRCA.crt.new root_sia.p7b.new caCertsIssuedTofcpca.p7c.new + +distclean: clean + rm -f CPCA_TRCA.crt root_sia.p7b caCertsIssuedTofcpca.p7c Index: cackey.c ================================================================== --- cackey.c +++ cackey.c @@ -154,17 +154,39 @@ #define GSCIS_TAG_EXPIRE_DATE 0x53 #define GSCIS_TAG_CARD_TYPE 0x54 #define GSCIS_TAG_SECURITY_CODE 0x57 #define GSCIS_TAG_CARDID_AID 0x58 +/*** PIV Codes ***/ +#define NISTSP800_73_3_INSTR_GET_DATA 0xCB +#define NISTSP800_73_3_INSTR_GENAUTH 0x87 + /*** PKI Information - EF 7000 ***/ #define GSCIS_TAG_CERTIFICATE 0x70 #define GSCIS_TAG_CERT_ISSUE_DATE 0x71 #define GSCIS_TAG_CERT_EXPIRE_DATE 0x72 /** Applet IDs **/ #define GSCIS_AID_CCC 0xA0, 0x00, 0x00, 0x01, 0x16, 0xDB, 0x00 +#define NISTSP800_73_3_PIV_AID 0xA0, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00 + +/* PIV IDs */ +/** Key Identifiers (NIST SP 800-78-3, Table 6-1 **/ +#define NISTSP800_78_3_KEY_PIVAUTH 0x9A +#define NISTSP800_78_3_KEY_SIGNATURE 0x9C +#define NISTSP800_78_3_KEY_KEYMGT 0x9D +#define NISTSP800_78_3_KEY_CARDAUTH 0x9E + +/** Algorithm Identifiers (NIST SP 800-78-3, Table 6-2 **/ +#define NISTSP800_78_3_ALGO_RSA1024 0x06 +#define NISTSP800_78_3_ALGO_RSA2048 0x07 + +/** Object Identifiers (NIST SP 800-73-3 Part 1, Table 2) **/ +#define NISTSP800_73_3_OID_PIVAUTH 0x5F, 0xC1, 0x05 +#define NISTSP800_73_3_OID_SIGNATURE 0x5F, 0xC1, 0x0A +#define NISTSP800_73_3_OID_KEYMGT 0x5F, 0xC1, 0x0B +#define NISTSP800_73_3_OID_CARDAUTH 0x5F, 0xC1, 0x01 /* Maximum size of data portion of APDUs */ /** Do not set this above 250 **/ #define CACKEY_APDU_MTU 250 @@ -1357,11 +1379,11 @@ * It will connect to the card in the reader attached to the slot * specified. It will reconnect to the card if the connection * goes away. * */ -static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned char lc, unsigned char *data, unsigned char le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) { +static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned int lc, unsigned char *data, unsigned int le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) { uint8_t major_rc, minor_rc; size_t bytes_to_copy, tmp_respdata_len; LPCSCARD_IO_REQUEST pioSendPci; DWORD protocol; DWORD xmit_len, recv_len; @@ -1406,24 +1428,38 @@ xmit_buf[xmit_len++] = class; xmit_buf[xmit_len++] = instruction; xmit_buf[xmit_len++] = p1; xmit_buf[xmit_len++] = p2; if (data) { - xmit_buf[xmit_len++] = lc; + if (lc > 256) { + xmit_buf[xmit_len++] = 0x80; /* XXX UNTESTED */ + xmit_buf[xmit_len++] = (lc & 0xff00) >> 8; + xmit_buf[xmit_len++] = lc & 0xff; + } else { + xmit_buf[xmit_len++] = lc; + } for (idx = 0; idx < lc; idx++) { xmit_buf[xmit_len++] = data[idx]; } } if (le != 0x00) { - xmit_buf[xmit_len++] = le; + if (le > 256) { + xmit_buf[xmit_len++] = 0x80; /* XXX UNTESTED */ + xmit_buf[xmit_len++] = (le & 0xff00) >> 8; + xmit_buf[xmit_len++] = le & 0xff; + } else if (le == 256) { + xmit_buf[xmit_len++] = 0x00; + } else { + xmit_buf[xmit_len++] = le; + } } /* Begin Smartcard Transaction */ cackey_begin_transaction(slot); - if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00 && p2 == 0x00) { + if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00) { CACKEY_DEBUG_PRINTF("Sending APDU: <>"); } else { CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len); } @@ -1613,10 +1649,139 @@ CACKEY_DEBUG_PRINTF("APDU Returned an error, returning in failure"); return(CACKEY_PCSC_E_GENERIC); } + +/* + * SYNPOSIS + * ssize_t cackey_get_data(struct cackey_slot *slot, unsigned char *buffer, size_t count, .... + * + * ARGUMENTS + * struct cackey_slot *slot + * Slot to send commands to + * + * unsigned char *buffer + * [OUT] Buffer + * + * size_t count + * Number of bytes to attempt to read + * + * size_t initial_offset + * Specify the offset to begin the read from + * + * + * RETURN VALUE + * This function returns the number of bytes actually read, or -1 on error. + * + * NOTES + * None + * + */ +static ssize_t cackey_get_data(struct cackey_slot *slot, unsigned char *buffer, size_t count, unsigned char oid[3]) { + unsigned char *buffer_p; + size_t init_count; + + size_t offset = 0, max_offset, max_count, size; + unsigned char cmd[] = {0x5C, 0x03, 0x00, 0x00, 0x00}; + uint16_t respcode; + int send_ret; + int idx; + + CACKEY_DEBUG_PRINTF("Called."); + + init_count = count; + + max_offset = count; + max_count = CACKEY_APDU_MTU; + + cmd[2] = oid[0]; + cmd[3] = oid[1]; + cmd[4] = oid[2]; + + send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, NISTSP800_73_3_INSTR_GET_DATA, 0x3F, 0xFF, sizeof(cmd), cmd, count, &respcode, buffer, &count); + + if (send_ret == CACKEY_PCSC_E_RETRY) { + CACKEY_DEBUG_PRINTF("ADPU Sending failed, retrying read buffer"); + + return(cackey_get_data(slot, buffer, init_count, oid)); + } + + if (send_ret != CACKEY_PCSC_S_OK) { + if (respcode == 0x6A86) { +/* XXX TODO PIV */ + } + + CACKEY_DEBUG_PRINTF("cackey_send_apdu() failed, returning in failure"); + + return(-1); + } + + offset += count; + +#ifdef CACKEY_PARANOID +# ifdef _POSIX_SSIZE_MAX + if (offset > _POSIX_SSIZE_MAX) { + CACKEY_DEBUG_PRINTF("Offset exceeds maximum value, returning in failure. (max = %li, offset = %lu)", (long) _POSIX_SSIZE_MAX, (unsigned long) offset); + + return(-1); + } +# endif +#endif + + if (offset < 2) { + CACKEY_DEBUG_PRINTF("APDU GET DATA returned %lu bytes, which is too short for a BER-TLV response", (unsigned long) offset); + + return(-1); + } + + buffer_p = buffer; + if (*buffer_p != 0x53) { + CACKEY_DEBUG_PRINTF("APDU GET DATA did not return a BER-TLV with tag 53. Tag = %02x", (unsigned int) *buffer_p); + + return(-1); + } + buffer_p++; + + if ((*buffer_p & 0x80) == 0x80) { + size = 0; + idx = (*buffer_p & 0x7f); + + if (((buffer_p - buffer) + idx) >= offset) { + CACKEY_DEBUG_PRINTF("Malformed BER value -- not enough bytes available to read length"); + + return(-1); + } + + for (; idx > 0; idx--) { + buffer_p++; + size <<= 8; + size |= *buffer_p; + } + } else { + size = *buffer_p; + } + buffer_p++; + + if (((buffer_p - buffer) + size) != offset) { + CACKEY_DEBUG_PRINTF("Entire buffer is not consumed!"); + + if (((buffer_p - buffer) + size) > offset) { + CACKEY_DEBUG_PRINTF("Encoded size is greater than the amount of data read, dropping"); + + return(-1); + } + } + + memmove(buffer, buffer_p, size); + + CACKEY_DEBUG_PRINTBUF("GET DATA result", buffer, size); + + CACKEY_DEBUG_PRINTF("Returning in success, read %lu bytes", (unsigned long) size); + + return(size); +} /* * SYNPOSIS * ssize_t cackey_read_buffer(struct cackey_slot *slot, unsigned char *buffer, size_t count, unsigned char t_or_v, size_t initial_offset); * @@ -2132,16 +2297,21 @@ * */ static struct cackey_pcsc_identity *cackey_read_certs(struct cackey_slot *slot, struct cackey_pcsc_identity *certs, unsigned long *count) { struct cackey_pcsc_identity *curr_id; struct cackey_tlv_entity *ccc_tlv, *ccc_curr, *app_tlv, *app_curr; - unsigned char ccc_aid[] = {GSCIS_AID_CCC}; + unsigned char ccc_aid[] = {GSCIS_AID_CCC}, piv_aid[] = {NISTSP800_73_3_PIV_AID}; + unsigned char *piv_oid, piv_oid_pivauth[] = {NISTSP800_73_3_OID_PIVAUTH}, piv_oid_signature[] = {NISTSP800_73_3_OID_SIGNATURE}, piv_oid_keymgt[] = {NISTSP800_73_3_OID_KEYMGT}; unsigned char curr_aid[7]; + unsigned char buffer[8192]; unsigned long outidx = 0; cackey_ret transaction_ret; + ssize_t read_ret; int certs_resizable; int send_ret, select_ret; + int piv_key, piv = 0; + int idx; CACKEY_DEBUG_PRINTF("Called."); if (count == NULL) { CACKEY_DEBUG_PRINTF("count is NULL, returning in failure"); @@ -2198,105 +2368,152 @@ } /* Select the CCC Applet */ send_ret = cackey_select_applet(slot, ccc_aid, sizeof(ccc_aid)); if (send_ret != CACKEY_PCSC_S_OK) { - CACKEY_DEBUG_PRINTF("Unable to select CCC Applet, returning in failure"); - - /* Terminate SmartCard Transaction */ - cackey_end_transaction(slot); - - return(NULL); - } - - /* Read all the applets from the CCC's TLV */ - ccc_tlv = cackey_read_tlv(slot); - - /* Look for CARDURLs that coorespond to PKI applets */ - for (ccc_curr = ccc_tlv; ccc_curr; ccc_curr = ccc_curr->_next) { - CACKEY_DEBUG_PRINTF("Found tag: %s ... ", CACKEY_DEBUG_FUNC_TAG_TO_STR(ccc_curr->tag)); - - if (ccc_curr->tag != GSCIS_TAG_CARDURL) { - CACKEY_DEBUG_PRINTF(" ... skipping it (we only care about CARDURLs)"); - - continue; - } - - if ((ccc_curr->value_cardurl->apptype & CACKEY_TLV_APP_PKI) != CACKEY_TLV_APP_PKI) { - 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); - - continue; - } - - CACKEY_DEBUG_PRINTBUF("RID:", ccc_curr->value_cardurl->rid, sizeof(ccc_curr->value_cardurl->rid)); - CACKEY_DEBUG_PRINTF("AppID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(ccc_curr->value_cardurl->appid), (unsigned long) ccc_curr->value_cardurl->appid); - CACKEY_DEBUG_PRINTF("ObjectID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(ccc_curr->value_cardurl->objectid), (unsigned long) ccc_curr->value_cardurl->objectid); - - memcpy(curr_aid, ccc_curr->value_cardurl->rid, sizeof(ccc_curr->value_cardurl->rid)); - curr_aid[sizeof(curr_aid) - 2] = (ccc_curr->value_cardurl->appid >> 8) & 0xff; - curr_aid[sizeof(curr_aid) - 1] = ccc_curr->value_cardurl->appid & 0xff; - - /* Select found applet ... */ - select_ret = cackey_select_applet(slot, curr_aid, sizeof(curr_aid)); - if (select_ret != CACKEY_PCSC_S_OK) { - CACKEY_DEBUG_PRINTF("Failed to select applet, skipping processing of this object"); - - continue; - } - - /* ... and object (file) */ - select_ret = cackey_select_file(slot, ccc_curr->value_cardurl->objectid); - if (select_ret != CACKEY_PCSC_S_OK) { - CACKEY_DEBUG_PRINTF("Failed to select file, skipping processing of this object"); - - continue; - } - - /* Process this file's TLV looking for certificates */ - app_tlv = cackey_read_tlv(slot); - - for (app_curr = app_tlv; app_curr; app_curr = app_curr->_next) { - CACKEY_DEBUG_PRINTF("Found tag: %s", CACKEY_DEBUG_FUNC_TAG_TO_STR(app_curr->tag)); - if (app_curr->tag != GSCIS_TAG_CERTIFICATE) { - CACKEY_DEBUG_PRINTF(" ... skipping it (we only care about CERTIFICATEs)"); - + /* Try PIV application */ + send_ret = cackey_select_applet(slot, piv_aid, sizeof(piv_aid)); + if (send_ret == CACKEY_PCSC_S_OK) { + CACKEY_DEBUG_PRINTF("We have a PIV card -- not using the CCC, pulling pre-selected keys"); + + piv = 1; + } else { + + CACKEY_DEBUG_PRINTF("Unable to select CCC Applet, returning in failure"); + + /* Terminate SmartCard Transaction */ + cackey_end_transaction(slot); + + return(NULL); + } + } + + if (piv) { + for (idx = 0; idx < 3; idx++) { + switch (idx) { + case 0: + piv_oid = piv_oid_pivauth; + piv_key = NISTSP800_78_3_KEY_PIVAUTH; + break; + case 1: + piv_oid = piv_oid_signature; + piv_key = NISTSP800_78_3_KEY_SIGNATURE; + break; + case 2: + piv_oid = piv_oid_keymgt; + piv_key = NISTSP800_78_3_KEY_KEYMGT; + break; + } + + read_ret = cackey_get_data(slot, buffer, sizeof(buffer), piv_oid); + + if (read_ret <= 0) { continue; } curr_id = &certs[outidx]; outidx++; - memcpy(curr_id->applet, curr_aid, sizeof(curr_id->applet)); - curr_id->file = ccc_curr->value_cardurl->objectid; - curr_id->keysize = -1; - - CACKEY_DEBUG_PRINTF("Filling curr_id->applet (%p) with %lu bytes:", curr_id->applet, (unsigned long) sizeof(curr_id->applet)); - CACKEY_DEBUG_PRINTBUF("VAL:", curr_id->applet, sizeof(curr_id->applet)); - - curr_id->certificate_len = app_curr->length; - - curr_id->certificate = malloc(curr_id->certificate_len); - memcpy(curr_id->certificate, app_curr->value, curr_id->certificate_len); - - if (outidx >= *count) { - if (certs_resizable) { - *count *= 2; - certs = realloc(certs, sizeof(*certs) * (*count)); - } else { - break; - } - } - } - - cackey_free_tlv(app_tlv); - - if (outidx >= *count) { - break; - } - } - - cackey_free_tlv(ccc_tlv); + curr_id->keysize = -1; + curr_id->file = 0xFFFF; + curr_id->applet[0] = piv_key; + + curr_id->certificate_len = read_ret; + curr_id->certificate = malloc(curr_id->certificate_len); + memcpy(curr_id->certificate, buffer + 4, curr_id->certificate_len - 4); /* XXX TODO PIV (-4 header, -5 trailer == why ?) */ + curr_id->certificate_len -= 4; + curr_id->certificate_len -= 5; + } + } else { + /* Read all the applets from the CCC's TLV */ + ccc_tlv = cackey_read_tlv(slot); + + /* Look for CARDURLs that coorespond to PKI applets */ + for (ccc_curr = ccc_tlv; ccc_curr; ccc_curr = ccc_curr->_next) { + CACKEY_DEBUG_PRINTF("Found tag: %s ... ", CACKEY_DEBUG_FUNC_TAG_TO_STR(ccc_curr->tag)); + + if (ccc_curr->tag != GSCIS_TAG_CARDURL) { + CACKEY_DEBUG_PRINTF(" ... skipping it (we only care about CARDURLs)"); + + continue; + } + + if ((ccc_curr->value_cardurl->apptype & CACKEY_TLV_APP_PKI) != CACKEY_TLV_APP_PKI) { + 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); + + continue; + } + + CACKEY_DEBUG_PRINTBUF("RID:", ccc_curr->value_cardurl->rid, sizeof(ccc_curr->value_cardurl->rid)); + CACKEY_DEBUG_PRINTF("AppID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(ccc_curr->value_cardurl->appid), (unsigned long) ccc_curr->value_cardurl->appid); + CACKEY_DEBUG_PRINTF("ObjectID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(ccc_curr->value_cardurl->objectid), (unsigned long) ccc_curr->value_cardurl->objectid); + + memcpy(curr_aid, ccc_curr->value_cardurl->rid, sizeof(ccc_curr->value_cardurl->rid)); + curr_aid[sizeof(curr_aid) - 2] = (ccc_curr->value_cardurl->appid >> 8) & 0xff; + curr_aid[sizeof(curr_aid) - 1] = ccc_curr->value_cardurl->appid & 0xff; + + /* Select found applet ... */ + select_ret = cackey_select_applet(slot, curr_aid, sizeof(curr_aid)); + if (select_ret != CACKEY_PCSC_S_OK) { + CACKEY_DEBUG_PRINTF("Failed to select applet, skipping processing of this object"); + + continue; + } + + /* ... and object (file) */ + select_ret = cackey_select_file(slot, ccc_curr->value_cardurl->objectid); + if (select_ret != CACKEY_PCSC_S_OK) { + CACKEY_DEBUG_PRINTF("Failed to select file, skipping processing of this object"); + + continue; + } + + /* Process this file's TLV looking for certificates */ + app_tlv = cackey_read_tlv(slot); + + for (app_curr = app_tlv; app_curr; app_curr = app_curr->_next) { + CACKEY_DEBUG_PRINTF("Found tag: %s", CACKEY_DEBUG_FUNC_TAG_TO_STR(app_curr->tag)); + if (app_curr->tag != GSCIS_TAG_CERTIFICATE) { + CACKEY_DEBUG_PRINTF(" ... skipping it (we only care about CERTIFICATEs)"); + + continue; + } + + curr_id = &certs[outidx]; + outidx++; + + memcpy(curr_id->applet, curr_aid, sizeof(curr_id->applet)); + curr_id->file = ccc_curr->value_cardurl->objectid; + curr_id->keysize = -1; + + CACKEY_DEBUG_PRINTF("Filling curr_id->applet (%p) with %lu bytes:", curr_id->applet, (unsigned long) sizeof(curr_id->applet)); + CACKEY_DEBUG_PRINTBUF("VAL:", curr_id->applet, sizeof(curr_id->applet)); + + curr_id->certificate_len = app_curr->length; + + curr_id->certificate = malloc(curr_id->certificate_len); + memcpy(curr_id->certificate, app_curr->value, curr_id->certificate_len); + + if (outidx >= *count) { + if (certs_resizable) { + *count *= 2; + certs = realloc(certs, sizeof(*certs) * (*count)); + } else { + break; + } + } + } + + cackey_free_tlv(app_tlv); + + if (outidx >= *count) { + break; + } + } + + cackey_free_tlv(ccc_tlv); + } *count = outidx; if (certs_resizable) { certs = realloc(certs, sizeof(*certs) * (*count)); @@ -2324,19 +2541,21 @@ * NOTES * ... * */ static ssize_t cackey_signdecrypt(struct cackey_slot *slot, struct cackey_identity *identity, unsigned char *buf, size_t buflen, unsigned char *outbuf, size_t outbuflen, int padInput, int unpadOutput) { + unsigned char dyn_auth_template[10]; unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s; - unsigned char bytes_to_send, p1; + unsigned char bytes_to_send, p1, class; unsigned char blocktype; cackey_ret send_ret; uint16_t respcode; ssize_t retval = 0, unpadoffset; size_t tmpbuflen, padlen, tmpoutbuflen; int free_tmpbuf = 0; int le; + int piv; CACKEY_DEBUG_PRINTF("Called."); if (slot == NULL) { CACKEY_DEBUG_PRINTF("Error. slot is NULL"); @@ -2419,34 +2638,70 @@ padlen = 0; } /* Begin transaction */ cackey_begin_transaction(slot); + + /* Determine type of transaction */ + if (identity->pcsc_identity->file == 0xFFFF) { + piv = 1; + } else { + piv = 0; + } /* Select correct applet */ - CACKEY_DEBUG_PRINTF("Selecting applet found at %p ...", identity->pcsc_identity->applet); - cackey_select_applet(slot, identity->pcsc_identity->applet, sizeof(identity->pcsc_identity->applet)); + if (!piv) { + CACKEY_DEBUG_PRINTF("Selecting applet found at %p ...", identity->pcsc_identity->applet); + cackey_select_applet(slot, identity->pcsc_identity->applet, sizeof(identity->pcsc_identity->applet)); - /* Select correct file */ - cackey_select_file(slot, identity->pcsc_identity->file); + /* Select correct file */ + cackey_select_file(slot, identity->pcsc_identity->file); + } else { + dyn_auth_template[0] = 0x7C; + dyn_auth_template[1] = 0x82; + dyn_auth_template[2] = ((tmpbuflen + 6) & 0xff00) >> 8; + dyn_auth_template[3] = (tmpbuflen + 6) & 0x00ff; + dyn_auth_template[4] = 0x82; + dyn_auth_template[5] = 0x00; + dyn_auth_template[6] = 0x81; + dyn_auth_template[7] = 0x82; + dyn_auth_template[8] = (tmpbuflen & 0xff00) >> 8; + dyn_auth_template[9] = tmpbuflen & 0x00ff; + + send_ret = cackey_send_apdu(slot, 0x10, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->applet[0], sizeof(dyn_auth_template), dyn_auth_template, 0x00, NULL, NULL, NULL); + } tmpbuf_s = tmpbuf; outbuf_s = outbuf; while (tmpbuflen) { if (tmpbuflen > 245) { bytes_to_send = 245; - p1 = 0x80; - le = 0x00; + if (piv) { + class = 0x10; + le = 0x00; + } else { + p1 = 0x80; + le = 0x00; + } } else { bytes_to_send = tmpbuflen; - p1 = 0x00; - le = 0x00; + if (piv) { + class = GSCIS_CLASS_ISO7816; + le = 256; + } else { + p1 = 0x00; + le = 0x00; + } } tmpoutbuflen = outbuflen; - send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, p1, 0x00, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen); + if (piv) { + send_ret = cackey_send_apdu(slot, class, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->applet[0], bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen); + } else { + send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, p1, 0x00, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen); + } if (send_ret != CACKEY_PCSC_S_OK) { CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error."); if (free_tmpbuf) { if (tmpbuf_s) { @@ -2503,10 +2758,24 @@ return(-1); } # endif #endif + + /* We must remove the "7C" tag to get to the signature */ + if (piv) { + if (outbuf[0] != 0x7C) { + CACKEY_DEBUG_PRINTF("Response from PIV for GENERATE AUTHENTICATION was not a 0x7C tag, returning in failure"); + + + return(-1); + } + + /* XXX TODO PIV */ + memmove(outbuf, outbuf + 8, retval - 8); + retval -= 8; + } /* Unpad reply */ if (unpadOutput) { if (retval < 3) { CACKEY_DEBUG_PRINTF("Reply is too small, we are not able to unpad -- passing back and hoping for the best!"); @@ -2603,10 +2872,11 @@ static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) { unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint16_t response_code; int tries_remaining; int send_ret; + int key_reference = 0x00; /* Indicate that we do not know about how many tries are remaining */ if (tries_remaining_p) { *tries_remaining_p = -1; } @@ -2617,11 +2887,17 @@ } else { memcpy(cac_pin, pin, pin_len); } /* Issue PIN Verify */ - send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_VERIFY, 0x00, 0x00, sizeof(cac_pin), cac_pin, 0x00, &response_code, NULL, NULL); + 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); + if (send_ret != CACKEY_PCSC_S_OK && response_code == 0x6A88) { + key_reference = 0x80; + + 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); + } + if (send_ret != CACKEY_PCSC_S_OK) { if ((response_code & 0x63C0) == 0x63C0) { tries_remaining = (response_code & 0xF); CACKEY_DEBUG_PRINTF("PIN Verification failed, %i tries remaining", tries_remaining);