passy_reader.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. #include "passy_reader.h"
  2. #define ASN_EMIT_DEBUG 0
  3. #include <lib/asn1/COM.h>
  4. #define TAG "PassyReader"
  5. #define PASSY_READER_DG1_CHUNK_SIZE 0x20
  6. #define PASSY_READER_DG2_CHUNK_SIZE 0x20
  7. #define PASSY_DG2_LOOKAHEAD 120
  8. static uint8_t passport_aid[] = {0xA0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01};
  9. static uint8_t select_header[] = {0x00, 0xA4, 0x04, 0x0C};
  10. static uint8_t get_challenge[] = {0x00, 0x84, 0x00, 0x00, 0x08};
  11. static uint8_t SW_success[] = {0x90, 0x00};
  12. static const uint8_t jpeg_header[4] = {0xFF, 0xD8, 0xFF, 0xE0};
  13. static const uint8_t jpeg2k_header[6] = {0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50};
  14. static const uint8_t jpeg2k_cs_header[4] = {0xFF, 0x4F, 0xFF, 0x51};
  15. static bool print_logs = true;
  16. size_t asn1_length(uint8_t data[3]) {
  17. if(data[0] <= 0x7F) {
  18. return data[0];
  19. } else if(data[0] == 0x81) {
  20. return data[1];
  21. } else if(data[0] == 0x82) {
  22. return (data[1] << 8) | data[2];
  23. }
  24. return 0;
  25. }
  26. size_t asn1_length_length(uint8_t data[3]) {
  27. if(data[0] <= 0x7F) {
  28. return 1;
  29. } else if(data[0] == 0x81) {
  30. return 2;
  31. } else if(data[0] == 0x82) {
  32. return 3;
  33. }
  34. return 0;
  35. }
  36. PassyReader* passy_reader_alloc(Passy* passy) {
  37. PassyReader* passy_reader = malloc(sizeof(PassyReader));
  38. memset(passy_reader, 0, sizeof(PassyReader));
  39. furi_assert(passy);
  40. passy_reader->passy = passy;
  41. passy_reader->DG1 = passy->DG1;
  42. passy_reader->COM = passy->COM;
  43. passy_reader->dg_header = passy->dg_header;
  44. passy_reader->tx_buffer = bit_buffer_alloc(PASSY_READER_MAX_BUFFER_SIZE);
  45. passy_reader->rx_buffer = bit_buffer_alloc(PASSY_READER_MAX_BUFFER_SIZE);
  46. char passport_number[11];
  47. memset(passport_number, 0, sizeof(passport_number));
  48. memcpy(passport_number, passy->passport_number, strlen(passy->passport_number));
  49. passport_number[strlen(passy->passport_number)] = passy_checksum(passy->passport_number);
  50. FURI_LOG_I(TAG, "Passport number: %s", passport_number);
  51. char date_of_birth[8];
  52. memset(date_of_birth, 0, sizeof(date_of_birth));
  53. memcpy(date_of_birth, passy->date_of_birth, strlen(passy->date_of_birth));
  54. date_of_birth[strlen(passy->date_of_birth)] = passy_checksum(passy->date_of_birth);
  55. FURI_LOG_I(TAG, "Date of birth: %s", date_of_birth);
  56. char date_of_expiry[8];
  57. memset(date_of_expiry, 0, sizeof(date_of_expiry));
  58. memcpy(date_of_expiry, passy->date_of_expiry, strlen(passy->date_of_expiry));
  59. date_of_expiry[strlen(passy->date_of_expiry)] = passy_checksum(passy->date_of_expiry);
  60. FURI_LOG_I(TAG, "Date of expiry: %s", date_of_expiry);
  61. passy_reader->secure_messaging = secure_messaging_alloc(
  62. (uint8_t*)passport_number, (uint8_t*)date_of_birth, (uint8_t*)date_of_expiry);
  63. return passy_reader;
  64. }
  65. void passy_reader_free(PassyReader* passy_reader) {
  66. furi_assert(passy_reader);
  67. bit_buffer_free(passy_reader->tx_buffer);
  68. bit_buffer_free(passy_reader->rx_buffer);
  69. if(passy_reader->secure_messaging) {
  70. secure_messaging_free(passy_reader->secure_messaging);
  71. }
  72. free(passy_reader);
  73. }
  74. NfcCommand passy_reader_send(PassyReader* passy_reader) {
  75. NfcCommand ret = NfcCommandContinue;
  76. Passy* passy = passy_reader->passy;
  77. BitBuffer* tx_buffer = passy_reader->tx_buffer;
  78. BitBuffer* rx_buffer = passy_reader->rx_buffer;
  79. if(strcmp(passy->proto, "4a") == 0) {
  80. Iso14443_4aPoller* iso14443_4a_poller = passy_reader->iso14443_4a_poller;
  81. Iso14443_4aError error;
  82. if(print_logs) {
  83. passy_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  84. }
  85. error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
  86. if(error != Iso14443_4aErrorNone) {
  87. FURI_LOG_W(TAG, "iso14443_4a_poller_send_block error %d", error);
  88. return NfcCommandStop;
  89. }
  90. } else if(strcmp(passy->proto, "4b") == 0) {
  91. Iso14443_4bPoller* iso14443_4b_poller = passy_reader->iso14443_4b_poller;
  92. Iso14443_4bError error;
  93. if(print_logs) {
  94. passy_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  95. }
  96. error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  97. if(error != Iso14443_4bErrorNone) {
  98. FURI_LOG_W(TAG, "iso14443_4b_poller_send_block error %d", error);
  99. return NfcCommandStop;
  100. }
  101. } else {
  102. FURI_LOG_W(TAG, "Unknown protocol %s", passy->proto);
  103. return NfcCommandStop;
  104. }
  105. bit_buffer_reset(tx_buffer);
  106. if(print_logs) {
  107. passy_log_bitbuffer(TAG, "NFC response", rx_buffer);
  108. }
  109. // Check SW
  110. size_t length = bit_buffer_get_size_bytes(rx_buffer);
  111. const uint8_t* data = bit_buffer_get_data(rx_buffer);
  112. if(length < 2) {
  113. FURI_LOG_W(TAG, "Invalid response length %d", length);
  114. return NfcCommandStop;
  115. }
  116. passy_reader->last_sw = (data[length - 2] << 8) | data[length - 1];
  117. if(memcmp(data + length - 2, SW_success, sizeof(SW_success)) != 0) {
  118. FURI_LOG_W(TAG, "Invalid SW %02x %02x", data[length - 2], data[length - 1]);
  119. return NfcCommandStop;
  120. }
  121. return ret;
  122. }
  123. NfcCommand passy_reader_select_application(PassyReader* passy_reader) {
  124. NfcCommand ret = NfcCommandContinue;
  125. BitBuffer* tx_buffer = passy_reader->tx_buffer;
  126. bit_buffer_append_bytes(tx_buffer, select_header, sizeof(select_header));
  127. bit_buffer_append_byte(tx_buffer, sizeof(passport_aid));
  128. bit_buffer_append_bytes(tx_buffer, passport_aid, sizeof(passport_aid));
  129. ret = passy_reader_send(passy_reader);
  130. if(ret != NfcCommandContinue) {
  131. return ret;
  132. }
  133. return ret;
  134. }
  135. NfcCommand passy_reader_get_challenge(PassyReader* passy_reader) {
  136. NfcCommand ret = NfcCommandContinue;
  137. bit_buffer_append_bytes(passy_reader->tx_buffer, get_challenge, sizeof(get_challenge));
  138. ret = passy_reader_send(passy_reader);
  139. if(ret != NfcCommandContinue) {
  140. return ret;
  141. }
  142. const uint8_t* data = bit_buffer_get_data(passy_reader->rx_buffer);
  143. SecureMessaging* secure_messaging = passy_reader->secure_messaging;
  144. const uint8_t* rnd_icc = data;
  145. memcpy(secure_messaging->rndICC, rnd_icc, 8);
  146. return ret;
  147. }
  148. NfcCommand passy_reader_authenticate(PassyReader* passy_reader) {
  149. NfcCommand ret = NfcCommandContinue;
  150. BitBuffer* tx_buffer = passy_reader->tx_buffer;
  151. // TODO: move into secure_messaging
  152. SecureMessaging* secure_messaging = passy_reader->secure_messaging;
  153. uint8_t S[32];
  154. memset(S, 0, sizeof(S));
  155. uint8_t eifd[32];
  156. memcpy(S, secure_messaging->rndIFD, sizeof(secure_messaging->rndIFD));
  157. memcpy(
  158. S + sizeof(secure_messaging->rndIFD),
  159. secure_messaging->rndICC,
  160. sizeof(secure_messaging->rndICC));
  161. memcpy(
  162. S + sizeof(secure_messaging->rndIFD) + sizeof(secure_messaging->rndICC),
  163. secure_messaging->Kifd,
  164. sizeof(secure_messaging->Kifd));
  165. uint8_t iv[8];
  166. memset(iv, 0, sizeof(iv));
  167. mbedtls_des3_context ctx;
  168. mbedtls_des3_init(&ctx);
  169. mbedtls_des3_set2key_enc(&ctx, secure_messaging->KENC);
  170. mbedtls_des3_crypt_cbc(&ctx, MBEDTLS_DES_ENCRYPT, sizeof(S), iv, S, eifd);
  171. mbedtls_des3_free(&ctx);
  172. passy_log_buffer(TAG, "S", S, sizeof(S));
  173. passy_log_buffer(TAG, "eifd", eifd, sizeof(eifd));
  174. uint8_t mifd[8];
  175. passy_mac(secure_messaging->KMAC, eifd, sizeof(eifd), mifd, false);
  176. passy_log_buffer(TAG, "mifd", mifd, sizeof(mifd));
  177. uint8_t authenticate_header[] = {0x00, 0x82, 0x00, 0x00};
  178. bit_buffer_append_bytes(tx_buffer, authenticate_header, sizeof(authenticate_header));
  179. bit_buffer_append_byte(tx_buffer, sizeof(eifd) + sizeof(mifd));
  180. bit_buffer_append_bytes(tx_buffer, eifd, sizeof(eifd));
  181. bit_buffer_append_bytes(tx_buffer, mifd, sizeof(mifd));
  182. bit_buffer_append_byte(tx_buffer, 0); // Le
  183. ret = passy_reader_send(passy_reader);
  184. if(ret != NfcCommandContinue) {
  185. return ret;
  186. }
  187. const uint8_t* data = bit_buffer_get_data(passy_reader->rx_buffer);
  188. size_t length = bit_buffer_get_size_bytes(passy_reader->rx_buffer);
  189. const uint8_t* mac = data + length - 2 - 8;
  190. uint8_t calculated_mac[8];
  191. passy_mac(secure_messaging->KMAC, (uint8_t*)data, length - 8 - 2, calculated_mac, false);
  192. if(memcmp(mac, calculated_mac, sizeof(calculated_mac)) != 0) {
  193. FURI_LOG_W(TAG, "Invalid MAC");
  194. return NfcCommandStop;
  195. }
  196. uint8_t decrypted[32];
  197. do {
  198. uint8_t iv[8];
  199. memset(iv, 0, sizeof(iv));
  200. mbedtls_des3_context ctx;
  201. mbedtls_des3_init(&ctx);
  202. mbedtls_des3_set2key_dec(&ctx, secure_messaging->KENC);
  203. mbedtls_des3_crypt_cbc(&ctx, MBEDTLS_DES_DECRYPT, length - 2 - 8, iv, data, decrypted);
  204. mbedtls_des3_free(&ctx);
  205. } while(false);
  206. if(print_logs) {
  207. passy_log_buffer(TAG, "decrypted", decrypted, sizeof(decrypted));
  208. }
  209. uint8_t* rnd_icc = decrypted;
  210. uint8_t* rnd_ifd = decrypted + 8;
  211. uint8_t* Kicc = decrypted + 16;
  212. if(memcmp(rnd_icc, secure_messaging->rndICC, sizeof(secure_messaging->rndICC)) != 0) {
  213. FURI_LOG_W(TAG, "Invalid rndICC");
  214. return NfcCommandStop;
  215. }
  216. memcpy(secure_messaging->Kicc, Kicc, sizeof(secure_messaging->Kicc));
  217. memcpy(secure_messaging->SSC + 0, rnd_icc + 4, 4);
  218. memcpy(secure_messaging->SSC + 4, rnd_ifd + 4, 4);
  219. return ret;
  220. }
  221. NfcCommand passy_reader_select_file(PassyReader* passy_reader, uint16_t file_id) {
  222. NfcCommand ret = NfcCommandContinue;
  223. uint8_t select_0101[] = {0x00, 0xa4, 0x02, 0x0c, 0x02, 0x00, 0x00};
  224. select_0101[5] = (file_id >> 8) & 0xFF;
  225. select_0101[6] = file_id & 0xFF;
  226. secure_messaging_wrap_apdu(
  227. passy_reader->secure_messaging, select_0101, sizeof(select_0101), passy_reader->tx_buffer);
  228. ret = passy_reader_send(passy_reader);
  229. if(ret != NfcCommandContinue) {
  230. return ret;
  231. }
  232. secure_messaging_unwrap_rapdu(passy_reader->secure_messaging, passy_reader->rx_buffer);
  233. if(print_logs) {
  234. passy_log_bitbuffer(TAG, "NFC response (decrypted)", passy_reader->rx_buffer);
  235. }
  236. return ret;
  237. }
  238. NfcCommand passy_reader_read_binary(
  239. PassyReader* passy_reader,
  240. uint16_t offset,
  241. uint8_t Le,
  242. uint8_t* output_buffer) {
  243. NfcCommand ret = NfcCommandContinue;
  244. if(offset & 0x8000) {
  245. FURI_LOG_W(TAG, "Invalid offset %04x", offset);
  246. }
  247. uint8_t read_binary[] = {0x00, 0xB0, (offset >> 8) & 0xff, (offset >> 0) & 0xff, Le};
  248. secure_messaging_wrap_apdu(
  249. passy_reader->secure_messaging, read_binary, sizeof(read_binary), passy_reader->tx_buffer);
  250. ret = passy_reader_send(passy_reader);
  251. if(ret != NfcCommandContinue) {
  252. return ret;
  253. }
  254. secure_messaging_unwrap_rapdu(passy_reader->secure_messaging, passy_reader->rx_buffer);
  255. if(print_logs) {
  256. passy_log_bitbuffer(TAG, "NFC response (decrypted)", passy_reader->rx_buffer);
  257. }
  258. const uint8_t* decrypted_data = bit_buffer_get_data(passy_reader->rx_buffer);
  259. memcpy(output_buffer, decrypted_data, Le);
  260. return ret;
  261. }
  262. NfcCommand passy_reader_read_com(PassyReader* passy_reader) {
  263. NfcCommand ret = NfcCommandContinue;
  264. Passy* passy = passy_reader->passy;
  265. bit_buffer_reset(passy_reader->COM);
  266. uint8_t header[4];
  267. ret = passy_reader_read_binary(passy_reader, 0x00, sizeof(header), header);
  268. if(ret != NfcCommandContinue) {
  269. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  270. return ret;
  271. }
  272. size_t body_size = 1 + asn1_length_length(header + 1) + asn1_length(header + 1);
  273. uint8_t body_offset = sizeof(header);
  274. bit_buffer_append_bytes(passy_reader->COM, header, sizeof(header));
  275. do {
  276. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderReading);
  277. uint8_t chunk[PASSY_READER_DG1_CHUNK_SIZE];
  278. uint8_t Le = MIN(sizeof(chunk), (size_t)(body_size - body_offset));
  279. ret = passy_reader_read_binary(passy_reader, body_offset, Le, chunk);
  280. if(ret != NfcCommandContinue) {
  281. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  282. break;
  283. }
  284. bit_buffer_append_bytes(passy_reader->COM, chunk, Le);
  285. body_offset += Le;
  286. } while(body_offset < body_size);
  287. return ret;
  288. }
  289. NfcCommand passy_reader_read_dg1(PassyReader* passy_reader) {
  290. NfcCommand ret = NfcCommandContinue;
  291. Passy* passy = passy_reader->passy;
  292. bit_buffer_reset(passy->DG1);
  293. uint8_t header[4];
  294. ret = passy_reader_read_binary(passy_reader, 0x00, sizeof(header), header);
  295. if(ret != NfcCommandContinue) {
  296. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  297. return ret;
  298. }
  299. size_t body_size = 1 + asn1_length_length(header + 1) + asn1_length(header + 1);
  300. uint8_t body_offset = sizeof(header);
  301. bit_buffer_append_bytes(passy_reader->DG1, header, sizeof(header));
  302. do {
  303. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderReading);
  304. uint8_t chunk[PASSY_READER_DG1_CHUNK_SIZE];
  305. uint8_t Le = MIN(sizeof(chunk), (size_t)(body_size - body_offset));
  306. ret = passy_reader_read_binary(passy_reader, body_offset, Le, chunk);
  307. if(ret != NfcCommandContinue) {
  308. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  309. break;
  310. }
  311. bit_buffer_append_bytes(passy_reader->DG1, chunk, Le);
  312. body_offset += Le;
  313. } while(body_offset < body_size);
  314. passy_log_bitbuffer(TAG, "DG1", passy_reader->DG1);
  315. return ret;
  316. }
  317. NfcCommand passy_reader_read_dg2_or_dg7(PassyReader* passy_reader) {
  318. NfcCommand ret = NfcCommandContinue;
  319. Passy* passy = passy_reader->passy;
  320. uint8_t header[PASSY_DG2_LOOKAHEAD];
  321. ret = passy_reader_read_binary(passy_reader, 0x00, sizeof(header) / 2, header);
  322. if(ret != NfcCommandContinue) {
  323. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  324. return ret;
  325. }
  326. // Issue with reading whole 120 bytes at once, so we read 60 bytes and then
  327. ret = passy_reader_read_binary(
  328. passy_reader, sizeof(header) / 2, sizeof(header) / 2, header + sizeof(header) / 2);
  329. if(ret != NfcCommandContinue) {
  330. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  331. return ret;
  332. }
  333. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderReading);
  334. size_t body_size = 1 + asn1_length_length(header + 1) + asn1_length(header + 1);
  335. FURI_LOG_I(TAG, "%s length: %d", passy->read_type == PassyReadDG2 ? "DG2" : "DG7", body_size);
  336. void* jpeg = memmem(header, sizeof(header), jpeg_header, sizeof(jpeg_header));
  337. void* jpeg2k = memmem(header, sizeof(header), jpeg2k_header, sizeof(jpeg2k_header));
  338. void* jpeg2k_cs = memmem(header, sizeof(header), jpeg2k_cs_header, sizeof(jpeg2k_cs_header));
  339. FuriString* path = furi_string_alloc();
  340. uint8_t start = 0;
  341. const char* dg_type = passy->read_type == PassyReadDG2 ? "DG2" : "DG7";
  342. char* dg_ext = ".bin";
  343. if(jpeg) {
  344. dg_ext = ".jpeg";
  345. start = (uint8_t*)jpeg - header;
  346. } else if(jpeg2k) {
  347. dg_ext = ".jp2";
  348. start = (uint8_t*)jpeg2k - header;
  349. } else if(jpeg2k_cs) {
  350. dg_ext = ".jpc";
  351. start = (uint8_t*)jpeg2k_cs - header;
  352. } else {
  353. dg_ext = ".bin";
  354. start = 0;
  355. }
  356. furi_string_printf(path, "%s/%s%s", STORAGE_APP_DATA_PATH_PREFIX, dg_type, dg_ext);
  357. FURI_LOG_I(TAG, "Writing offset %d to %s", start, furi_string_get_cstr(path));
  358. Storage* storage = furi_record_open(RECORD_STORAGE);
  359. Stream* stream = file_stream_alloc(storage);
  360. file_stream_open(stream, furi_string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_ALWAYS);
  361. uint8_t chunk[PASSY_READER_DG2_CHUNK_SIZE];
  362. passy->offset = start;
  363. passy->bytes_total = body_size;
  364. do {
  365. memset(chunk, 0, sizeof(chunk));
  366. uint8_t Le = MIN(sizeof(chunk), (size_t)(body_size - passy->offset));
  367. ret = passy_reader_read_binary(passy_reader, passy->offset, Le, chunk);
  368. if(ret != NfcCommandContinue) {
  369. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  370. break;
  371. }
  372. passy->offset += Le;
  373. // passy_log_buffer(TAG, "chunk", chunk, sizeof(chunk));
  374. stream_write(stream, chunk, Le);
  375. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderReading);
  376. } while(passy->offset < body_size);
  377. file_stream_close(stream);
  378. furi_record_close(RECORD_STORAGE);
  379. furi_string_free(path);
  380. return ret;
  381. }
  382. NfcCommand passy_reader_state_machine(PassyReader* passy_reader) {
  383. furi_assert(passy_reader);
  384. Passy* passy = passy_reader->passy;
  385. NfcCommand ret = NfcCommandContinue;
  386. do {
  387. ret = passy_reader_select_application(passy_reader);
  388. if(ret != NfcCommandContinue) {
  389. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  390. break;
  391. }
  392. ret = passy_reader_get_challenge(passy_reader);
  393. if(ret != NfcCommandContinue) {
  394. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  395. break;
  396. }
  397. ret = passy_reader_authenticate(passy_reader);
  398. if(ret != NfcCommandContinue) {
  399. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  400. break;
  401. }
  402. FURI_LOG_I(TAG, "Mututal authentication success");
  403. secure_messaging_calculate_session_keys(passy_reader->secure_messaging);
  404. view_dispatcher_send_custom_event(
  405. passy->view_dispatcher, PassyCustomEventReaderAuthenticated);
  406. ret = passy_reader_select_file(passy_reader, passy->read_type);
  407. if(ret != NfcCommandContinue) {
  408. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  409. break;
  410. }
  411. if(passy->read_type == PassyReadCOM) {
  412. ret = passy_reader_read_com(passy_reader);
  413. } else if(passy->read_type == PassyReadDG1) {
  414. ret = passy_reader_read_dg1(passy_reader);
  415. } else if(passy->read_type == PassyReadDG2) {
  416. print_logs = false;
  417. ret = passy_reader_read_dg2_or_dg7(passy_reader);
  418. print_logs = true;
  419. } else if(passy->read_type == PassyReadDG7) {
  420. print_logs = false;
  421. ret = passy_reader_read_dg2_or_dg7(passy_reader);
  422. print_logs = true;
  423. } else {
  424. // Until file specific handling is implemented, we just read the header
  425. bit_buffer_reset(passy_reader->dg_header);
  426. uint8_t header[4];
  427. ret = passy_reader_read_binary(passy_reader, 0x00, sizeof(header), header);
  428. if(ret != NfcCommandContinue) {
  429. view_dispatcher_send_custom_event(
  430. passy->view_dispatcher, PassyCustomEventReaderError);
  431. break;
  432. }
  433. bit_buffer_append_bytes(passy_reader->dg_header, header, sizeof(header));
  434. }
  435. // Everything done
  436. ret = NfcCommandStop;
  437. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderSuccess);
  438. } while(false);
  439. return ret;
  440. }
  441. NfcCommand passy_reader_poller_callback(NfcGenericEvent event, void* context) {
  442. PassyReader* passy_reader = context;
  443. NfcCommand ret = NfcCommandContinue;
  444. Passy* passy = passy_reader->passy;
  445. if(strcmp(passy->proto, "4a") == 0) {
  446. furi_assert(event.protocol == NfcProtocolIso14443_4a);
  447. const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
  448. Iso14443_4aPoller* iso14443_4a_poller = event.instance;
  449. FURI_LOG_D(TAG, "iso14443_4a_event->type %i", iso14443_4a_event->type);
  450. passy_reader->iso14443_4a_poller = iso14443_4a_poller;
  451. if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
  452. nfc_device_set_data(
  453. passy_reader->passy->nfc_device,
  454. NfcProtocolIso14443_4a,
  455. nfc_poller_get_data(passy_reader->passy->poller));
  456. ret = passy_reader_state_machine(passy_reader);
  457. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  458. } else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) {
  459. Iso14443_4aPollerEventData* data = iso14443_4a_event->data;
  460. Iso14443_4aError error = data->error;
  461. FURI_LOG_W(TAG, "Iso14443_4aError %i", error);
  462. switch(error) {
  463. case Iso14443_4aErrorNone:
  464. break;
  465. case Iso14443_4aErrorNotPresent:
  466. break;
  467. case Iso14443_4aErrorProtocol:
  468. ret = NfcCommandStop;
  469. break;
  470. case Iso14443_4aErrorTimeout:
  471. break;
  472. default:
  473. break;
  474. }
  475. }
  476. } else if(strcmp(passy->proto, "4b") == 0) {
  477. furi_assert(event.protocol == NfcProtocolIso14443_4b);
  478. const Iso14443_4bPollerEvent* iso14443_4b_event = event.event_data;
  479. Iso14443_4bPoller* iso14443_4b_poller = event.instance;
  480. FURI_LOG_D(TAG, "iso14443_4b_event->type %i", iso14443_4b_event->type);
  481. passy_reader->iso14443_4b_poller = iso14443_4b_poller;
  482. if(iso14443_4b_event->type == Iso14443_4bPollerEventTypeReady) {
  483. nfc_device_set_data(
  484. passy_reader->passy->nfc_device,
  485. NfcProtocolIso14443_4b,
  486. nfc_poller_get_data(passy_reader->passy->poller));
  487. ret = passy_reader_state_machine(passy_reader);
  488. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  489. } else if(iso14443_4b_event->type == Iso14443_4bPollerEventTypeError) {
  490. Iso14443_4bPollerEventData* data = iso14443_4b_event->data;
  491. Iso14443_4bError error = data->error;
  492. FURI_LOG_W(TAG, "Iso14443_4bError %i", error);
  493. switch(error) {
  494. case Iso14443_4bErrorNone:
  495. break;
  496. case Iso14443_4bErrorNotPresent:
  497. break;
  498. case Iso14443_4bErrorProtocol:
  499. ret = NfcCommandStop;
  500. break;
  501. case Iso14443_4bErrorTimeout:
  502. break;
  503. }
  504. }
  505. } else {
  506. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  507. }
  508. return ret;
  509. }