diff --git a/configure.ac b/configure.ac index ad13f34..9ac52f2 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) # Checks for pkg-config modules. - LIBNFC_REQUIRED_VERSION=1.3.9 + LIBNFC_REQUIRED_VERSION=1.4.0 PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])]) PKG_CONFIG_REQUIRES="libnfc" diff --git a/src/mfoc.c b/src/mfoc.c index 549b0f5..449ec9d 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -158,11 +158,11 @@ int main(int argc, char * const argv[]) { mf_init(&t, &r); // Configure reader settings mf_configure(r.pdi); - mf_select_tag(r.pdi, &t.ti); + mf_select_tag(r.pdi, &(t.nt)); // Save tag uid and info about block size (b4K) - t.b4K = (t.ti.nai.abtAtqa[1] == 0x02); - t.uid = (uint32_t) bytes_to_num(t.ti.nai.abtUid, 4); + t.b4K = (t.nt.nti.nai.abtAtqa[1] == 0x02); + t.uid = (uint32_t) bytes_to_num(t.nt.nti.nai.abtUid, 4); t.num_blocks = (t.b4K) ? 0xff : 0x3f; t.num_sectors = t.b4K ? NR_TRAILERS_4k : NR_TRAILERS_1k; @@ -191,7 +191,7 @@ int main(int argc, char * const argv[]) { } // Test if a compatible MIFARE tag is used - if ((t.ti.nai.btSak & 0x08) == 0) { + if ((t.nt.nti.nai.btSak & 0x08) == 0) { printf("Error: inserted tag is not a MIFARE Classic card\n"); nfc_disconnect(r.pdi); exit(1); @@ -206,7 +206,7 @@ int main(int argc, char * const argv[]) { // Try to authenticate to all sectors with default keys // Set the authentication information (uid) - memcpy(mp.mpa.abtUid, t.ti.nai.abtUid, sizeof(mp.mpa.abtUid)); + memcpy(mp.mpa.abtUid, t.nt.nti.nai.abtUid, sizeof(mp.mpa.abtUid)); // Iterate over all keys (n = number of keys) n = sizeof(defaultKeys)/sizeof(defaultKeys[0]); for (key = 0; key < n; key++) { @@ -276,7 +276,7 @@ int main(int argc, char * const argv[]) { for (m = 0; m < 2; ++m) { if (e_sector == -1) break; // All keys are default, I am skipping recovery mode for (j = 0; j < (t.num_sectors); ++j) { - memcpy(mp.mpa.abtUid, t.ti.nai.abtUid, sizeof(mp.mpa.abtUid)); + memcpy(mp.mpa.abtUid, t.nt.nti.nai.abtUid, sizeof(mp.mpa.abtUid)); if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) { // First, try already broken keys @@ -407,7 +407,7 @@ int main(int argc, char * const argv[]) { fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'A', bytes_to_num(t.sectors[i].KeyA, 6)); print_hex(mp.mpd.abtData, 16); mf_configure(r.pdi); - mf_select_tag(r.pdi, &t.ti); + mf_select_tag(r.pdi, &(t.nt)); failure = false; } else { // Error, now try read() with B key @@ -424,7 +424,7 @@ int main(int argc, char * const argv[]) { fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'B', bytes_to_num(t.sectors[i].KeyB, 6)); print_hex(mp.mpd.abtData, 16); mf_configure(r.pdi); - mf_select_tag(r.pdi, &t.ti); + mf_select_tag(r.pdi, &(t.nt)); failure = false; } else { mf_configure(r.pdi); @@ -440,7 +440,7 @@ int main(int argc, char * const argv[]) { memcpy(mtDump.amb[block].mbt.abtKeyB,t.sectors[i].KeyB,6); if (!failure) memcpy(mtDump.amb[block].mbt.abtAccessBits,mp.mpd.abtData+6,4); } else if (!failure) memcpy(mtDump.amb[block].mbd.abtData, mp.mpd.abtData,16); - memcpy(mp.mpa.abtUid,t.ti.nai.abtUid,4); + memcpy(mp.mpa.abtUid,t.nt.nti.nai.abtUid,4); } // Finally save all keys + data to file @@ -506,9 +506,13 @@ void mf_configure(nfc_device_t* pdi) { nfc_configure(pdi,NDO_ACTIVATE_FIELD,true); } -void mf_select_tag(nfc_device_t* pdi, nfc_target_info_t* ti) { +void mf_select_tag(nfc_device_t* pdi, nfc_target_t* pnt) { // Poll for a ISO14443A (MIFARE) tag - if (!nfc_initiator_select_passive_target(pdi,NM_ISO14443A_106,NULL,0,ti)) { + const nfc_modulation_t nm = { + .nmt = NMT_ISO14443A, + .nbr = NBR_106, + }; + if (!nfc_initiator_select_passive_target(pdi, nm, NULL, 0, pnt)) { fprintf(stderr, "!Error connecting to the MIFARE Classic tag\n"); nfc_disconnect(pdi); exit(1); @@ -547,7 +551,11 @@ int find_exploit_sector(mftag t) { } void mf_anticollision(mftag t, mfreader r) { - if (!nfc_initiator_select_passive_target(r.pdi, NM_ISO14443A_106, NULL, 0, &t.ti)) { + const nfc_modulation_t nm = { + .nmt = NMT_ISO14443A, + .nbr = NBR_106, + }; + if (!nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt)) { fprintf(stderr, "\n\n!Error: tag has been removed\n"); exit(1); } @@ -581,7 +589,7 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d // Prepare AUTH command Auth[0] = (t.sectors[e_sector].foundKeyA) ? 0x60 : 0x61; - append_iso14443a_crc(Auth,2); + iso14443a_crc_append (Auth,2); // fprintf(stdout, "\nAuth command:\t"); // print_hex(Auth, 4); @@ -724,7 +732,7 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d // Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC Auth[0] = dumpKeysA ? 0x60 : 0x61; Auth[1] = a_sector; - append_iso14443a_crc(Auth,2); + iso14443a_crc_append (Auth,2); // Encryption of the Auth command, sending the Auth command for (i = 0; i < 4; i++) { diff --git a/src/mfoc.h b/src/mfoc.h index 80d1a2f..e9786dd 100644 --- a/src/mfoc.h +++ b/src/mfoc.h @@ -40,7 +40,7 @@ typedef struct { } denonce; // Revealed information about nonce typedef struct { - nfc_target_info_t ti; + nfc_target_t nt; sector * sectors; // Allocate later, we do not know the number of sectors yet sector e_sector; // Exploit sector uint32_t num_sectors; @@ -72,7 +72,7 @@ typedef struct { void usage(FILE * stream, int errno); void mf_init(mftag *t, mfreader *r); void mf_configure(nfc_device_t* pdi); -void mf_select_tag(nfc_device_t* pdi, nfc_target_info_t* ti); +void mf_select_tag(nfc_device_t* pdi, nfc_target_t* pnt); int trailer_block(uint32_t block); int find_exploit_sector(mftag t); void mf_anticollision(mftag t, mfreader r); diff --git a/src/nfc-utils.c b/src/nfc-utils.c index 494cc8d..0a5b9b0 100644 --- a/src/nfc-utils.c +++ b/src/nfc-utils.c @@ -1,4 +1,5 @@ #include +#include #include "nfc-utils.h" @@ -97,34 +98,409 @@ print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDa printf ("\n"); } +#define SAK_UID_NOT_COMPLETE 0x04 #define SAK_ISO14443_4_COMPLIANT 0x20 #define SAK_ISO18092_COMPLIANT 0x40 void -print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai) +print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose) { printf (" ATQA (SENS_RES): "); print_hex (nai.abtAtqa, 2); + if (verbose) { + printf("* UID size: "); + switch ((nai.abtAtqa[1] & 0xc0)>>6) { + case 0: + printf("single\n"); + break; + case 1: + printf("double\n"); + break; + case 2: + printf("triple\n"); + break; + case 3: + printf("RFU\n"); + break; + } + printf("* bit frame anticollision "); + switch (nai.abtAtqa[1] & 0x1f) { + case 0x01: + case 0x02: + case 0x04: + case 0x08: + case 0x10: + printf("supported\n"); + break; + default: + printf("not supported\n"); + break; + } + } printf (" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1')); print_hex (nai.abtUid, nai.szUidLen); + if (verbose) { + if (nai.abtUid[0] == 0x08) { + printf ("* Random UID\n"); + } + } printf (" SAK (SEL_RES): "); print_hex (&nai.btSak, 1); + if (verbose) { + if (nai.btSak & SAK_UID_NOT_COMPLETE) { + printf ("* Warning! Cascade bit set: UID not complete\n"); + } + if (nai.btSak & SAK_ISO14443_4_COMPLIANT) { + printf ("* Compliant with ISO/IEC 14443-4\n"); + } else { + printf ("* Not compliant with ISO/IEC 14443-4\n"); + } + if (nai.btSak & SAK_ISO18092_COMPLIANT) { + printf ("* Compliant with ISO/IEC 18092\n"); + } else { + printf ("* Not compliant with ISO/IEC 18092\n"); + } + } if (nai.szAtsLen) { - printf (" ATS (ATR): "); + printf (" ATS: "); print_hex (nai.abtAts, nai.szAtsLen); } - if ((nai.btSak & SAK_ISO14443_4_COMPLIANT) || (nai.btSak & SAK_ISO18092_COMPLIANT)) { - printf (" Compliant with: "); - if (nai.btSak & SAK_ISO14443_4_COMPLIANT) - printf ("ISO/IEC 14443-4 "); - if (nai.btSak & SAK_ISO18092_COMPLIANT) - printf ("ISO/IEC 18092"); - printf ("\n"); + if (nai.szAtsLen && verbose) { + // Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select) + const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 }; + printf ("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]); + + size_t offset = 1; + if (nai.abtAts[0] & 0x10) { // TA(1) present + byte_t TA = nai.abtAts[offset]; + offset++; + printf ("* Bit Rate Capability:\n"); + if (TA == 0) { + printf (" * PICC supports only 106 kbits/s in both directions\n"); + } + if (TA & 1<<7) { + printf (" * Same bitrate in both directions mandatory\n"); + } + if (TA & 1<<4) { + printf (" * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n"); + } + if (TA & 1<<5) { + printf (" * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n"); + } + if (TA & 1<<6) { + printf (" * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n"); + } + if (TA & 1<<0) { + printf (" * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n"); + } + if (TA & 1<<1) { + printf (" * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n"); + } + if (TA & 1<<2) { + printf (" * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n"); + } + if (TA & 1<<3) { + printf (" * ERROR unknown value\n"); + } + } + if (nai.abtAts[0] & 0x20) { // TB(1) present + byte_t TB= nai.abtAts[offset]; + offset++; + printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((TB & 0xf0) >> 4))/13560.0); + if ((TB & 0x0f) == 0) { + printf ("* No Start-up Frame Guard Time required\n"); + } else { + printf ("* Start-up Frame Guard Time: %.4g ms\n",256.0*16.0*(1<<(TB & 0x0f))/13560.0); + } + } + if (nai.abtAts[0] & 0x40) { // TC(1) present + byte_t TC = nai.abtAts[offset]; + offset++; + if (TC & 0x1) { + printf("* Node ADdress supported\n"); + } else { + printf("* Node ADdress not supported\n"); + } + if (TC & 0x2) { + printf("* Card IDentifier supported\n"); + } else { + printf("* Card IDentifier not supported\n"); + } + } + if (nai.szAtsLen > offset) { + printf ("* Historical bytes Tk: " ); + print_hex (nai.abtAts + offset, (nai.szAtsLen - offset)); + byte_t CIB = nai.abtAts[offset]; + offset++; + if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) { + printf(" * Proprietary format\n"); + if (CIB == 0xc1) { + printf(" * Tag byte: Mifare or virtual cards of various types\n"); + byte_t L = nai.abtAts[offset]; + offset++; + if (L != (nai.szAtsLen - offset)) { + printf(" * Warning: Type Identification Coding length (%i)", L); + printf(" not matching Tk length (%zi)\n", (nai.szAtsLen - offset)); + } + if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes + byte_t CTC = nai.abtAts[offset]; + offset++; + printf(" * Chip Type: "); + switch (CTC & 0xf0) { + case 0x00: + printf("(Multiple) Virtual Cards\n"); + break; + case 0x10: + printf("Mifare DESFire\n"); + break; + case 0x20: + printf("Mifare Plus\n"); + break; + default: + printf("RFU\n"); + break; + } + printf(" * Memory size: "); + switch (CTC & 0x0f) { + case 0x00: + printf("<1 kbyte\n"); + break; + case 0x01: + printf("1 kbyte\n"); + break; + case 0x02: + printf("2 kbyte\n"); + break; + case 0x03: + printf("4 kbyte\n"); + break; + case 0x04: + printf("8 kbyte\n"); + break; + case 0x0f: + printf("Unspecified\n"); + break; + default: + printf("RFU\n"); + break; + } + } + if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes + byte_t CVC = nai.abtAts[offset]; + offset++; + printf(" * Chip Status: "); + switch (CVC & 0xf0) { + case 0x00: + printf("Engineering sample\n"); + break; + case 0x20: + printf("Released\n"); + break; + default: + printf("RFU\n"); + break; + } + printf(" * Chip Generation: "); + switch (CVC & 0x0f) { + case 0x00: + printf("Generation 1\n"); + break; + case 0x01: + printf("Generation 2\n"); + break; + case 0x02: + printf("Generation 3\n"); + break; + case 0x0f: + printf("Unspecified\n"); + break; + default: + printf("RFU\n"); + break; + } + } + if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes + byte_t VCS = nai.abtAts[offset]; + offset++; + printf(" * Specifics (Virtual Card Selection):\n"); + if ((VCS & 0x09) == 0x00) { + printf(" * Only VCSL supported\n"); + } else if ((VCS & 0x09) == 0x01) { + printf(" * VCS, VCSL and SVC supported\n"); + } + if ((VCS & 0x0e) == 0x00) { + printf(" * SL1, SL2(?), SL3 supported\n"); + } else if ((VCS & 0x0e) == 0x02) { + printf(" * SL3 only card\n"); + } else if ((VCS & 0x0f) == 0x0e) { + printf(" * No VCS command supported\n"); + } else if ((VCS & 0x0f) == 0x0f) { + printf(" * Unspecified\n"); + } else { + printf(" * RFU\n"); + } + } + } + } else { + if (CIB == 0x00) { + printf(" * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n"); + printf(" followed by a mandatory status indicator (the last three bytes, not in TLV)\n"); + printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n"); + } + if (CIB == 0x10) { + printf(" * DIR data reference: %02x\n", nai.abtAts[offset]); + } + if (CIB == 0x80) { + if (nai.szAtsLen == offset) { + printf(" * No COMPACT-TLV objects found, no status found\n"); + } else { + printf(" * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n"); + printf(" the last data object may carry a status indicator of one, two or three bytes.\n"); + printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n"); + } + } + } + } + } + if (verbose) { + printf("Fingerprinting based on ATQA & SAK values:\n"); + uint32_t atqasak = 0; + atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff)<<16); + atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff)<<8); + atqasak += ((uint32_t)nai.btSak & 0xff); + bool found_possible_match = false; + switch (atqasak) { + case 0x000218: + printf("* Mifare Classic 4K\n"); + found_possible_match = true; + break; + case 0x000408: + printf("* Mifare Classic 1K\n"); + printf("* Mifare Plus (4-byte UID) 2K SL1\n"); + found_possible_match = true; + break; + case 0x000409: + printf("* Mifare MINI\n"); + found_possible_match = true; + break; + case 0x000410: + printf("* Mifare Plus (4-byte UID) 2K SL2\n"); + found_possible_match = true; + break; + case 0x000411: + printf("* Mifare Plus (4-byte UID) 4K SL2\n"); + found_possible_match = true; + break; + case 0x000418: + printf("* Mifare Plus (4-byte UID) 4K SL1\n"); + found_possible_match = true; + break; + case 0x000420: + printf("* Mifare Plus (4-byte UID) 2K/4K SL3\n"); + found_possible_match = true; + break; + case 0x004400: + printf("* Mifare Ultralight\n"); + printf("* Mifare UltralightC\n"); + found_possible_match = true; + break; + case 0x004208: + case 0x004408: + printf("* Mifare Plus (7-byte UID) 2K SL1\n"); + found_possible_match = true; + break; + case 0x004218: + case 0x004418: + printf("* Mifare Plus (7-byte UID) 4K SL1\n"); + found_possible_match = true; + break; + case 0x004210: + case 0x004410: + printf("* Mifare Plus (7-byte UID) 2K SL2\n"); + found_possible_match = true; + break; + case 0x004211: + case 0x004411: + printf("* Mifare Plus (7-byte UID) 4K SL2\n"); + found_possible_match = true; + break; + case 0x004220: + case 0x004420: + printf("* Mifare Plus (7-byte UID) 2K/4K SL3\n"); + found_possible_match = true; + break; + case 0x034420: + printf("* Mifare DESFire / Desfire EV1\n"); + found_possible_match = true; + break; + } + + // Other matches not described in + // AN MIFARE Type Identification Procedure + // but seen in the field: + switch (atqasak) { + case 0x000488: + printf("* Mifare Classic 1K Infineon\n"); + found_possible_match = true; + break; + case 0x000298: + printf("* Gemplus MPCOS\n"); + found_possible_match = true; + break; + case 0x030428: + printf("* JCOP31\n"); + found_possible_match = true; + break; + case 0x004820: + printf("* JCOP31 v2.4.1\n"); + printf("* JCOP31 v2.2\n"); + found_possible_match = true; + break; + case 0x000428: + printf("* JCOP31 v2.3.1\n"); + found_possible_match = true; + break; + case 0x000453: + printf("* Fudan FM1208SH01\n"); + found_possible_match = true; + break; + case 0x000820: + printf("* Fudan FM1208\n"); + found_possible_match = true; + break; + case 0x000238: + printf("* MFC 4K emulated by Nokia 6212 Classic\n"); + found_possible_match = true; + break; + case 0x000838: + printf("* MFC 4K emulated by Nokia 6131 NFC\n"); + found_possible_match = true; + break; + } + if ((nai.abtAtqa[0] & 0xf0) == 0) { + switch (nai.abtAtqa[1]) { + case 0x02: + printf("* SmartMX with Mifare 4K emulation\n"); + found_possible_match = true; + break; + case 0x04: + printf("* SmartMX with Mifare 1K emulation\n"); + found_possible_match = true; + break; + case 0x48: + printf("* SmartMX with 7-byte UID\n"); + found_possible_match = true; + break; + } + } + if (! found_possible_match) { + printf("* Unknown card, sorry\n"); + } } } void -print_nfc_felica_info (const nfc_felica_info_t nfi) +print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose) { printf (" ID (NFCID2): "); print_hex (nfi.abtId, 8); @@ -133,18 +509,85 @@ print_nfc_felica_info (const nfc_felica_info_t nfi) } void -print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi) +print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose) { - printf (" ATQB: "); - print_hex (nbi.abtAtqb, 12); - printf (" ID: "); - print_hex (nbi.abtId, 4); - printf (" CID: %02x\n", nbi.btCid); - if (nbi.szInfLen > 0) { - printf (" INF: "); - print_hex (nbi.abtInf, nbi.szInfLen); + printf (" ATQA (SENS_RES): "); + print_hex (nji.btSensRes, 2); + printf (" 4-LSB JEWELID: "); + print_hex (nji.btId, 4); +} + +#define PI_ISO14443_4_SUPPORTED 0x01 +#define PI_NAD_SUPPORTED 0x01 +#define PI_CID_SUPPORTED 0x02 +void +print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose) +{ + const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 }; + printf (" PUPI: "); + print_hex (nbi.abtPupi, 4); + printf (" Application Data: "); + print_hex (nbi.abtApplicationData, 4); + printf (" Protocol Info: "); + print_hex (nbi.abtProtocolInfo, 3); + if (verbose) { + printf ("* Bit Rate Capability:\n"); + if (nbi.abtProtocolInfo[0] == 0) { + printf (" * PICC supports only 106 kbits/s in both directions\n"); + } + if (nbi.abtProtocolInfo[0] & 1<<7) { + printf (" * Same bitrate in both directions mandatory\n"); + } + if (nbi.abtProtocolInfo[0] & 1<<4) { + printf (" * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n"); + } + if (nbi.abtProtocolInfo[0] & 1<<5) { + printf (" * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n"); + } + if (nbi.abtProtocolInfo[0] & 1<<6) { + printf (" * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n"); + } + if (nbi.abtProtocolInfo[0] & 1<<0) { + printf (" * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n"); + } + if (nbi.abtProtocolInfo[0] & 1<<1) { + printf (" * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n"); + } + if (nbi.abtProtocolInfo[0] & 1<<2) { + printf (" * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n"); + } + if (nbi.abtProtocolInfo[0] & 1<<3) { + printf (" * ERROR unknown value\n"); + } + if( (nbi.abtProtocolInfo[1] & 0xf0) <= 0x80 ) { + printf ("* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]); + } + if((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) { + printf ("* Protocol types supported: ISO/IEC 14443-4\n"); + } + printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((nbi.abtProtocolInfo[2] & 0xf0) >> 4))/13560.0); + if((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED|PI_CID_SUPPORTED)) != 0) { + printf ("* Frame options supported: "); + if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) printf ("NAD "); + if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) printf ("CID "); + printf("\n"); + } + } +} + +void +print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose) +{ + printf (" NFCID3: "); + print_hex (ndi.abtNFCID3, 10); + printf (" BS: %02x\n", ndi.btBS); + printf (" BR: %02x\n", ndi.btBR); + printf (" TO: %02x\n", ndi.btTO); + printf (" PP: %02x\n", ndi.btPP); + if (ndi.szGB) { + printf ("General Bytes: "); + print_hex (ndi.abtGB, ndi.szGB); } - printf (" PARAMS: %02x %02x %02x %02x\n", nbi.btParam1, nbi.btParam2, nbi.btParam3, nbi.btParam4); } /** @@ -152,7 +595,7 @@ print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi) * @return Returns the list of found device descriptions. */ nfc_device_desc_t * -parse_device_desc (int argc, const char *argv[], size_t * szFound) +parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose) { nfc_device_desc_t *pndd = 0; int arg; @@ -162,7 +605,7 @@ parse_device_desc (int argc, const char *argv[], size_t * szFound) for (arg = 1; arg < argc; arg++) { if (0 == strcmp (argv[arg], "--device")) { - + // FIXME: this device selection by command line options is terrible & does not support USB/PCSC drivers if (argc > arg + 1) { char buffer[256]; @@ -182,10 +625,64 @@ parse_device_desc (int argc, const char *argv[], size_t * szFound) sscanf (strtok (NULL, ":"), "%u", &pndd->uiSpeed); *szFound = 1; + } else { + errx (1, "usage: %s [--device driver:port:speed]", argv[0]); } - break; + } + if ((0 == strcmp (argv[arg], "-v")) || (0 == strcmp (argv[arg], "--verbose"))) { + *verbose = true; } } - return pndd; } + +const char * +str_nfc_baud_rate (const nfc_baud_rate_t nbr) +{ + switch(nbr) { + case NBR_UNDEFINED: + return "undefined baud rate"; + break; + case NBR_106: + return "106 kbps"; + break; + case NBR_212: + return "212 kbps"; + break; + case NBR_424: + return "424 kbps"; + break; + case NBR_847: + return "847 kbps"; + break; + } + return ""; +} + +void +print_nfc_target (const nfc_target_t nt, bool verbose) +{ + switch(nt.nm.nmt) { + case NMT_ISO14443A: + printf ("ISO/IEC 14443A (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr)); + print_nfc_iso14443a_info (nt.nti.nai, verbose); + break; + case NMT_JEWEL: + printf ("Innovision Jewel (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr)); + print_nfc_jewel_info (nt.nti.nji, verbose); + break; + case NMT_FELICA: + printf ("FeliCa (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr)); + print_nfc_felica_info (nt.nti.nfi, verbose); + break; + case NMT_ISO14443B: + printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr)); + print_nfc_iso14443b_info (nt.nti.nbi, verbose); + break; + case NMT_DEP: + printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr)); + print_nfc_dep_info (nt.nti.ndi, verbose); + break; + } +} + diff --git a/src/nfc-utils.h b/src/nfc-utils.h index 5f7ea46..2df7981 100644 --- a/src/nfc-utils.h +++ b/src/nfc-utils.h @@ -34,10 +34,14 @@ void print_hex (const byte_t * pbtData, const size_t szLen); void print_hex_bits (const byte_t * pbtData, const size_t szBits); void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar); -void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai); -void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi); -void print_nfc_felica_info (const nfc_felica_info_t nfi); +void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose); +void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose); +void print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose); +void print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose); +void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose); -nfc_device_desc_t *parse_device_desc (int argc, const char *argv[], size_t * szFound); +void print_nfc_target (const nfc_target_t nt, bool verbose); + +nfc_device_desc_t *parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose); #endif