Modify pcsc.c to have support for Mifare classic and Ultralight card

Modify pcsc.c and mifare.c files.
1. add code into pcsc.c to have support Mifare classic card.
2. The PCSC reader has SW value, add response data length for PCSC
reader
This commit is contained in:
hongbin@ftsafe.com 2020-05-13 12:15:28 +08:00
parent 66176016ed
commit 8352c80679
2 changed files with 259 additions and 71 deletions

View file

@ -44,6 +44,27 @@
#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
// define from pcsclite for apple
#define SCARD_AUTOALLOCATE (DWORD)(-1)
#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag)))
#define SCARD_CLASS_VENDOR_INFO 1 /**< Vendor information definitions */
#define SCARD_CLASS_COMMUNICATIONS 2 /**< Communication definitions */
#define SCARD_CLASS_PROTOCOL 3 /**< Protocol definitions */
#define SCARD_CLASS_POWER_MGMT 4 /**< Power Management definitions */
#define SCARD_CLASS_SECURITY 5 /**< Security Assurance definitions */
#define SCARD_CLASS_MECHANICAL 6 /**< Mechanical characteristic definitions */
#define SCARD_CLASS_VENDOR_DEFINED 7 /**< Vendor specific definitions */
#define SCARD_CLASS_IFD_PROTOCOL 8 /**< Interface Device Protocol options */
#define SCARD_CLASS_ICC_STATE 9 /**< ICC State specific definitions */
#define SCARD_CLASS_SYSTEM 0x7fff /**< System-specific definitions */
#define SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0100) /**< Vendor name. */
#define SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0101) /**< Vendor-supplied interface device type (model designation of reader). */
#define SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0102) /**< Vendor-supplied interface device version (DWORD in the form 0xMMmmbbbb where MM = major version, mm = minor version, and bbbb = build number). */
#define SCARD_ATTR_VENDOR_IFD_SERIAL_NO SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0103) /**< Vendor-supplied interface device serial number. */
#define SCARD_ATTR_ICC_TYPE_PER_ATR SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0304) /**< Single byte indicating smart card type */
#else
#ifndef _Win32
#include <reader.h>
@ -76,18 +97,6 @@ struct pcsc_data {
#define DRIVER_DATA(pnd) ((struct pcsc_data*)(pnd->driver_data))
//Doesn't have define in macOS, so define from reader.h
#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag)))
#define SCARD_CLASS_VENDOR_INFO 1
#define SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0100)
#define SCARD_ATTR_ICC_TYPE_PER_ATR SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0304)
#define SCARD_CLASS_ICC_STATE 9
#define SCARD_AUTOALLOCATE (DWORD)(-1)
#define SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0100)
#define SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0101)
#define SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0102)
#define SCARD_ATTR_VENDOR_IFD_SERIAL_NO SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0103)
static SCARDCONTEXT _SCardContext;
static int _iSCardContextRefCount = 0;
@ -184,6 +193,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};
@ -209,7 +330,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(uint8_t it, const uint8_t *patr, size_t szatr, const uint8_t *puid, int szuid, const nfc_modulation_type nmt, nfc_target *pnt)
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) {
@ -228,13 +349,31 @@ int pcsc_props_to_target(uint8_t it, const uint8_t *patr, size_t szatr, const ui
memcpy(pnt->nti.nai.abtUid, puid, szuid);
pnt->nti.nai.szUidLen = szuid;
}
/* 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);
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;
@ -303,40 +442,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);
}
// Supported Feitian Contactless Reader
#if defined (__APPLE__)
// Feitian R502
if (strstr(acDeviceNames + szPos, "Feitian R502") != NULL)
{
bSupported = true;
}
// Feitian 502-CL
if (strstr(acDeviceNames + szPos, "Feitian 502-CL") != NULL)
{
bSupported = true;
}
// Feitian bR500
if (strstr(acDeviceNames + szPos, "Feitian bR500") != NULL)
{
bSupported = true;
}
#else
// Feitian R502
if (strstr(acDeviceNames + szPos, "Feitian R502 [R502 Contact Reader]") != NULL)
{
bSupported = true;
}
// Feitian 502-CL
if (strstr(acDeviceNames + szPos, "Feitian 502-CL [R502 Contactless Reader]") != NULL)
{
bSupported = true;
}
// Feitian bR500
if (strstr(acDeviceNames + szPos, "Feitian bR500") != NULL)
{
bSupported = true;
}
#endif
if (bSupported) {
// Supported non-ACR122 device found
@ -428,8 +533,7 @@ pcsc_open(const nfc_context *context, const nfc_connstring connstring)
// Test if context succeeded
if (!(pscc = pcsc_get_scardcontext()))
goto error;
// T1 or T0 protocol.
DRIVER_DATA(pnd)->last_error = SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol));
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");
@ -656,7 +760,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(icc_type, atr, atr_len, uid, uid_len, nm.nmt, pnt) != NFC_SUCCESS) {
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;
}
@ -681,7 +785,75 @@ int pcsc_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx
// FIXME: timeout is not handled
(void) timeout;
pnd->last_error = pcsc_transmit(pnd, pbtTx, szTx, pbtRx, &resp_len);
if (is_pcsc_reader_vendor_feitian(pnd)){
LOG_HEX(NFC_LOG_GROUP_COM, "not feitian reader 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] == 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 reader 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 reader pcsc apdu received:", resp, resp_len);
memcpy(pbtRx, resp, resp_len);
} else {
pnd->last_error = pcsc_transmit(pnd, pbtTx, szTx, pbtRx, &resp_len);
}
if (pnd->last_error != NFC_SUCCESS)
return pnd->last_error;
@ -705,7 +877,7 @@ int pcsc_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *p
}
if (pnt) {
if (pcsc_props_to_target(ICC_TYPE_UNKNOWN, atr, atr_len, NULL, 0, pnt->nm.nmt, &nt) != NFC_SUCCESS
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;
@ -722,7 +894,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:
@ -772,7 +958,7 @@ pcsc_get_information_about(nfc_device *pnd, char **pbuf)
struct pcsc_data *data = pnd->driver_data;
LPBYTE name = NULL, version = NULL, type = NULL, serial = NULL;
DWORD name_len = SCARD_AUTOALLOCATE, version_len = SCARD_AUTOALLOCATE,
type_len = SCARD_AUTOALLOCATE, serial_len = SCARD_AUTOALLOCATE;
type_len = SCARD_AUTOALLOCATE, serial_len = SCARD_AUTOALLOCATE;
int res = NFC_SUCCESS;
SCARDCONTEXT *pscc;
@ -807,27 +993,28 @@ pcsc_get_information_about(nfc_device *pnd, char **pbuf)
? "\nserial: " : "", serial_len > 0 ? (char *)serial : "");
error:
// SCardFreeMemory function not supported in macOS.
#if defined(__APPLE__)
if (name != NULL){
#ifdef __APPLE__
SCardReleaseContext(*pscc);
if (name != NULL)
{
free(name);
name = NULL;
}
if (type != NULL){
if (type != NULL)
{
free(type);
type = NULL;
}
if (version != NULL){
if (version != NULL)
{
free(version);
version = NULL;
}
if (serial != NULL){
if (serial != NULL)
{
free(serial);
serial = NULL;
}
if (pscc != NULL){
SCardReleaseContext(pscc);
}
#else
SCardFreeMemory(*pscc, name);
SCardFreeMemory(*pscc, type);
@ -835,7 +1022,6 @@ error:
SCardFreeMemory(*pscc, serial);
#endif
pnd->last_error = res;
return pnd->last_error;
}

View file

@ -130,7 +130,9 @@ nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8
// When we have executed a read command, copy the received bytes into the param
if (mc == MC_READ) {
if (res == 16) {
//Check the length of response data, with PCSC reader, there have 2 bytes for SW value
if (res == 16 || res == (16 + 2)) {
memcpy(pmp->mpd.abtData, abtRx, 16);
} else {
return false;