seader_worker.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. #include "seader_worker_i.h"
  2. #include <flipper_format/flipper_format.h>
  3. #include <lib/bit_lib/bit_lib.h>
  4. #define TAG "SeaderWorker"
  5. #define APDU_HEADER_LEN 5
  6. #define ASN1_PREFIX 6
  7. #define ASN1_DEBUG true
  8. #define RFAL_PICOPASS_TXRX_FLAGS \
  9. (FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | \
  10. FURI_HAL_NFC_LL_TXRX_FLAGS_PAR_RX_REMV | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP)
  11. // Forward declaration
  12. void seader_send_card_detected(SeaderUartBridge* seader_uart, CardDetails_t* cardDetails);
  13. /***************************** Seader Worker API *******************************/
  14. SeaderWorker* seader_worker_alloc() {
  15. SeaderWorker* seader_worker = malloc(sizeof(SeaderWorker));
  16. // Worker thread attributes
  17. seader_worker->thread =
  18. furi_thread_alloc_ex("SeaderWorker", 8192, seader_worker_task, seader_worker);
  19. seader_worker->messages = furi_message_queue_alloc(3, sizeof(SeaderAPDU));
  20. seader_worker->mq_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  21. seader_worker->callback = NULL;
  22. seader_worker->context = NULL;
  23. seader_worker->storage = furi_record_open(RECORD_STORAGE);
  24. memset(seader_worker->sam_version, 0, sizeof(seader_worker->sam_version));
  25. seader_worker_change_state(seader_worker, SeaderWorkerStateReady);
  26. return seader_worker;
  27. }
  28. void seader_worker_free(SeaderWorker* seader_worker) {
  29. furi_assert(seader_worker);
  30. furi_thread_free(seader_worker->thread);
  31. furi_message_queue_free(seader_worker->messages);
  32. furi_mutex_free(seader_worker->mq_mutex);
  33. furi_record_close(RECORD_STORAGE);
  34. free(seader_worker);
  35. }
  36. SeaderWorkerState seader_worker_get_state(SeaderWorker* seader_worker) {
  37. return seader_worker->state;
  38. }
  39. void seader_worker_start(
  40. SeaderWorker* seader_worker,
  41. SeaderWorkerState state,
  42. SeaderUartBridge* uart,
  43. SeaderWorkerCallback callback,
  44. void* context) {
  45. furi_assert(seader_worker);
  46. furi_assert(uart);
  47. seader_worker->stage = SeaderPollerEventTypeCardDetect;
  48. seader_worker->callback = callback;
  49. seader_worker->context = context;
  50. seader_worker->uart = uart;
  51. seader_worker_change_state(seader_worker, state);
  52. furi_thread_start(seader_worker->thread);
  53. }
  54. void seader_worker_stop(SeaderWorker* seader_worker) {
  55. furi_assert(seader_worker);
  56. if(seader_worker->state == SeaderWorkerStateBroken ||
  57. seader_worker->state == SeaderWorkerStateReady) {
  58. return;
  59. }
  60. seader_worker_change_state(seader_worker, SeaderWorkerStateStop);
  61. furi_thread_join(seader_worker->thread);
  62. }
  63. void seader_worker_change_state(SeaderWorker* seader_worker, SeaderWorkerState state) {
  64. seader_worker->state = state;
  65. }
  66. /***************************** Seader Worker Thread *******************************/
  67. bool seader_process_success_response(Seader* seader, uint8_t* apdu, size_t len) {
  68. SeaderWorker* seader_worker = seader->worker;
  69. if(seader_process_success_response_i(seader, apdu, len, false, NULL)) {
  70. // no-op, message was processed
  71. } else {
  72. FURI_LOG_I(TAG, "Enqueue SAM message, %d bytes", len);
  73. uint32_t space = furi_message_queue_get_space(seader_worker->messages);
  74. if(space > 0) {
  75. SeaderAPDU seaderApdu = {};
  76. seaderApdu.len = len;
  77. memcpy(seaderApdu.buf, apdu, len);
  78. if(furi_mutex_acquire(seader_worker->mq_mutex, FuriWaitForever) == FuriStatusOk) {
  79. furi_message_queue_put(seader_worker->messages, &seaderApdu, FuriWaitForever);
  80. furi_mutex_release(seader_worker->mq_mutex);
  81. }
  82. }
  83. }
  84. return true;
  85. }
  86. bool seader_worker_process_sam_message(Seader* seader, uint8_t* apdu, uint32_t len) {
  87. SeaderWorker* seader_worker = seader->worker;
  88. SeaderUartBridge* seader_uart = seader_worker->uart;
  89. if(len < 2) {
  90. return false;
  91. }
  92. if(seader_worker->state == SeaderWorkerStateAPDURunner) {
  93. return seader_apdu_runner_response(seader, apdu, len);
  94. }
  95. char* display = malloc(len * 2 + 1);
  96. memset(display, 0, len * 2 + 1);
  97. for(uint8_t i = 0; i < len; i++) {
  98. snprintf(display + (i * 2), sizeof(display), "%02x", apdu[i]);
  99. }
  100. FURI_LOG_I(TAG, "APDU: %s", display);
  101. free(display);
  102. uint8_t SW1 = apdu[len - 2];
  103. uint8_t SW2 = apdu[len - 1];
  104. uint8_t GET_RESPONSE[] = {0x00, 0xc0, 0x00, 0x00, 0xff};
  105. switch(SW1) {
  106. case 0x61:
  107. // FURI_LOG_I(TAG, "Request %d bytes", SW2);
  108. GET_RESPONSE[4] = SW2;
  109. seader_ccid_XfrBlock(seader_uart, GET_RESPONSE, sizeof(GET_RESPONSE));
  110. return true;
  111. break;
  112. case 0x90:
  113. if(SW2 == 0x00) {
  114. if(len > 2) {
  115. return seader_process_success_response(seader, apdu, len - 2);
  116. }
  117. }
  118. break;
  119. default:
  120. FURI_LOG_W(TAG, "Unknown SW %02x%02x", SW1, SW2);
  121. break;
  122. }
  123. return false;
  124. }
  125. void seader_worker_virtual_credential(Seader* seader) {
  126. SeaderWorker* seader_worker = seader->worker;
  127. // Detect card
  128. seader_worker_card_detect(
  129. seader, 0, NULL, seader->credential->diversifier, sizeof(PicopassSerialNum), NULL, 0);
  130. bool running = true;
  131. // Max times the loop will run with no message to process
  132. uint8_t dead_loops = 20;
  133. while(running) {
  134. if(furi_mutex_acquire(seader_worker->mq_mutex, 0) == FuriStatusOk) {
  135. uint32_t count = furi_message_queue_get_count(seader_worker->messages);
  136. if(count > 0) {
  137. FURI_LOG_I(TAG, "Dequeue SAM message [%ld messages]", count);
  138. SeaderAPDU seaderApdu = {};
  139. FuriStatus status =
  140. furi_message_queue_get(seader_worker->messages, &seaderApdu, FuriWaitForever);
  141. if(status != FuriStatusOk) {
  142. FURI_LOG_W(TAG, "furi_message_queue_get fail %d", status);
  143. view_dispatcher_send_custom_event(
  144. seader->view_dispatcher, SeaderCustomEventWorkerExit);
  145. }
  146. if(seader_process_success_response_i(
  147. seader, seaderApdu.buf, seaderApdu.len, true, NULL)) {
  148. // no-op
  149. } else {
  150. FURI_LOG_I(TAG, "Response false");
  151. running = false;
  152. }
  153. }
  154. furi_mutex_release(seader_worker->mq_mutex);
  155. } else {
  156. dead_loops--;
  157. running = (dead_loops > 0);
  158. FURI_LOG_D(
  159. TAG, "Dead loops: %d -> Running: %s", dead_loops, running ? "true" : "false");
  160. }
  161. running = (seader_worker->stage != SeaderPollerEventTypeComplete);
  162. }
  163. if(dead_loops > 0) {
  164. FURI_LOG_D(TAG, "Final dead loops: %d", dead_loops);
  165. } else {
  166. view_dispatcher_send_custom_event(seader->view_dispatcher, SeaderCustomEventWorkerExit);
  167. }
  168. }
  169. int32_t seader_worker_task(void* context) {
  170. SeaderWorker* seader_worker = context;
  171. Seader* seader = seader_worker->context;
  172. SeaderUartBridge* seader_uart = seader_worker->uart;
  173. if(seader_worker->state == SeaderWorkerStateCheckSam) {
  174. FURI_LOG_D(TAG, "Check for SAM");
  175. seader_ccid_check_for_sam(seader_uart);
  176. } else if(seader_worker->state == SeaderWorkerStateVirtualCredential) {
  177. FURI_LOG_D(TAG, "Virtual Credential");
  178. seader_worker_virtual_credential(seader);
  179. } else if(seader_worker->state == SeaderWorkerStateAPDURunner) {
  180. FURI_LOG_D(TAG, "APDU Runner");
  181. seader_apdu_runner_init(seader);
  182. return 0;
  183. }
  184. seader_worker_change_state(seader_worker, SeaderWorkerStateReady);
  185. return 0;
  186. }
  187. void seader_worker_poller_conversation(Seader* seader, SeaderPollerContainer* spc) {
  188. SeaderWorker* seader_worker = seader->worker;
  189. if(furi_mutex_acquire(seader_worker->mq_mutex, 0) == FuriStatusOk) {
  190. furi_thread_set_current_priority(FuriThreadPriorityHighest);
  191. uint32_t count = furi_message_queue_get_count(seader_worker->messages);
  192. if(count > 0) {
  193. FURI_LOG_I(TAG, "Dequeue SAM message [%ld messages]", count);
  194. SeaderAPDU seaderApdu = {};
  195. FuriStatus status =
  196. furi_message_queue_get(seader_worker->messages, &seaderApdu, FuriWaitForever);
  197. if(status != FuriStatusOk) {
  198. FURI_LOG_W(TAG, "furi_message_queue_get fail %d", status);
  199. seader_worker->stage = SeaderPollerEventTypeComplete;
  200. view_dispatcher_send_custom_event(
  201. seader->view_dispatcher, SeaderCustomEventWorkerExit);
  202. }
  203. if(seader_process_success_response_i(
  204. seader, seaderApdu.buf, seaderApdu.len, true, spc)) {
  205. // no-op
  206. } else {
  207. FURI_LOG_I(TAG, "Response false");
  208. view_dispatcher_send_custom_event(
  209. seader->view_dispatcher, SeaderCustomEventWorkerExit);
  210. seader_worker->stage = SeaderPollerEventTypeComplete;
  211. }
  212. }
  213. furi_mutex_release(seader_worker->mq_mutex);
  214. } else {
  215. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  216. }
  217. }
  218. NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context) {
  219. furi_assert(event.protocol == NfcProtocolIso14443_4a);
  220. NfcCommand ret = NfcCommandContinue;
  221. Seader* seader = context;
  222. SeaderWorker* seader_worker = seader->worker;
  223. const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
  224. SeaderPollerContainer spc = {.iso14443_4a_poller = event.instance};
  225. if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
  226. if(seader_worker->stage == SeaderPollerEventTypeCardDetect) {
  227. view_dispatcher_send_custom_event(
  228. seader->view_dispatcher, SeaderCustomEventPollerDetect);
  229. nfc_device_set_data(
  230. seader->nfc_device, NfcProtocolIso14443_4a, nfc_poller_get_data(seader->poller));
  231. size_t uid_len;
  232. const uint8_t* uid = nfc_device_get_uid(seader->nfc_device, &uid_len);
  233. const Iso14443_3aData* iso14443_3a_data =
  234. nfc_device_get_data(seader->nfc_device, NfcProtocolIso14443_3a);
  235. uint8_t sak = iso14443_3a_get_sak(iso14443_3a_data);
  236. seader_worker_card_detect(
  237. seader, sak, (uint8_t*)iso14443_3a_data->atqa, uid, uid_len, NULL, 0);
  238. // nfc_set_fdt_poll_fc(event.instance, SEADER_POLLER_MAX_FWT);
  239. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  240. seader_worker->stage = SeaderPollerEventTypeConversation;
  241. } else if(seader_worker->stage == SeaderPollerEventTypeConversation) {
  242. seader_worker_poller_conversation(seader, &spc);
  243. } else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
  244. ret = NfcCommandStop;
  245. } else if(seader_worker->stage == SeaderPollerEventTypeFail) {
  246. ret = NfcCommandStop;
  247. view_dispatcher_send_custom_event(
  248. seader->view_dispatcher, SeaderCustomEventWorkerExit);
  249. FURI_LOG_W(TAG, "SeaderPollerEventTypeFail");
  250. }
  251. } else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) {
  252. Iso14443_4aPollerEventData* data = iso14443_4a_event->data;
  253. Iso14443_4aError error = data->error;
  254. FURI_LOG_W(TAG, "Iso14443_4aError %i", error);
  255. // I was hoping to catch MFC here, but it seems to be treated the same (None) as no card being present.
  256. switch(error) {
  257. case Iso14443_4aErrorNone:
  258. break;
  259. case Iso14443_4aErrorNotPresent:
  260. break;
  261. case Iso14443_4aErrorProtocol:
  262. ret = NfcCommandStop;
  263. break;
  264. case Iso14443_4aErrorTimeout:
  265. break;
  266. case Iso14443_4aErrorSendExtra:
  267. break;
  268. }
  269. }
  270. return ret;
  271. }
  272. NfcCommand seader_worker_poller_callback_mfc(NfcGenericEvent event, void* context) {
  273. furi_assert(event.protocol == NfcProtocolMfClassic);
  274. NfcCommand ret = NfcCommandContinue;
  275. Seader* seader = context;
  276. SeaderWorker* seader_worker = seader->worker;
  277. MfClassicPollerEvent* mfc_event = event.event_data;
  278. SeaderPollerContainer spc = {.mfc_poller = event.instance};
  279. if(mfc_event->type == MfClassicPollerEventTypeSuccess) {
  280. if(seader_worker->stage == SeaderPollerEventTypeCardDetect) {
  281. view_dispatcher_send_custom_event(
  282. seader->view_dispatcher, SeaderCustomEventPollerDetect);
  283. const MfClassicData* mfc_data = nfc_poller_get_data(seader->poller);
  284. uint8_t sak = iso14443_3a_get_sak(mfc_data->iso14443_3a_data);
  285. size_t uid_len = 0;
  286. const uint8_t* uid = mf_classic_get_uid(mfc_data, &uid_len);
  287. seader_worker_card_detect(seader, sak, NULL, uid, uid_len, NULL, 0);
  288. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  289. seader_worker->stage = SeaderPollerEventTypeConversation;
  290. } else if(seader_worker->stage == SeaderPollerEventTypeConversation) {
  291. seader_worker_poller_conversation(seader, &spc);
  292. } else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
  293. ret = NfcCommandStop;
  294. } else if(seader_worker->stage == SeaderPollerEventTypeFail) {
  295. ret = NfcCommandStop;
  296. }
  297. } else if(mfc_event->type == MfClassicPollerEventTypeFail) {
  298. ret = NfcCommandStop;
  299. }
  300. return ret;
  301. }
  302. NfcCommand seader_worker_poller_callback_picopass(PicopassPollerEvent event, void* context) {
  303. furi_assert(context);
  304. NfcCommand ret = NfcCommandContinue;
  305. Seader* seader = context;
  306. SeaderWorker* seader_worker = seader->worker;
  307. // I know this is is passing the same thing that is on seader all the way down, but I prefer the symmetry between the 15a and iso15 stuff
  308. PicopassPoller* instance = seader->picopass_poller;
  309. SeaderPollerContainer spc = {.picopass_poller = instance};
  310. if(event.type == PicopassPollerEventTypeCardDetected) {
  311. seader_worker->stage = SeaderPollerEventTypeCardDetect;
  312. } else if(event.type == PicopassPollerEventTypeSuccess) {
  313. if(seader_worker->stage == SeaderPollerEventTypeCardDetect) {
  314. view_dispatcher_send_custom_event(
  315. seader->view_dispatcher, SeaderCustomEventPollerDetect);
  316. uint8_t* csn = picopass_poller_get_csn(instance);
  317. seader_worker_card_detect(seader, 0, NULL, csn, sizeof(PicopassSerialNum), NULL, 0);
  318. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  319. seader_worker->stage = SeaderPollerEventTypeConversation;
  320. } else if(seader_worker->stage == SeaderPollerEventTypeConversation) {
  321. seader_worker_poller_conversation(seader, &spc);
  322. } else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
  323. ret = NfcCommandStop;
  324. }
  325. } else if(event.type == PicopassPollerEventTypeFail) {
  326. ret = NfcCommandStop;
  327. FURI_LOG_W(TAG, "PicopassPollerEventTypeFail");
  328. } else {
  329. FURI_LOG_D(TAG, "picopass event type %x", event.type);
  330. }
  331. return ret;
  332. }