seos_emulator.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. #include "seos_emulator_i.h"
  2. #define TAG "SeosEmulator"
  3. #define NAD_MASK 0x08
  4. static uint8_t select_header[] = {0x00, 0xa4, 0x04, 0x00};
  5. static uint8_t standard_seos_aid[] = {0xa0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x01, 0x01, 0x00, 0x01};
  6. static uint8_t MOBILE_SEOS_ADMIN_CARD[] =
  7. {0xa0, 0x00, 0x00, 0x03, 0x82, 0x00, 0x2d, 0x00, 0x01, 0x01};
  8. static uint8_t OPERATION_SELECTOR[] = {0xa0, 0x00, 0x00, 0x03, 0x82, 0x00, 0x2f, 0x00, 0x01, 0x01};
  9. static uint8_t OPERATION_SELECTOR_POST_RESET[] =
  10. {0xa0, 0x00, 0x00, 0x03, 0x82, 0x00, 0x31, 0x00, 0x01, 0x01};
  11. static uint8_t SEOS_APPLET_FCI[] =
  12. {0x6F, 0x0C, 0x84, 0x0A, 0xA0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x01, 0x01, 0x00, 0x01};
  13. static uint8_t FILE_NOT_FOUND[] = {0x6A, 0x82};
  14. static uint8_t success[] = {0x90, 0x00};
  15. static uint8_t select_adf_header[] = {0x80, 0xa5, 0x04, 0x00};
  16. static uint8_t general_authenticate_1[] =
  17. {0x00, 0x87, 0x00, 0x01, 0x04, 0x7c, 0x02, 0x81, 0x00, 0x00};
  18. static uint8_t general_authenticate_1_response_header[] = {0x7c, 0x0a, 0x81, 0x08};
  19. static uint8_t general_authenticate_2_header[] = {0x00, 0x87, 0x00, 0x01};
  20. static uint8_t secure_messaging_header[] = {0x0c, 0xcb, 0x3f, 0xff};
  21. static uint8_t empty[16] =
  22. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  23. SeosEmulator* seos_emulator_alloc(SeosCredential* credential) {
  24. SeosEmulator* seos_emulator = malloc(sizeof(SeosEmulator));
  25. memset(seos_emulator, 0, sizeof(SeosEmulator));
  26. if(credential->adf_response[0] == 0) {
  27. // Using DES for greater compatibilty
  28. seos_emulator->params.cipher = TWO_KEY_3DES_CBC_MODE;
  29. seos_emulator->params.hash = SHA1;
  30. } else {
  31. seos_emulator->params.cipher = credential->adf_response[2];
  32. seos_emulator->params.hash = credential->adf_response[3];
  33. }
  34. memset(seos_emulator->params.rndICC, 0x0d, sizeof(seos_emulator->params.rndICC));
  35. memset(seos_emulator->params.rNonce, 0x0c, sizeof(seos_emulator->params.rNonce));
  36. seos_emulator->credential = credential;
  37. seos_emulator->secure_messaging = NULL;
  38. seos_emulator->tx_buffer = bit_buffer_alloc(SEOS_WORKER_MAX_BUFFER_SIZE);
  39. return seos_emulator;
  40. }
  41. void seos_emulator_free(SeosEmulator* seos_emulator) {
  42. furi_assert(seos_emulator);
  43. if(seos_emulator->secure_messaging) {
  44. secure_messaging_free(seos_emulator->secure_messaging);
  45. }
  46. bit_buffer_free(seos_emulator->tx_buffer);
  47. free(seos_emulator);
  48. }
  49. void seos_emulator_select_aid(BitBuffer* tx_buffer) {
  50. FURI_LOG_D(TAG, "Select AID");
  51. bit_buffer_append_bytes(tx_buffer, SEOS_APPLET_FCI, sizeof(SEOS_APPLET_FCI));
  52. }
  53. void seos_emulator_general_authenticate_1(BitBuffer* tx_buffer, AuthParameters params) {
  54. bit_buffer_append_bytes(
  55. tx_buffer,
  56. general_authenticate_1_response_header,
  57. sizeof(general_authenticate_1_response_header));
  58. bit_buffer_append_bytes(tx_buffer, params.rndICC, sizeof(params.rndICC));
  59. }
  60. // 0a00
  61. // 00870001 2c7c 2a82 28 bbb4e9156136f27f687e2967865dfe812e33c95ddcf9294a4340d26da3e76db0220d1163c591e5b8 00
  62. bool seos_emulator_general_authenticate_2(
  63. const uint8_t* buffer,
  64. size_t buffer_len,
  65. SeosCredential* credential,
  66. AuthParameters* params,
  67. BitBuffer* tx_buffer) {
  68. FURI_LOG_D(TAG, "seos_emulator_general_authenticate_2");
  69. UNUSED(buffer_len);
  70. uint8_t* rx_data = (uint8_t*)buffer;
  71. uint8_t* cryptogram = rx_data + sizeof(general_authenticate_2_header) + 5;
  72. size_t encrypted_len = 32;
  73. uint8_t* mac = cryptogram + encrypted_len;
  74. params->key_no = rx_data[3];
  75. if(memcmp(credential->priv_key, empty, sizeof(empty)) == 0) {
  76. seos_worker_diversify_key(
  77. SEOS_ADF1_READ,
  78. credential->diversifier,
  79. credential->diversifier_len,
  80. SEOS_ADF_OID,
  81. SEOS_ADF_OID_LEN,
  82. params->cipher,
  83. params->hash,
  84. params->key_no,
  85. true,
  86. params->priv_key);
  87. } else {
  88. memcpy(params->priv_key, credential->priv_key, sizeof(params->priv_key));
  89. }
  90. if(memcmp(credential->auth_key, empty, sizeof(empty)) == 0) {
  91. seos_worker_diversify_key(
  92. SEOS_ADF1_READ,
  93. credential->diversifier,
  94. credential->diversifier_len,
  95. SEOS_ADF_OID,
  96. SEOS_ADF_OID_LEN,
  97. params->cipher,
  98. params->hash,
  99. params->key_no,
  100. false,
  101. params->auth_key);
  102. } else {
  103. memcpy(params->auth_key, credential->auth_key, sizeof(params->auth_key));
  104. }
  105. uint8_t cmac[16];
  106. if(params->cipher == AES_128_CBC) {
  107. aes_cmac(params->auth_key, sizeof(params->auth_key), cryptogram, encrypted_len, cmac);
  108. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  109. des_cmac(params->auth_key, sizeof(params->auth_key), cryptogram, encrypted_len, cmac);
  110. } else {
  111. FURI_LOG_W(TAG, "Cipher not matched");
  112. return false;
  113. }
  114. if(memcmp(cmac, mac, SEOS_WORKER_CMAC_SIZE) != 0) {
  115. FURI_LOG_W(TAG, "Incorrect cryptogram mac %02x... vs %02x...", cmac[0], mac[0]);
  116. return false;
  117. }
  118. uint8_t clear[32];
  119. if(params->cipher == AES_128_CBC) {
  120. seos_worker_aes_decrypt(params->priv_key, encrypted_len, cryptogram, clear);
  121. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  122. seos_worker_des_decrypt(params->priv_key, encrypted_len, cryptogram, clear);
  123. } else {
  124. FURI_LOG_W(TAG, "Cipher not matched");
  125. }
  126. size_t index = 0;
  127. memcpy(params->UID, clear + index, sizeof(params->UID));
  128. index += sizeof(params->UID);
  129. if(memcmp(clear + index, params->rndICC, sizeof(params->rndICC)) != 0) {
  130. FURI_LOG_W(TAG, "Incorrect rndICC returned");
  131. return false;
  132. }
  133. index += sizeof(params->rndICC);
  134. memcpy(params->cNonce, clear + index, sizeof(params->cNonce));
  135. index += sizeof(params->cNonce);
  136. // Construct response
  137. uint8_t response_header[] = {0x7c, 0x2a, 0x82, 0x28};
  138. memset(clear, 0, sizeof(clear));
  139. memset(cmac, 0, sizeof(cmac));
  140. index = 0;
  141. memcpy(clear + index, params->rndICC, sizeof(params->rndICC));
  142. index += sizeof(params->rndICC);
  143. memcpy(clear + index, params->UID, sizeof(params->UID));
  144. index += sizeof(params->UID);
  145. memcpy(clear + index, params->rNonce, sizeof(params->rNonce));
  146. index += sizeof(params->rNonce);
  147. uint8_t encrypted[32];
  148. if(params->cipher == AES_128_CBC) {
  149. seos_worker_aes_encrypt(params->priv_key, sizeof(clear), clear, encrypted);
  150. aes_cmac(params->auth_key, sizeof(params->auth_key), encrypted, sizeof(encrypted), cmac);
  151. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  152. seos_worker_des_encrypt(params->priv_key, sizeof(clear), clear, encrypted);
  153. des_cmac(params->auth_key, sizeof(params->auth_key), encrypted, sizeof(encrypted), cmac);
  154. } else {
  155. FURI_LOG_W(TAG, "Cipher not matched");
  156. }
  157. bit_buffer_append_bytes(tx_buffer, response_header, sizeof(response_header));
  158. bit_buffer_append_bytes(tx_buffer, encrypted, sizeof(encrypted));
  159. bit_buffer_append_bytes(tx_buffer, cmac, SEOS_WORKER_CMAC_SIZE);
  160. return true;
  161. }
  162. void seos_emulator_des_adf_payload(SeosCredential* credential, uint8_t* buffer) {
  163. // Synethic IV
  164. /// random bytes
  165. uint8_t rnd[4] = {0, 0, 0, 0};
  166. uint8_t cmac[8] = {0};
  167. /// cmac
  168. des_cmac(SEOS_ADF1_PRIV_MAC, sizeof(SEOS_ADF1_PRIV_MAC), rnd, sizeof(rnd), cmac);
  169. uint8_t iv[8];
  170. memcpy(iv + 0, rnd, sizeof(rnd));
  171. memcpy(iv + sizeof(rnd), cmac, sizeof(iv) - sizeof(rnd));
  172. // Copy IV to buffer because mbedtls_des3_crypt_cbc mutates it
  173. memcpy(buffer + 0, iv, sizeof(iv));
  174. uint8_t clear[0x30];
  175. memset(clear, 0, sizeof(clear));
  176. size_t index = 0;
  177. // OID
  178. clear[index++] = 0x06;
  179. clear[index++] = SEOS_ADF_OID_LEN, memcpy(clear + index, SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  180. index += SEOS_ADF_OID_LEN;
  181. // diversifier
  182. clear[index++] = 0xcf;
  183. clear[index++] = credential->diversifier_len;
  184. memcpy(clear + index, credential->diversifier, credential->diversifier_len);
  185. index += credential->diversifier_len;
  186. mbedtls_des3_context ctx;
  187. mbedtls_des3_init(&ctx);
  188. mbedtls_des3_set2key_enc(&ctx, SEOS_ADF1_PRIV_ENC);
  189. mbedtls_des3_crypt_cbc(
  190. &ctx, MBEDTLS_DES_ENCRYPT, sizeof(clear), iv, clear, buffer + sizeof(iv));
  191. mbedtls_des3_free(&ctx);
  192. }
  193. void seos_emulator_aes_adf_payload(SeosCredential* credential, uint8_t* buffer) {
  194. // Synethic IV
  195. /// random bytes
  196. uint8_t rnd[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  197. uint8_t cmac[16] = {0};
  198. /// cmac
  199. aes_cmac(SEOS_ADF1_PRIV_MAC, sizeof(SEOS_ADF1_PRIV_MAC), rnd, sizeof(rnd), cmac);
  200. uint8_t iv[16];
  201. memcpy(iv + 0, rnd, sizeof(rnd));
  202. memcpy(iv + sizeof(rnd), cmac, sizeof(iv) - sizeof(rnd));
  203. // Copy IV to buffer because mbedtls_aes_crypt_cbc mutates it
  204. memcpy(buffer + 0, iv, sizeof(iv));
  205. uint8_t clear[0x30];
  206. memset(clear, 0, sizeof(clear));
  207. size_t index = 0;
  208. // OID
  209. clear[index++] = 0x06;
  210. clear[index++] = SEOS_ADF_OID_LEN;
  211. memcpy(clear + index, SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  212. index += SEOS_ADF_OID_LEN;
  213. // diversifier
  214. clear[index++] = 0xcf;
  215. clear[index++] = credential->diversifier_len;
  216. memcpy(clear + index, credential->diversifier, credential->diversifier_len);
  217. index += credential->diversifier_len;
  218. mbedtls_aes_context ctx;
  219. mbedtls_aes_init(&ctx);
  220. mbedtls_aes_setkey_enc(&ctx, SEOS_ADF1_PRIV_ENC, sizeof(SEOS_ADF1_PRIV_ENC) * 8);
  221. mbedtls_aes_crypt_cbc(
  222. &ctx, MBEDTLS_AES_ENCRYPT, sizeof(clear), iv, clear, buffer + sizeof(iv));
  223. mbedtls_aes_free(&ctx);
  224. }
  225. void seos_emulator_select_adf(
  226. AuthParameters* params,
  227. SeosCredential* credential,
  228. BitBuffer* tx_buffer) {
  229. FURI_LOG_D(TAG, "Select ADF");
  230. // Shortcut if the credential file contained the hardcoded response
  231. if(credential->adf_response[2] != 0x00 && credential->adf_response[2] == params->cipher) {
  232. FURI_LOG_I(TAG, "Using hardcoded ADF Response");
  233. bit_buffer_append_bytes(
  234. tx_buffer, credential->adf_response, sizeof(credential->adf_response));
  235. bit_buffer_append_bytes(tx_buffer, success, sizeof(success));
  236. seos_log_bitbuffer(TAG, "Select ADF (0xcd02...)", tx_buffer);
  237. return;
  238. }
  239. size_t prefix_len = bit_buffer_get_size_bytes(tx_buffer);
  240. size_t des_cryptogram_length = 56;
  241. size_t aes_cryptogram_length = 64;
  242. uint8_t header[] = {0xcd, 0x02, params->cipher, params->hash};
  243. bit_buffer_append_bytes(tx_buffer, header, sizeof(header));
  244. // cryptogram
  245. // 06112b0601040181e438010102011801010202 cf 07 3d4c010c71cfa7 e2d0b41a00cc5e494c8d52b6e562592399fe614a
  246. uint8_t buffer[64];
  247. uint8_t cmac[16];
  248. memset(buffer, 0, sizeof(buffer));
  249. if(params->cipher == AES_128_CBC) {
  250. uint8_t cryptogram_prefix[] = {0x85, aes_cryptogram_length};
  251. bit_buffer_append_bytes(tx_buffer, cryptogram_prefix, sizeof(cryptogram_prefix));
  252. seos_emulator_aes_adf_payload(credential, buffer);
  253. bit_buffer_append_bytes(tx_buffer, buffer, aes_cryptogram_length);
  254. aes_cmac(
  255. SEOS_ADF1_PRIV_MAC,
  256. sizeof(SEOS_ADF1_PRIV_MAC),
  257. (uint8_t*)bit_buffer_get_data(tx_buffer) + prefix_len,
  258. bit_buffer_get_size_bytes(tx_buffer) - prefix_len,
  259. cmac);
  260. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  261. uint8_t cryptogram_prefix[] = {0x85, des_cryptogram_length};
  262. bit_buffer_append_bytes(tx_buffer, cryptogram_prefix, sizeof(cryptogram_prefix));
  263. seos_emulator_des_adf_payload(credential, buffer);
  264. bit_buffer_append_bytes(tx_buffer, buffer, des_cryptogram_length);
  265. // +2 / -2 is to ignore iso14a framing
  266. des_cmac(
  267. SEOS_ADF1_PRIV_MAC,
  268. sizeof(SEOS_ADF1_PRIV_MAC),
  269. (uint8_t*)bit_buffer_get_data(tx_buffer) + prefix_len,
  270. bit_buffer_get_size_bytes(tx_buffer) - prefix_len,
  271. cmac);
  272. }
  273. uint8_t cmac_prefix[] = {0x8e, 0x08};
  274. bit_buffer_append_bytes(tx_buffer, cmac_prefix, sizeof(cmac_prefix));
  275. bit_buffer_append_bytes(tx_buffer, cmac, SEOS_WORKER_CMAC_SIZE);
  276. seos_log_bitbuffer(TAG, "Select ADF (0xcd02...)", tx_buffer);
  277. }
  278. NfcCommand seos_worker_listener_inspect_reader(Seos* seos) {
  279. SeosEmulator* seos_emulator = seos->seos_emulator;
  280. BitBuffer* tx_buffer = seos_emulator->tx_buffer;
  281. NfcCommand ret = NfcCommandContinue;
  282. const uint8_t* rx_data = bit_buffer_get_data(seos_emulator->rx_buffer);
  283. bool NAD = (rx_data[0] & NAD_MASK) == NAD_MASK;
  284. uint8_t offset = NAD ? 2 : 1;
  285. // + x to skip stuff before APDU
  286. const uint8_t* apdu = rx_data + offset;
  287. if(memcmp(apdu, select_header, sizeof(select_header)) == 0) {
  288. if(memcmp(
  289. apdu + sizeof(select_header) + 1, OPERATION_SELECTOR, sizeof(OPERATION_SELECTOR)) ==
  290. 0) {
  291. uint8_t enableInspection[] = {
  292. 0x6f, 0x08, 0x85, 0x06, 0x02, 0x01, 0x40, 0x02, 0x01, 0x00};
  293. bit_buffer_append_bytes(tx_buffer, enableInspection, sizeof(enableInspection));
  294. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventAIDSelected);
  295. } else {
  296. bit_buffer_append_bytes(tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  297. }
  298. } else if(bit_buffer_get_size_bytes(seos_emulator->rx_buffer) > (size_t)(offset + 2)) {
  299. FURI_LOG_I(TAG, "NFC stop; %d bytes", bit_buffer_get_size_bytes(seos_emulator->rx_buffer));
  300. ret = NfcCommandStop;
  301. }
  302. return ret;
  303. }
  304. NfcCommand seos_worker_listener_process_message(Seos* seos) {
  305. SeosEmulator* seos_emulator = seos->seos_emulator;
  306. BitBuffer* tx_buffer = seos_emulator->tx_buffer;
  307. NfcCommand ret = NfcCommandContinue;
  308. const uint8_t* rx_data = bit_buffer_get_data(seos_emulator->rx_buffer);
  309. bool NAD = (rx_data[0] & NAD_MASK) == NAD_MASK;
  310. uint8_t offset = NAD ? 2 : 1;
  311. // + x to skip stuff before APDU
  312. const uint8_t* apdu = rx_data + offset;
  313. if(memcmp(apdu, select_header, sizeof(select_header)) == 0) {
  314. if(memcmp(apdu + sizeof(select_header) + 1, standard_seos_aid, sizeof(standard_seos_aid)) ==
  315. 0) {
  316. seos_emulator_select_aid(seos_emulator->tx_buffer);
  317. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventAIDSelected);
  318. } else if(
  319. memcmp(
  320. apdu + sizeof(select_header) + 1,
  321. OPERATION_SELECTOR_POST_RESET,
  322. sizeof(OPERATION_SELECTOR_POST_RESET)) == 0) {
  323. FURI_LOG_I(TAG, "OPERATION_SELECTOR_POST_RESET");
  324. bit_buffer_append_bytes(
  325. seos_emulator->tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  326. } else if(
  327. memcmp(
  328. apdu + sizeof(select_header) + 1,
  329. OPERATION_SELECTOR,
  330. sizeof(OPERATION_SELECTOR)) == 0) {
  331. FURI_LOG_I(TAG, "OPERATION_SELECTOR");
  332. bit_buffer_append_bytes(
  333. seos_emulator->tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  334. } else if(
  335. memcmp(
  336. apdu + sizeof(select_header) + 1,
  337. MOBILE_SEOS_ADMIN_CARD,
  338. sizeof(MOBILE_SEOS_ADMIN_CARD)) == 0) {
  339. FURI_LOG_I(TAG, "MOBILE_SEOS_ADMIN_CARD");
  340. bit_buffer_append_bytes(
  341. seos_emulator->tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  342. } else {
  343. seos_log_bitbuffer(TAG, "Reject select", seos_emulator->rx_buffer);
  344. bit_buffer_append_bytes(
  345. seos_emulator->tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  346. }
  347. } else if(memcmp(apdu, select_adf_header, sizeof(select_adf_header)) == 0) {
  348. void* p = NULL;
  349. // +1 to skip APDU length byte
  350. const uint8_t* oid_list = apdu + sizeof(select_adf_header) + 1;
  351. // First we try to match the credential ADF OID
  352. SeosCredential* credential = seos_emulator->credential;
  353. if(credential->adf_oid_len > 0) {
  354. p = memmem(
  355. oid_list,
  356. apdu[sizeof(select_adf_header)],
  357. credential->adf_oid,
  358. credential->adf_oid_len);
  359. if(p) {
  360. seos_log_buffer(TAG, "Select ADF OID(credential)", p, SEOS_ADF_OID_LEN);
  361. view_dispatcher_send_custom_event(
  362. seos->view_dispatcher, SeosCustomEventADFMatched);
  363. bit_buffer_append_bytes(
  364. seos_emulator->tx_buffer,
  365. credential->adf_response,
  366. sizeof(credential->adf_response));
  367. return ret;
  368. }
  369. }
  370. // Next we try to match the ADF OID from the keys file
  371. p = memmem(oid_list, apdu[sizeof(select_adf_header)], SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  372. if(p) {
  373. seos_log_buffer(TAG, "Select ADF OID(keys)", p, SEOS_ADF_OID_LEN);
  374. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventADFMatched);
  375. seos_emulator_select_adf(
  376. &seos_emulator->params, seos_emulator->credential, seos_emulator->tx_buffer);
  377. } else {
  378. FURI_LOG_W(TAG, "Failed to match any ADF OID");
  379. }
  380. } else if(memcmp(apdu, general_authenticate_1, sizeof(general_authenticate_1)) == 0) {
  381. seos_emulator_general_authenticate_1(seos_emulator->tx_buffer, seos_emulator->params);
  382. } else if(memcmp(apdu, general_authenticate_2_header, sizeof(general_authenticate_2_header)) == 0) {
  383. if(!seos_emulator_general_authenticate_2(
  384. apdu,
  385. bit_buffer_get_size_bytes(seos_emulator->rx_buffer),
  386. seos_emulator->credential,
  387. &seos_emulator->params,
  388. seos_emulator->tx_buffer)) {
  389. FURI_LOG_W(TAG, "Failure in General Authenticate 2");
  390. ret = NfcCommandStop;
  391. return ret;
  392. }
  393. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventAuthenticated);
  394. // Prepare for future communication
  395. seos_emulator->secure_messaging = secure_messaging_alloc(&seos_emulator->params);
  396. } else if(memcmp(apdu, secure_messaging_header, sizeof(secure_messaging_header)) == 0) {
  397. uint8_t request_sio[] = {0x5c, 0x02, 0xff, 0x00};
  398. if(seos_emulator->secure_messaging) {
  399. FURI_LOG_D(TAG, "Unwrap secure message");
  400. // 0b00 0ccb3fff 16 8508fa8395d30de4e8e097008e085da7edbd833b002d00
  401. // Ignore 2 iso frame bytes
  402. size_t bytes_to_ignore = offset;
  403. BitBuffer* tmp = bit_buffer_alloc(bit_buffer_get_size_bytes(seos_emulator->rx_buffer));
  404. bit_buffer_append_bytes(
  405. tmp,
  406. bit_buffer_get_data(seos_emulator->rx_buffer) + bytes_to_ignore,
  407. bit_buffer_get_size_bytes(seos_emulator->rx_buffer) - bytes_to_ignore);
  408. seos_log_bitbuffer(TAG, "NFC received(wrapped)", tmp);
  409. secure_messaging_unwrap_apdu(seos_emulator->secure_messaging, tmp);
  410. seos_log_bitbuffer(TAG, "NFC received(clear)", tmp);
  411. const uint8_t* message = bit_buffer_get_data(tmp);
  412. if(memcmp(message, request_sio, sizeof(request_sio)) == 0) {
  413. view_dispatcher_send_custom_event(
  414. seos->view_dispatcher, SeosCustomEventSIORequested);
  415. BitBuffer* sio_file = bit_buffer_alloc(128);
  416. bit_buffer_append_bytes(sio_file, message + 2, 2); // fileId
  417. bit_buffer_append_byte(sio_file, seos_emulator->credential->sio_len);
  418. bit_buffer_append_bytes(
  419. sio_file, seos_emulator->credential->sio, seos_emulator->credential->sio_len);
  420. secure_messaging_wrap_rapdu(
  421. seos_emulator->secure_messaging,
  422. (uint8_t*)bit_buffer_get_data(sio_file),
  423. bit_buffer_get_size_bytes(sio_file),
  424. tx_buffer);
  425. bit_buffer_free(sio_file);
  426. }
  427. bit_buffer_free(tmp);
  428. } else {
  429. uint8_t no_sm[] = {0x69, 0x88};
  430. bit_buffer_append_bytes(tx_buffer, no_sm, sizeof(no_sm));
  431. }
  432. } else {
  433. // I'm trying to find a good place to re-assert that we're emulating so we don't get stuck on a previous UI screen when we emulate repeatedly
  434. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventEmulate);
  435. }
  436. return ret;
  437. }
  438. NfcCommand seos_worker_listener_callback(NfcGenericEvent event, void* context) {
  439. furi_assert(context);
  440. furi_assert(event.protocol == NfcProtocolIso14443_4a);
  441. furi_assert(event.event_data);
  442. Seos* seos = context;
  443. SeosEmulator* seos_emulator = seos->seos_emulator;
  444. NfcCommand ret = NfcCommandContinue;
  445. Iso14443_4aListenerEvent* iso14443_4a_event = event.event_data;
  446. Iso14443_3aListener* iso14443_listener = event.instance;
  447. seos_emulator->iso14443_listener = iso14443_listener;
  448. BitBuffer* tx_buffer = seos_emulator->tx_buffer;
  449. bit_buffer_reset(tx_buffer);
  450. switch(iso14443_4a_event->type) {
  451. case Iso14443_4aListenerEventTypeReceivedData:
  452. seos_emulator->rx_buffer = iso14443_4a_event->data->buffer;
  453. const uint8_t* rx_data = bit_buffer_get_data(seos_emulator->rx_buffer);
  454. bool NAD = (rx_data[0] & NAD_MASK) == NAD_MASK;
  455. uint8_t offset = NAD ? 2 : 1;
  456. if(bit_buffer_get_size_bytes(iso14443_4a_event->data->buffer) == offset) {
  457. FURI_LOG_I(TAG, "No contents in frame");
  458. break;
  459. }
  460. seos_log_bitbuffer(TAG, "NFC received", seos_emulator->rx_buffer);
  461. // Some ISO14443a framing I need to figure out
  462. bit_buffer_append_bytes(tx_buffer, rx_data, offset);
  463. if(seos->flow_mode == FLOW_CRED) {
  464. ret = seos_worker_listener_process_message(seos);
  465. } else if(seos->flow_mode == FLOW_INSPECT) {
  466. ret = seos_worker_listener_inspect_reader(seos);
  467. }
  468. if(bit_buffer_get_size_bytes(seos_emulator->tx_buffer) >
  469. offset) { // contents belong iso framing
  470. if(memcmp(
  471. FILE_NOT_FOUND,
  472. bit_buffer_get_data(tx_buffer) + bit_buffer_get_size_bytes(tx_buffer) -
  473. sizeof(FILE_NOT_FOUND),
  474. sizeof(FILE_NOT_FOUND)) != 0) {
  475. bit_buffer_append_bytes(tx_buffer, success, sizeof(success));
  476. }
  477. iso14443_crc_append(Iso14443CrcTypeA, tx_buffer);
  478. seos_log_bitbuffer(TAG, "NFC transmit", seos_emulator->tx_buffer);
  479. NfcError error = nfc_listener_tx((Nfc*)iso14443_listener, tx_buffer);
  480. if(error != NfcErrorNone) {
  481. FURI_LOG_W(TAG, "Tx error: %d", error);
  482. break;
  483. }
  484. } else {
  485. iso14443_crc_append(Iso14443CrcTypeA, tx_buffer);
  486. seos_log_bitbuffer(TAG, "NFC transmit", seos_emulator->tx_buffer);
  487. NfcError error = nfc_listener_tx((Nfc*)iso14443_listener, tx_buffer);
  488. if(error != NfcErrorNone) {
  489. FURI_LOG_W(TAG, "Tx error: %d", error);
  490. break;
  491. }
  492. }
  493. break;
  494. case Iso14443_4aListenerEventTypeHalted:
  495. FURI_LOG_I(TAG, "Halted");
  496. break;
  497. case Iso14443_4aListenerEventTypeFieldOff:
  498. FURI_LOG_I(TAG, "Field Off");
  499. break;
  500. }
  501. if(ret == NfcCommandStop) {
  502. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventReaderError);
  503. }
  504. return ret;
  505. }