Update pcsc.c
Update code, and solve the Mifare classic, Ultralight bugs. Add method to get ATQA and ATS.
This commit is contained in:
parent
1070eb71b6
commit
95751e60cd
@ -135,6 +135,7 @@ int pcsc_transmit(struct nfc_device *pnd, const uint8_t *tx, const size_t tx_len
|
||||
return NFC_EIO;
|
||||
}
|
||||
*rx_len = dw_rx_len;
|
||||
|
||||
LOG_HEX(NFC_LOG_GROUP_COM, "RX", rx, *rx_len);
|
||||
|
||||
return NFC_SUCCESS;
|
||||
@ -183,6 +184,118 @@ uint8_t pcsc_get_icc_type(struct nfc_device *pnd)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
@ -294,7 +433,6 @@ pcsc_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t
|
||||
int l = strlen(supported_devices[i]);
|
||||
bSupported = 0 == !strncmp(supported_devices[i], acDeviceNames + szPos, l);
|
||||
}
|
||||
}
|
||||
|
||||
if (bSupported) {
|
||||
// Supported non-ACR122 device found
|
||||
@ -386,6 +524,7 @@ pcsc_open(const nfc_context *context, const nfc_connstring connstring)
|
||||
// Test if context succeeded
|
||||
if (!(pscc = pcsc_get_scardcontext()))
|
||||
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) {
|
||||
// We can not connect to this device.
|
||||
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);
|
||||
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");
|
||||
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
|
||||
(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)
|
||||
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 (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) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Target doesn't meet requirements");
|
||||
return NFC_ENOTSUCHDEV;
|
||||
@ -675,7 +889,21 @@ int pcsc_device_set_property_bool(struct nfc_device *pnd, const nfc_property pro
|
||||
// ignore
|
||||
return NFC_SUCCESS;
|
||||
case NP_AUTO_ISO14443_4:
|
||||
{
|
||||
if (is_pcsc_reader_vendor_feitian(pnd))
|
||||
{
|
||||
//ignore
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
}
|
||||
case NP_EASY_FRAMING:
|
||||
{
|
||||
if (is_pcsc_reader_vendor_feitian(pnd))
|
||||
{
|
||||
//ignore
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
}
|
||||
case NP_FORCE_ISO14443_A:
|
||||
case NP_HANDLE_CRC:
|
||||
case NP_HANDLE_PARITY:
|
||||
@ -760,7 +988,7 @@ pcsc_get_information_about(nfc_device *pnd, char **pbuf)
|
||||
? "\nserial: " : "", serial_len > 0 ? (char *)serial : "");
|
||||
|
||||
error:
|
||||
// SCardFreeMemory function not supported in macOS.
|
||||
// SCardFreeMemory function not supported in macOS.
|
||||
#if defined(__APPLE__)
|
||||
if (name != NULL){
|
||||
free(name);
|
||||
@ -827,4 +1055,3 @@ const struct nfc_driver pcsc_driver = {
|
||||
.idle = NULL,
|
||||
.powerdown = NULL,
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user