seos_emulator.c 33 KB

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