seos_emulator.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  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. // Using DES for greater compatibilty
  27. seos_emulator->params.cipher = TWO_KEY_3DES_CBC_MODE;
  28. seos_emulator->params.hash = SHA1;
  29. memset(seos_emulator->params.rndICC, 0x0d, sizeof(seos_emulator->params.rndICC));
  30. memset(seos_emulator->params.rNonce, 0x0c, sizeof(seos_emulator->params.rNonce));
  31. seos_emulator->credential = credential;
  32. seos_emulator->secure_messaging = NULL;
  33. seos_emulator->storage = furi_record_open(RECORD_STORAGE);
  34. seos_emulator->dialogs = furi_record_open(RECORD_DIALOGS);
  35. seos_emulator->load_path = furi_string_alloc();
  36. seos_emulator->tx_buffer = bit_buffer_alloc(SEOS_WORKER_MAX_BUFFER_SIZE);
  37. return seos_emulator;
  38. }
  39. void seos_emulator_free(SeosEmulator* seos_emulator) {
  40. furi_assert(seos_emulator);
  41. if(seos_emulator->secure_messaging) {
  42. secure_messaging_free(seos_emulator->secure_messaging);
  43. }
  44. furi_record_close(RECORD_STORAGE);
  45. furi_record_close(RECORD_DIALOGS);
  46. furi_string_free(seos_emulator->load_path);
  47. bit_buffer_free(seos_emulator->tx_buffer);
  48. free(seos_emulator);
  49. }
  50. void seos_emulator_set_loading_callback(
  51. SeosEmulator* seos_emulator,
  52. SeosLoadingCallback callback,
  53. void* context) {
  54. furi_assert(seos_emulator);
  55. seos_emulator->loading_cb = callback;
  56. seos_emulator->loading_cb_ctx = context;
  57. }
  58. static bool
  59. seos_emulator_file_load(SeosEmulator* seos_emulator, FuriString* path, bool show_dialog) {
  60. bool parsed = false;
  61. FlipperFormat* file = flipper_format_file_alloc(seos_emulator->storage);
  62. FuriString* temp_str;
  63. temp_str = furi_string_alloc();
  64. bool deprecated_version = false;
  65. if(seos_emulator->loading_cb) {
  66. seos_emulator->loading_cb(seos_emulator->loading_cb_ctx, true);
  67. }
  68. memset(
  69. seos_emulator->credential->diversifier, 0, sizeof(seos_emulator->credential->diversifier));
  70. memset(seos_emulator->credential->sio, 0, sizeof(seos_emulator->credential->sio));
  71. do {
  72. if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;
  73. // Read and verify file header
  74. uint32_t version = 0;
  75. if(!flipper_format_read_header(file, temp_str, &version)) break;
  76. if(furi_string_cmp_str(temp_str, seos_file_header) || (version != seos_file_version)) {
  77. deprecated_version = true;
  78. break;
  79. }
  80. if(!flipper_format_read_uint32(
  81. file,
  82. "Diversifier Length",
  83. (uint32_t*)&(seos_emulator->credential->diversifier_len),
  84. 1))
  85. break;
  86. if(!flipper_format_read_hex(
  87. file,
  88. "Diversifier",
  89. seos_emulator->credential->diversifier,
  90. seos_emulator->credential->diversifier_len))
  91. break;
  92. if(!flipper_format_read_uint32(
  93. file, "SIO Length", (uint32_t*)&(seos_emulator->credential->sio_len), 1))
  94. break;
  95. if(!flipper_format_read_hex(
  96. file, "SIO", seos_emulator->credential->sio, seos_emulator->credential->sio_len))
  97. break;
  98. // optional
  99. memset(
  100. seos_emulator->credential->priv_key, 0, sizeof(seos_emulator->credential->priv_key));
  101. memset(
  102. seos_emulator->credential->auth_key, 0, sizeof(seos_emulator->credential->auth_key));
  103. memset(
  104. seos_emulator->credential->adf_response,
  105. 0,
  106. sizeof(seos_emulator->credential->adf_response));
  107. flipper_format_read_hex(
  108. file,
  109. "Priv Key",
  110. seos_emulator->credential->priv_key,
  111. sizeof(seos_emulator->credential->priv_key));
  112. flipper_format_read_hex(
  113. file,
  114. "Auth Key",
  115. seos_emulator->credential->auth_key,
  116. sizeof(seos_emulator->credential->auth_key));
  117. if(memcmp(seos_emulator->credential->priv_key, empty, sizeof(empty)) != 0) {
  118. FURI_LOG_I(TAG, "+ Priv Key");
  119. }
  120. if(memcmp(seos_emulator->credential->priv_key, empty, sizeof(empty)) != 0) {
  121. FURI_LOG_I(TAG, "+ Auth Key");
  122. }
  123. flipper_format_read_hex(
  124. file,
  125. "ADF Response",
  126. seos_emulator->credential->adf_response,
  127. sizeof(seos_emulator->credential->adf_response));
  128. parsed = true;
  129. } while(false);
  130. if(seos_emulator->loading_cb) {
  131. seos_emulator->loading_cb(seos_emulator->loading_cb_ctx, false);
  132. }
  133. if((!parsed) && (show_dialog)) {
  134. if(deprecated_version) {
  135. dialog_message_show_storage_error(seos_emulator->dialogs, "File format deprecated");
  136. } else {
  137. dialog_message_show_storage_error(seos_emulator->dialogs, "Can not parse\nfile");
  138. }
  139. }
  140. furi_string_free(temp_str);
  141. flipper_format_free(file);
  142. return parsed;
  143. }
  144. bool seos_emulator_file_select(SeosEmulator* seos_emulator) {
  145. furi_assert(seos_emulator);
  146. bool res = false;
  147. FuriString* seos_app_folder = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
  148. DialogsFileBrowserOptions browser_options;
  149. dialog_file_browser_set_basic_options(&browser_options, SEOS_APP_EXTENSION, &I_Nfc_10px);
  150. browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
  151. res = dialog_file_browser_show(
  152. seos_emulator->dialogs, seos_emulator->load_path, seos_app_folder, &browser_options);
  153. furi_string_free(seos_app_folder);
  154. if(res) {
  155. FuriString* filename;
  156. filename = furi_string_alloc();
  157. path_extract_filename(seos_emulator->load_path, filename, true);
  158. strncpy(seos_emulator->name, furi_string_get_cstr(filename), SEOS_FILE_NAME_MAX_LENGTH);
  159. res = seos_emulator_file_load(seos_emulator, seos_emulator->load_path, true);
  160. furi_string_free(filename);
  161. }
  162. return res;
  163. }
  164. bool seos_emulator_delete(SeosEmulator* seos_emulator, bool use_load_path) {
  165. furi_assert(seos_emulator);
  166. bool deleted = false;
  167. FuriString* file_path;
  168. file_path = furi_string_alloc();
  169. do {
  170. // Delete original file
  171. if(use_load_path && !furi_string_empty(seos_emulator->load_path)) {
  172. furi_string_set(file_path, seos_emulator->load_path);
  173. } else {
  174. furi_string_printf(
  175. file_path, APP_DATA_PATH("%s%s"), seos_emulator->name, SEOS_APP_EXTENSION);
  176. }
  177. if(!storage_simply_remove(seos_emulator->storage, furi_string_get_cstr(file_path))) break;
  178. deleted = true;
  179. } while(0);
  180. if(!deleted) {
  181. dialog_message_show_storage_error(seos_emulator->dialogs, "Can not remove file");
  182. }
  183. furi_string_free(file_path);
  184. return deleted;
  185. }
  186. void seos_emulator_select_aid(BitBuffer* tx_buffer) {
  187. FURI_LOG_D(TAG, "Select AID");
  188. bit_buffer_append_bytes(tx_buffer, SEOS_APPLET_FCI, sizeof(SEOS_APPLET_FCI));
  189. }
  190. void seos_emulator_general_authenticate_1(BitBuffer* tx_buffer, AuthParameters params) {
  191. bit_buffer_append_bytes(
  192. tx_buffer,
  193. general_authenticate_1_response_header,
  194. sizeof(general_authenticate_1_response_header));
  195. bit_buffer_append_bytes(tx_buffer, params.rndICC, sizeof(params.rndICC));
  196. }
  197. // 0a00
  198. // 00870001 2c7c 2a82 28 bbb4e9156136f27f687e2967865dfe812e33c95ddcf9294a4340d26da3e76db0220d1163c591e5b8 00
  199. bool seos_emulator_general_authenticate_2(
  200. const uint8_t* buffer,
  201. size_t buffer_len,
  202. SeosCredential* credential,
  203. AuthParameters* params,
  204. BitBuffer* tx_buffer) {
  205. FURI_LOG_D(TAG, "seos_emulator_general_authenticate_2");
  206. UNUSED(buffer_len);
  207. uint8_t* rx_data = (uint8_t*)buffer;
  208. uint8_t* cryptogram = rx_data + sizeof(general_authenticate_2_header) + 5;
  209. size_t encrypted_len = 32;
  210. uint8_t* mac = cryptogram + encrypted_len;
  211. params->key_no = rx_data[3];
  212. if(memcmp(credential->priv_key, empty, sizeof(empty)) == 0) {
  213. seos_worker_diversify_key(
  214. SEOS_ADF1_READ,
  215. credential->diversifier,
  216. credential->diversifier_len,
  217. SEOS_ADF_OID,
  218. SEOS_ADF_OID_LEN,
  219. params->cipher,
  220. params->hash,
  221. params->key_no,
  222. true,
  223. params->priv_key);
  224. } else {
  225. memcpy(params->priv_key, credential->priv_key, sizeof(params->priv_key));
  226. }
  227. if(memcmp(credential->auth_key, empty, sizeof(empty)) == 0) {
  228. seos_worker_diversify_key(
  229. SEOS_ADF1_READ,
  230. credential->diversifier,
  231. credential->diversifier_len,
  232. SEOS_ADF_OID,
  233. SEOS_ADF_OID_LEN,
  234. params->cipher,
  235. params->hash,
  236. params->key_no,
  237. false,
  238. params->auth_key);
  239. } else {
  240. memcpy(params->auth_key, credential->auth_key, sizeof(params->auth_key));
  241. }
  242. uint8_t cmac[16];
  243. if(params->cipher == AES_128_CBC) {
  244. aes_cmac(params->auth_key, sizeof(params->auth_key), cryptogram, encrypted_len, cmac);
  245. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  246. des_cmac(params->auth_key, sizeof(params->auth_key), cryptogram, encrypted_len, cmac);
  247. } else {
  248. FURI_LOG_W(TAG, "Cipher not matched");
  249. return false;
  250. }
  251. if(memcmp(cmac, mac, SEOS_WORKER_CMAC_SIZE) != 0) {
  252. FURI_LOG_W(TAG, "Incorrect cryptogram mac %02x... vs %02x...", cmac[0], mac[0]);
  253. return false;
  254. }
  255. uint8_t clear[32];
  256. if(params->cipher == AES_128_CBC) {
  257. seos_worker_aes_decrypt(params->priv_key, encrypted_len, cryptogram, clear);
  258. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  259. seos_worker_des_decrypt(params->priv_key, encrypted_len, cryptogram, clear);
  260. } else {
  261. FURI_LOG_W(TAG, "Cipher not matched");
  262. }
  263. size_t index = 0;
  264. memcpy(params->UID, clear + index, sizeof(params->UID));
  265. index += sizeof(params->UID);
  266. if(memcmp(clear + index, params->rndICC, sizeof(params->rndICC)) != 0) {
  267. FURI_LOG_W(TAG, "Incorrect rndICC returned");
  268. return false;
  269. }
  270. index += sizeof(params->rndICC);
  271. memcpy(params->cNonce, clear + index, sizeof(params->cNonce));
  272. index += sizeof(params->cNonce);
  273. // Construct response
  274. uint8_t response_header[] = {0x7c, 0x2a, 0x82, 0x28};
  275. memset(clear, 0, sizeof(clear));
  276. memset(cmac, 0, sizeof(cmac));
  277. index = 0;
  278. memcpy(clear + index, params->rndICC, sizeof(params->rndICC));
  279. index += sizeof(params->rndICC);
  280. memcpy(clear + index, params->UID, sizeof(params->UID));
  281. index += sizeof(params->UID);
  282. memcpy(clear + index, params->rNonce, sizeof(params->rNonce));
  283. index += sizeof(params->rNonce);
  284. uint8_t encrypted[32];
  285. if(params->cipher == AES_128_CBC) {
  286. seos_worker_aes_encrypt(params->priv_key, sizeof(clear), clear, encrypted);
  287. aes_cmac(params->auth_key, sizeof(params->auth_key), encrypted, sizeof(encrypted), cmac);
  288. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  289. seos_worker_des_encrypt(params->priv_key, sizeof(clear), clear, encrypted);
  290. des_cmac(params->auth_key, sizeof(params->auth_key), encrypted, sizeof(encrypted), cmac);
  291. } else {
  292. FURI_LOG_W(TAG, "Cipher not matched");
  293. }
  294. bit_buffer_append_bytes(tx_buffer, response_header, sizeof(response_header));
  295. bit_buffer_append_bytes(tx_buffer, encrypted, sizeof(encrypted));
  296. bit_buffer_append_bytes(tx_buffer, cmac, SEOS_WORKER_CMAC_SIZE);
  297. return true;
  298. }
  299. void seos_emulator_des_adf_payload(SeosCredential* credential, uint8_t* buffer) {
  300. // Synethic IV
  301. /// random bytes
  302. uint8_t rnd[4] = {0, 0, 0, 0};
  303. uint8_t cmac[8] = {0};
  304. /// cmac
  305. des_cmac(SEOS_ADF1_PRIV_MAC, sizeof(SEOS_ADF1_PRIV_MAC), rnd, sizeof(rnd), cmac);
  306. uint8_t iv[8];
  307. memcpy(iv + 0, rnd, sizeof(rnd));
  308. memcpy(iv + sizeof(rnd), cmac, sizeof(iv) - sizeof(rnd));
  309. // Copy IV to buffer because mbedtls_des3_crypt_cbc mutates it
  310. memcpy(buffer + 0, iv, sizeof(iv));
  311. uint8_t clear[0x30];
  312. memset(clear, 0, sizeof(clear));
  313. size_t index = 0;
  314. // OID
  315. clear[index++] = 0x06;
  316. clear[index++] = SEOS_ADF_OID_LEN, memcpy(clear + index, SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  317. index += SEOS_ADF_OID_LEN;
  318. // diversifier
  319. clear[index++] = 0xcf;
  320. clear[index++] = credential->diversifier_len;
  321. memcpy(clear + index, credential->diversifier, credential->diversifier_len);
  322. index += credential->diversifier_len;
  323. mbedtls_des3_context ctx;
  324. mbedtls_des3_init(&ctx);
  325. mbedtls_des3_set2key_enc(&ctx, SEOS_ADF1_PRIV_ENC);
  326. mbedtls_des3_crypt_cbc(
  327. &ctx, MBEDTLS_DES_ENCRYPT, sizeof(clear), iv, clear, buffer + sizeof(iv));
  328. mbedtls_des3_free(&ctx);
  329. }
  330. void seos_emulator_aes_adf_payload(SeosCredential* credential, uint8_t* buffer) {
  331. // Synethic IV
  332. /// random bytes
  333. uint8_t rnd[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  334. uint8_t cmac[16] = {0};
  335. /// cmac
  336. aes_cmac(SEOS_ADF1_PRIV_MAC, sizeof(SEOS_ADF1_PRIV_MAC), rnd, sizeof(rnd), cmac);
  337. uint8_t iv[16];
  338. memcpy(iv + 0, rnd, sizeof(rnd));
  339. memcpy(iv + sizeof(rnd), cmac, sizeof(iv) - sizeof(rnd));
  340. // Copy IV to buffer because mbedtls_aes_crypt_cbc mutates it
  341. memcpy(buffer + 0, iv, sizeof(iv));
  342. uint8_t clear[0x30];
  343. memset(clear, 0, sizeof(clear));
  344. size_t index = 0;
  345. // OID
  346. clear[index++] = 0x06;
  347. clear[index++] = SEOS_ADF_OID_LEN;
  348. memcpy(clear + index, SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  349. index += SEOS_ADF_OID_LEN;
  350. // diversifier
  351. clear[index++] = 0xcf;
  352. clear[index++] = credential->diversifier_len;
  353. memcpy(clear + index, credential->diversifier, credential->diversifier_len);
  354. index += credential->diversifier_len;
  355. mbedtls_aes_context ctx;
  356. mbedtls_aes_init(&ctx);
  357. mbedtls_aes_setkey_enc(&ctx, SEOS_ADF1_PRIV_ENC, sizeof(SEOS_ADF1_PRIV_ENC) * 8);
  358. mbedtls_aes_crypt_cbc(
  359. &ctx, MBEDTLS_AES_ENCRYPT, sizeof(clear), iv, clear, buffer + sizeof(iv));
  360. mbedtls_aes_free(&ctx);
  361. }
  362. void seos_emulator_select_adf(
  363. AuthParameters* params,
  364. SeosCredential* credential,
  365. BitBuffer* tx_buffer) {
  366. FURI_LOG_D(TAG, "Select ADF");
  367. // Shortcut if the credential file contained the hardcoded response
  368. if(credential->adf_response[2] != 0x00 && credential->adf_response[2] == params->cipher) {
  369. FURI_LOG_I(TAG, "Using hardcoded ADF Response");
  370. bit_buffer_append_bytes(
  371. tx_buffer, credential->adf_response, sizeof(credential->adf_response));
  372. seos_log_bitbuffer(TAG, "Select ADF (0xcd02...)", tx_buffer);
  373. return;
  374. }
  375. size_t prefix_len = bit_buffer_get_size_bytes(tx_buffer);
  376. size_t des_cryptogram_length = 56;
  377. size_t aes_cryptogram_length = 64;
  378. uint8_t header[] = {0xcd, 0x02, params->cipher, params->hash};
  379. bit_buffer_append_bytes(tx_buffer, header, sizeof(header));
  380. // cryptogram
  381. // 06112b0601040181e438010102011801010202 cf 07 3d4c010c71cfa7 e2d0b41a00cc5e494c8d52b6e562592399fe614a
  382. uint8_t buffer[64];
  383. uint8_t cmac[16];
  384. memset(buffer, 0, sizeof(buffer));
  385. if(params->cipher == AES_128_CBC) {
  386. uint8_t cryptogram_prefix[] = {0x85, aes_cryptogram_length};
  387. bit_buffer_append_bytes(tx_buffer, cryptogram_prefix, sizeof(cryptogram_prefix));
  388. seos_emulator_aes_adf_payload(credential, buffer);
  389. bit_buffer_append_bytes(tx_buffer, buffer, aes_cryptogram_length);
  390. aes_cmac(
  391. SEOS_ADF1_PRIV_MAC,
  392. sizeof(SEOS_ADF1_PRIV_MAC),
  393. (uint8_t*)bit_buffer_get_data(tx_buffer) + prefix_len,
  394. bit_buffer_get_size_bytes(tx_buffer) - prefix_len,
  395. cmac);
  396. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  397. uint8_t cryptogram_prefix[] = {0x85, des_cryptogram_length};
  398. bit_buffer_append_bytes(tx_buffer, cryptogram_prefix, sizeof(cryptogram_prefix));
  399. seos_emulator_des_adf_payload(credential, buffer);
  400. bit_buffer_append_bytes(tx_buffer, buffer, des_cryptogram_length);
  401. // +2 / -2 is to ignore iso14a framing
  402. des_cmac(
  403. SEOS_ADF1_PRIV_MAC,
  404. sizeof(SEOS_ADF1_PRIV_MAC),
  405. (uint8_t*)bit_buffer_get_data(tx_buffer) + prefix_len,
  406. bit_buffer_get_size_bytes(tx_buffer) - prefix_len,
  407. cmac);
  408. }
  409. uint8_t cmac_prefix[] = {0x8e, 0x08};
  410. bit_buffer_append_bytes(tx_buffer, cmac_prefix, sizeof(cmac_prefix));
  411. bit_buffer_append_bytes(tx_buffer, cmac, SEOS_WORKER_CMAC_SIZE);
  412. seos_log_bitbuffer(TAG, "Select ADF (0xcd02...)", tx_buffer);
  413. }
  414. NfcCommand seos_worker_listener_inspect_reader(Seos* seos) {
  415. SeosEmulator* seos_emulator = seos->seos_emulator;
  416. BitBuffer* tx_buffer = seos_emulator->tx_buffer;
  417. NfcCommand ret = NfcCommandContinue;
  418. const uint8_t* rx_data = bit_buffer_get_data(seos_emulator->rx_buffer);
  419. bool NAD = (rx_data[0] & NAD_MASK) == NAD_MASK;
  420. uint8_t offset = NAD ? 2 : 1;
  421. // + x to skip stuff before APDU
  422. const uint8_t* apdu = rx_data + offset;
  423. if(memcmp(apdu, select_header, sizeof(select_header)) == 0) {
  424. if(memcmp(
  425. apdu + sizeof(select_header) + 1, OPERATION_SELECTOR, sizeof(OPERATION_SELECTOR)) ==
  426. 0) {
  427. uint8_t enableInspection[] = {
  428. 0x6f, 0x08, 0x85, 0x06, 0x02, 0x01, 0x40, 0x02, 0x01, 0x00};
  429. bit_buffer_append_bytes(tx_buffer, enableInspection, sizeof(enableInspection));
  430. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventAIDSelected);
  431. } else {
  432. bit_buffer_append_bytes(tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  433. }
  434. } else if(bit_buffer_get_size_bytes(seos_emulator->rx_buffer) > (size_t)(offset + 2)) {
  435. FURI_LOG_I(TAG, "NFC stop; %d bytes", bit_buffer_get_size_bytes(seos_emulator->rx_buffer));
  436. ret = NfcCommandStop;
  437. }
  438. return ret;
  439. }
  440. NfcCommand seos_worker_listener_process_message(Seos* seos) {
  441. SeosEmulator* seos_emulator = seos->seos_emulator;
  442. BitBuffer* tx_buffer = seos_emulator->tx_buffer;
  443. NfcCommand ret = NfcCommandContinue;
  444. const uint8_t* rx_data = bit_buffer_get_data(seos_emulator->rx_buffer);
  445. bool NAD = (rx_data[0] & NAD_MASK) == NAD_MASK;
  446. uint8_t offset = NAD ? 2 : 1;
  447. // + x to skip stuff before APDU
  448. const uint8_t* apdu = rx_data + offset;
  449. if(memcmp(apdu, select_header, sizeof(select_header)) == 0) {
  450. if(memcmp(apdu + sizeof(select_header) + 1, standard_seos_aid, sizeof(standard_seos_aid)) ==
  451. 0) {
  452. seos_emulator_select_aid(seos_emulator->tx_buffer);
  453. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventAIDSelected);
  454. } else if(
  455. memcmp(
  456. apdu + sizeof(select_header) + 1,
  457. OPERATION_SELECTOR_POST_RESET,
  458. sizeof(OPERATION_SELECTOR_POST_RESET)) == 0) {
  459. FURI_LOG_I(TAG, "OPERATION_SELECTOR_POST_RESET");
  460. bit_buffer_append_bytes(
  461. seos_emulator->tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  462. } else if(
  463. memcmp(
  464. apdu + sizeof(select_header) + 1,
  465. OPERATION_SELECTOR,
  466. sizeof(OPERATION_SELECTOR)) == 0) {
  467. FURI_LOG_I(TAG, "OPERATION_SELECTOR");
  468. bit_buffer_append_bytes(
  469. seos_emulator->tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  470. } else if(
  471. memcmp(
  472. apdu + sizeof(select_header) + 1,
  473. MOBILE_SEOS_ADMIN_CARD,
  474. sizeof(MOBILE_SEOS_ADMIN_CARD)) == 0) {
  475. FURI_LOG_I(TAG, "MOBILE_SEOS_ADMIN_CARD");
  476. bit_buffer_append_bytes(
  477. seos_emulator->tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  478. } else {
  479. seos_log_bitbuffer(TAG, "Reject select", seos_emulator->rx_buffer);
  480. bit_buffer_append_bytes(
  481. seos_emulator->tx_buffer, (uint8_t*)FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND));
  482. }
  483. } else if(memcmp(apdu, select_adf_header, sizeof(select_adf_header)) == 0) {
  484. // is our adf in the list?
  485. // +1 to skip APDU length byte
  486. void* p = memmem(
  487. apdu + sizeof(select_adf_header) + 1,
  488. apdu[sizeof(select_adf_header)],
  489. SEOS_ADF_OID,
  490. SEOS_ADF_OID_LEN);
  491. if(p) {
  492. BitBuffer* tmp = bit_buffer_alloc(SEOS_ADF_OID_LEN);
  493. bit_buffer_append_bytes(tmp, p, SEOS_ADF_OID_LEN);
  494. seos_log_bitbuffer(TAG, "Matched ADF", tmp);
  495. bit_buffer_free(tmp);
  496. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventADFMatched);
  497. seos_emulator_select_adf(
  498. &seos_emulator->params, seos_emulator->credential, seos_emulator->tx_buffer);
  499. } else {
  500. FURI_LOG_W(TAG, "Failed to match any ADF OID");
  501. }
  502. } else if(memcmp(apdu, general_authenticate_1, sizeof(general_authenticate_1)) == 0) {
  503. seos_emulator_general_authenticate_1(seos_emulator->tx_buffer, seos_emulator->params);
  504. } else if(memcmp(apdu, general_authenticate_2_header, sizeof(general_authenticate_2_header)) == 0) {
  505. if(!seos_emulator_general_authenticate_2(
  506. apdu,
  507. bit_buffer_get_size_bytes(seos_emulator->rx_buffer),
  508. seos_emulator->credential,
  509. &seos_emulator->params,
  510. seos_emulator->tx_buffer)) {
  511. FURI_LOG_W(TAG, "Failure in General Authenticate 2");
  512. ret = NfcCommandStop;
  513. return ret;
  514. }
  515. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventAuthenticated);
  516. // Prepare for future communication
  517. seos_emulator->secure_messaging = secure_messaging_alloc(&seos_emulator->params);
  518. } else if(memcmp(apdu, secure_messaging_header, sizeof(secure_messaging_header)) == 0) {
  519. uint8_t request_sio[] = {0x5c, 0x02, 0xff, 0x00};
  520. if(seos_emulator->secure_messaging) {
  521. FURI_LOG_D(TAG, "Unwrap secure message");
  522. // 0b00 0ccb3fff 16 8508fa8395d30de4e8e097008e085da7edbd833b002d00
  523. // Ignore 2 iso frame bytes
  524. size_t bytes_to_ignore = offset;
  525. BitBuffer* tmp = bit_buffer_alloc(bit_buffer_get_size_bytes(seos_emulator->rx_buffer));
  526. bit_buffer_append_bytes(
  527. tmp,
  528. bit_buffer_get_data(seos_emulator->rx_buffer) + bytes_to_ignore,
  529. bit_buffer_get_size_bytes(seos_emulator->rx_buffer) - bytes_to_ignore);
  530. seos_log_bitbuffer(TAG, "NFC received(wrapped)", tmp);
  531. secure_messaging_unwrap_apdu(seos_emulator->secure_messaging, tmp);
  532. seos_log_bitbuffer(TAG, "NFC received(clear)", tmp);
  533. const uint8_t* message = bit_buffer_get_data(tmp);
  534. if(memcmp(message, request_sio, sizeof(request_sio)) == 0) {
  535. view_dispatcher_send_custom_event(
  536. seos->view_dispatcher, SeosCustomEventSIORequested);
  537. BitBuffer* sio_file = bit_buffer_alloc(128);
  538. bit_buffer_append_bytes(sio_file, message + 2, 2); // fileId
  539. bit_buffer_append_byte(sio_file, seos_emulator->credential->sio_len);
  540. bit_buffer_append_bytes(
  541. sio_file, seos_emulator->credential->sio, seos_emulator->credential->sio_len);
  542. secure_messaging_wrap_rapdu(
  543. seos_emulator->secure_messaging,
  544. (uint8_t*)bit_buffer_get_data(sio_file),
  545. bit_buffer_get_size_bytes(sio_file),
  546. tx_buffer);
  547. bit_buffer_free(sio_file);
  548. }
  549. bit_buffer_free(tmp);
  550. } else {
  551. uint8_t no_sm[] = {0x69, 0x88};
  552. bit_buffer_append_bytes(tx_buffer, no_sm, sizeof(no_sm));
  553. }
  554. } else {
  555. // 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
  556. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventEmulate);
  557. }
  558. return ret;
  559. }
  560. NfcCommand seos_worker_listener_callback(NfcGenericEvent event, void* context) {
  561. furi_assert(context);
  562. furi_assert(event.protocol == NfcProtocolIso14443_4a);
  563. furi_assert(event.event_data);
  564. Seos* seos = context;
  565. SeosEmulator* seos_emulator = seos->seos_emulator;
  566. NfcCommand ret = NfcCommandContinue;
  567. Iso14443_4aListenerEvent* iso14443_4a_event = event.event_data;
  568. Iso14443_3aListener* iso14443_listener = event.instance;
  569. seos_emulator->iso14443_listener = iso14443_listener;
  570. BitBuffer* tx_buffer = seos_emulator->tx_buffer;
  571. bit_buffer_reset(tx_buffer);
  572. switch(iso14443_4a_event->type) {
  573. case Iso14443_4aListenerEventTypeReceivedData:
  574. seos_emulator->rx_buffer = iso14443_4a_event->data->buffer;
  575. const uint8_t* rx_data = bit_buffer_get_data(seos_emulator->rx_buffer);
  576. bool NAD = (rx_data[0] & NAD_MASK) == NAD_MASK;
  577. uint8_t offset = NAD ? 2 : 1;
  578. if(bit_buffer_get_size_bytes(iso14443_4a_event->data->buffer) == offset) {
  579. FURI_LOG_I(TAG, "No contents in frame");
  580. break;
  581. }
  582. seos_log_bitbuffer(TAG, "NFC received", seos_emulator->rx_buffer);
  583. // Some ISO14443a framing I need to figure out
  584. bit_buffer_append_bytes(tx_buffer, rx_data, offset);
  585. if(seos->flow_mode == FLOW_CRED) {
  586. ret = seos_worker_listener_process_message(seos);
  587. } else if(seos->flow_mode == FLOW_INSPECT) {
  588. ret = seos_worker_listener_inspect_reader(seos);
  589. }
  590. if(bit_buffer_get_size_bytes(seos_emulator->tx_buffer) >
  591. offset) { // contents belong iso framing
  592. if(memcmp(
  593. FILE_NOT_FOUND,
  594. bit_buffer_get_data(tx_buffer) + bit_buffer_get_size_bytes(tx_buffer) -
  595. sizeof(FILE_NOT_FOUND),
  596. sizeof(FILE_NOT_FOUND)) != 0) {
  597. bit_buffer_append_bytes(tx_buffer, success, sizeof(success));
  598. }
  599. iso14443_crc_append(Iso14443CrcTypeA, tx_buffer);
  600. seos_log_bitbuffer(TAG, "NFC transmit", seos_emulator->tx_buffer);
  601. NfcError error = nfc_listener_tx((Nfc*)iso14443_listener, tx_buffer);
  602. if(error != NfcErrorNone) {
  603. FURI_LOG_W(TAG, "Tx error: %d", error);
  604. break;
  605. }
  606. } else {
  607. iso14443_crc_append(Iso14443CrcTypeA, tx_buffer);
  608. seos_log_bitbuffer(TAG, "NFC transmit", seos_emulator->tx_buffer);
  609. NfcError error = nfc_listener_tx((Nfc*)iso14443_listener, tx_buffer);
  610. if(error != NfcErrorNone) {
  611. FURI_LOG_W(TAG, "Tx error: %d", error);
  612. break;
  613. }
  614. }
  615. break;
  616. case Iso14443_4aListenerEventTypeHalted:
  617. FURI_LOG_I(TAG, "Halted");
  618. break;
  619. case Iso14443_4aListenerEventTypeFieldOff:
  620. FURI_LOG_I(TAG, "Field Off");
  621. break;
  622. }
  623. if(ret == NfcCommandStop) {
  624. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventReaderError);
  625. }
  626. return ret;
  627. }