Update pcsc.c

Update code, and solve the Mifare classic, Ultralight bugs. Add method to get ATQA and ATS.
This commit is contained in:
Feitian Technologies 2020-05-12 23:53:33 +08:00 committed by GitHub
parent 1070eb71b6
commit 95751e60cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -135,6 +135,7 @@ int pcsc_transmit(struct nfc_device *pnd, const uint8_t *tx, const size_t tx_len
return NFC_EIO; return NFC_EIO;
} }
*rx_len = dw_rx_len; *rx_len = dw_rx_len;
LOG_HEX(NFC_LOG_GROUP_COM, "RX", rx, *rx_len); LOG_HEX(NFC_LOG_GROUP_COM, "RX", rx, *rx_len);
return NFC_SUCCESS; return NFC_SUCCESS;
@ -183,6 +184,118 @@ uint8_t pcsc_get_icc_type(struct nfc_device *pnd)
return it; return it;
} }
char* pcsc_get_vendor_name(struct nfc_device *pnd){
struct pcsc_data *data = pnd->driver_data;
LPBYTE vendor_name = NULL;
DWORD vendor_name_len = SCARD_AUTOALLOCATE;
int res = SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_NAME, (LPBYTE)&vendor_name, &vendor_name_len);
if (!res && vendor_name && vendor_name_len > 0 && vendor_name[0] != '\0') {
char *psVendorName = (char *)malloc(sizeof(char) * vendor_name_len);
memcpy(psVendorName, vendor_name, vendor_name_len);
return psVendorName;
}
return NULL;
}
bool is_pcsc_reader_vendor(struct nfc_device *pnd, const char * target_vendor_name)
{
bool isTarget = false;
char * sReaderVendorName = pcsc_get_vendor_name(pnd);
if (sReaderVendorName)
{
isTarget = (strstr(sReaderVendorName, target_vendor_name)) ? true:false;
free(sReaderVendorName);
sReaderVendorName = NULL;
}
return isTarget;
}
bool is_pcsc_reader_vendor_feitian(struct nfc_device *pnd)
{
return is_pcsc_reader_vendor(pnd, "Feitian") || is_pcsc_reader_vendor(pnd, "FeiTian") ||is_pcsc_reader_vendor(pnd, "feitian");
}
//get atqa by send apdu
int pcsc_get_atqa(struct nfc_device *pnd, uint8_t *atqa, size_t atqa_len)
{
const uint8_t get_data[] = {0xFF, 0xCA, 0x03, 0x00, 0x00};
uint8_t resp[256 + 2];
size_t resp_len = sizeof resp;
pnd->last_error = pcsc_transmit(pnd, get_data, sizeof get_data, resp, &resp_len);
if (pnd->last_error != NFC_SUCCESS)
return pnd->last_error;
if (resp_len < 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for ATQA");
pnd->last_error = NFC_EDEVNOTSUPP;
return pnd->last_error;
}
if (atqa_len < resp_len - 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ATQA length is wrong");
pnd->last_error = NFC_ESOFT;
return pnd->last_error;
}
memcpy(atqa, resp, resp_len - 2);
return resp_len - 2;
}
//get ats by send apdu
int pcsc_get_ats(struct nfc_device *pnd, uint8_t *ats, size_t ats_len)
{
const uint8_t get_data[] = {0xFF, 0xCA, 0x01, 0x00, 0x00};
uint8_t resp[256 + 2];
size_t resp_len = sizeof resp;
pnd->last_error = pcsc_transmit(pnd, get_data, sizeof get_data, resp, &resp_len);
if (pnd->last_error != NFC_SUCCESS)
return pnd->last_error;
if (resp_len < 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for ATS");
pnd->last_error = NFC_EDEVNOTSUPP;
return pnd->last_error;
}
if (ats_len < resp_len - 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ATS length is wrong");
pnd->last_error = NFC_ESOFT;
return pnd->last_error;
}
//memcpy(ats, resp + 1, resp_len - 2 - 1);
memcpy(ats, resp + 1, resp[0] - 1);
return resp_len - 2 - 1;
}
//get sak by send apdu
int pcsc_get_sak(struct nfc_device *pnd, uint8_t *sak, size_t sak_len)
{
const uint8_t get_data[] = {0xFF, 0xCA, 0x02, 0x00, 0x00};
uint8_t resp[256 + 2];
size_t resp_len = sizeof resp;
pnd->last_error = pcsc_transmit(pnd, get_data, sizeof get_data, resp, &resp_len);
if (pnd->last_error != NFC_SUCCESS)
return pnd->last_error;
if (resp_len < 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for SAK");
pnd->last_error = NFC_EDEVNOTSUPP;
return pnd->last_error;
}
if (sak_len < resp_len - 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "SAK length is wrong");
pnd->last_error = NFC_ESOFT;
return pnd->last_error;
}
memcpy(sak, resp, resp_len - 2);
return resp_len - 2;
}
int pcsc_get_uid(struct nfc_device *pnd, uint8_t *uid, size_t uid_len) int pcsc_get_uid(struct nfc_device *pnd, uint8_t *uid, size_t uid_len)
{ {
const uint8_t get_data[] = {0xFF, 0xCA, 0x00, 0x00, 0x00}; const uint8_t get_data[] = {0xFF, 0xCA, 0x00, 0x00, 0x00};
@ -208,6 +321,7 @@ int pcsc_get_uid(struct nfc_device *pnd, uint8_t *uid, size_t uid_len)
return resp_len - 2; return resp_len - 2;
} }
int pcsc_props_to_target(const struct nfc_device *pnd, uint8_t it, const uint8_t *patr, size_t szatr, const uint8_t *puid, int szuid, const nfc_modulation_type nmt, nfc_target *pnt)
{ {
if (NULL != pnt) { if (NULL != pnt) {
switch (nmt) { switch (nmt) {
@ -226,6 +340,31 @@ int pcsc_get_uid(struct nfc_device *pnd, uint8_t *uid, size_t uid_len)
memcpy(pnt->nti.nai.abtUid, puid, szuid); memcpy(pnt->nti.nai.abtUid, puid, szuid);
pnt->nti.nai.szUidLen = szuid; pnt->nti.nai.szUidLen = szuid;
} }
if (is_pcsc_reader_vendor_feitian(pnd))
{
uint8_t atqa[2];
pcsc_get_atqa(pnd,atqa,sizeof(atqa));
//memcpy(pnt->nti.nai.abtAtqa,atqa,2);
pnt->nti.nai.abtAtqa[0] = atqa[1];
pnt->nti.nai.abtAtqa[1] = atqa[0];
uint8_t sak[1];
pcsc_get_sak(pnd,sak,sizeof(sak));
pnt->nti.nai.btSak = sak[0];
uint8_t ats[256];
int ats_len = pcsc_get_ats(pnd, ats, sizeof(ats));
memcpy(pnt->nti.nai.abtAts, ats, ats_len);
//memcpy(pnt->nti.nai.abtAts + ats_len, patr + 4, (uint8_t)(szatr - 5));
pnt->nti.nai.szAtsLen = ats_len;// + szatr - 5;
} else {
/* SAK_ISO14443_4_COMPLIANT */
pnt->nti.nai.btSak = 0x20;
/* Choose TL, TA, TB, TC according to Mifare DESFire */
memcpy(pnt->nti.nai.abtAts, "\x75\x77\x81\x02", 4);
/* copy historical bytes */
memcpy(pnt->nti.nai.abtAts + 4, patr + 4, (uint8_t)(szatr - 5));
pnt->nti.nai.szAtsLen = 4 + (uint8_t)(szatr - 5);
}
return NFC_SUCCESS; return NFC_SUCCESS;
} }
break; break;
@ -294,7 +433,6 @@ pcsc_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t
int l = strlen(supported_devices[i]); int l = strlen(supported_devices[i]);
bSupported = 0 == !strncmp(supported_devices[i], acDeviceNames + szPos, l); bSupported = 0 == !strncmp(supported_devices[i], acDeviceNames + szPos, l);
} }
}
if (bSupported) { if (bSupported) {
// Supported non-ACR122 device found // Supported non-ACR122 device found
@ -386,6 +524,7 @@ pcsc_open(const nfc_context *context, const nfc_connstring connstring)
// Test if context succeeded // Test if context succeeded
if (!(pscc = pcsc_get_scardcontext())) if (!(pscc = pcsc_get_scardcontext()))
goto error; goto error;
DRIVER_DATA(pnd)->last_error = SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol));
if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) { if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) {
// We can not connect to this device. // We can not connect to this device.
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC connect failed"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC connect failed");
@ -612,6 +751,7 @@ int pcsc_initiator_select_passive_target(struct nfc_device *pnd, const nfc_modu
uint8_t icc_type = pcsc_get_icc_type(pnd); uint8_t icc_type = pcsc_get_icc_type(pnd);
int uid_len = pcsc_get_uid(pnd, uid, sizeof uid); int uid_len = pcsc_get_uid(pnd, uid, sizeof uid);
if (pcsc_props_to_target(pnd, icc_type, atr, atr_len, uid, uid_len, nm.nmt, pnt) != NFC_SUCCESS) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Type of target not supported"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Type of target not supported");
return NFC_EDEVNOTSUPP; return NFC_EDEVNOTSUPP;
} }
@ -636,6 +776,79 @@ int pcsc_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx
// FIXME: timeout is not handled // FIXME: timeout is not handled
(void) timeout; (void) timeout;
if (is_pcsc_reader_vendor_feitian(pnd)){
LOG_HEX(NFC_LOG_GROUP_COM, "not feitian pcsc apdu send", pbtTx, szTx);
uint8_t apdu_data[256];
uint8_t resp[256 + 2];
size_t send_size = 0;
if (pbtTx[0] == 0x30) {//read data
apdu_data[0] = 0xFF;
apdu_data[1] = 0xB0;
apdu_data[2] = 0x00;
apdu_data[3] = pbtTx[1];
apdu_data[4] = 0x10;
send_size = 5;
} else if (pbtTx[0] == 0xA0 || pbtTx[0] == 0xA2) {//write data
apdu_data[0] = 0xFF;
apdu_data[1] = 0xD6;
apdu_data[2] = 0x00;
apdu_data[3] = pbtTx[1];
apdu_data[4] = szTx - 2;
memcpy(apdu_data + 5, pbtTx + 2, szTx - 2);
send_size = 5 + szTx - 2;
} else if (pbtTx[0] == 0x60 || pbtTx[0] == 0x61 || pbtTx[0] == 0x1A){//Auth command
apdu_data[0] = 0xFF;
apdu_data[1] = 0x86;
apdu_data[2] = 0x00;
apdu_data[3] = 0x00;
apdu_data[4] = 0x05;
apdu_data[5] = 0x01;
apdu_data[6] = 0x00;
apdu_data[7] = pbtTx[1];//block index
apdu_data[8] = pbtTx[0];//type a or type b
apdu_data[9] = 0x01;
send_size = 10;
} else if (pbtTx[0] == 0xB0 ){//TRANSFER cmd
;
} else if (pbtTx[0] == 0xC0){//DECREMENT cmd
apdu_data[0] = 0xFF;
apdu_data[1] = 0xD7;
apdu_data[2] = 0x00;
apdu_data[3] = pbtTx[1];//block index
apdu_data[4] = 0x05;
memcpy(apdu_data + 5, pbtTx + 2, szTx - 2);
send_size = 5 + szTx - 2;
} else if (pbtTx[0] == 0xC1){//INCREMENT cmd
apdu_data[0] = 0xFF;
apdu_data[1] = 0xD7;
apdu_data[2] = 0x00;
apdu_data[3] = pbtTx[1];//block index
apdu_data[4] = 0x05;
memcpy(apdu_data + 5, pbtTx + 2, szTx - 2);
send_size = 5 + szTx - 2;
} else if (pbtTx[0] == 0xC2){//STORE cmd
apdu_data[0] = 0xFF;
apdu_data[1] = 0xD8;
apdu_data[2] = 0x00;
apdu_data[3] = pbtTx[1];
apdu_data[4] = szTx - 2;
memcpy(apdu_data + 5, pbtTx + 2, szTx - 2);
send_size = 5 + szTx - 2;
} else {//other cmd
memcpy(apdu_data, pbtTx, szTx);
send_size = szTx;
}
LOG_HEX(NFC_LOG_GROUP_COM, "feitian pcsc apdu send:", apdu_data, send_size);
pnd->last_error = pcsc_transmit(pnd, apdu_data, send_size, resp, &resp_len);
LOG_HEX(NFC_LOG_GROUP_COM, "feitian pcsc apdu received:", resp, resp_len);
memcpy(pbtRx, resp, resp_len);
// pnd->last_error = pcsc_transmit(pnd, pbtTx, szTx, pbtRx, &resp_len);
// LOG_HEX(NFC_LOG_GROUP_COM, "apdu return to client:", pbtRx, resp_len);
} else {
pnd->last_error = pcsc_transmit(pnd, pbtTx, szTx, pbtRx, &resp_len);
}
if (pnd->last_error != NFC_SUCCESS) if (pnd->last_error != NFC_SUCCESS)
return pnd->last_error; return pnd->last_error;
@ -659,6 +872,7 @@ int pcsc_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *p
} }
if (pnt) { if (pnt) {
if (pcsc_props_to_target(pnd, ICC_TYPE_UNKNOWN, atr, atr_len, NULL, 0, pnt->nm.nmt, &nt) != NFC_SUCCESS
|| pnt->nm.nmt != nt.nm.nmt || pnt->nm.nbr != nt.nm.nbr) { || pnt->nm.nmt != nt.nm.nmt || pnt->nm.nbr != nt.nm.nbr) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Target doesn't meet requirements"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Target doesn't meet requirements");
return NFC_ENOTSUCHDEV; return NFC_ENOTSUCHDEV;
@ -675,7 +889,21 @@ int pcsc_device_set_property_bool(struct nfc_device *pnd, const nfc_property pro
// ignore // ignore
return NFC_SUCCESS; return NFC_SUCCESS;
case NP_AUTO_ISO14443_4: case NP_AUTO_ISO14443_4:
{
if (is_pcsc_reader_vendor_feitian(pnd))
{
//ignore
return NFC_SUCCESS;
}
}
case NP_EASY_FRAMING: case NP_EASY_FRAMING:
{
if (is_pcsc_reader_vendor_feitian(pnd))
{
//ignore
return NFC_SUCCESS;
}
}
case NP_FORCE_ISO14443_A: case NP_FORCE_ISO14443_A:
case NP_HANDLE_CRC: case NP_HANDLE_CRC:
case NP_HANDLE_PARITY: case NP_HANDLE_PARITY:
@ -760,7 +988,7 @@ pcsc_get_information_about(nfc_device *pnd, char **pbuf)
? "\nserial: " : "", serial_len > 0 ? (char *)serial : ""); ? "\nserial: " : "", serial_len > 0 ? (char *)serial : "");
error: error:
// SCardFreeMemory function not supported in macOS. // SCardFreeMemory function not supported in macOS.
#if defined(__APPLE__) #if defined(__APPLE__)
if (name != NULL){ if (name != NULL){
free(name); free(name);
@ -827,4 +1055,3 @@ const struct nfc_driver pcsc_driver = {
.idle = NULL, .idle = NULL,
.powerdown = NULL, .powerdown = NULL,
}; };