seos_reader.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. #include "seos_reader_i.h"
  2. #define TAG "SeosReader"
  3. static uint8_t success[] = {0x90, 0x00};
  4. static uint8_t select[] =
  5. {0x00, 0xa4, 0x04, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00};
  6. static uint8_t SEOS_APPLET_FCI[] =
  7. {0x6F, 0x0C, 0x84, 0x0A, 0xA0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x01, 0x01, 0x00, 0x01};
  8. static uint8_t select_adf_header[] = {0x80, 0xa5, 0x04, 0x00};
  9. static uint8_t general_authenticate_1[] =
  10. {0x00, 0x87, 0x00, 0x01, 0x04, 0x7c, 0x02, 0x81, 0x00, 0x00};
  11. SeosReader* seos_reader_alloc(SeosCredential* credential, Iso14443_4aPoller* iso14443_4a_poller) {
  12. SeosReader* seos_reader = malloc(sizeof(SeosReader));
  13. memset(seos_reader, 0, sizeof(SeosReader));
  14. seos_reader->params.key_no = 1;
  15. seos_reader->secure_messaging = NULL;
  16. memset(seos_reader->params.cNonce, 0x0c, sizeof(seos_reader->params.cNonce));
  17. memset(seos_reader->params.UID, 0x0d, sizeof(seos_reader->params.UID));
  18. seos_reader->credential = credential;
  19. seos_reader->iso14443_4a_poller = iso14443_4a_poller;
  20. seos_reader->tx_buffer = bit_buffer_alloc(SEOS_WORKER_MAX_BUFFER_SIZE);
  21. seos_reader->rx_buffer = bit_buffer_alloc(SEOS_WORKER_MAX_BUFFER_SIZE);
  22. return seos_reader;
  23. }
  24. void seos_reader_free(SeosReader* seos_reader) {
  25. furi_assert(seos_reader);
  26. bit_buffer_free(seos_reader->tx_buffer);
  27. bit_buffer_free(seos_reader->rx_buffer);
  28. if(seos_reader->secure_messaging) {
  29. secure_messaging_free(seos_reader->secure_messaging);
  30. }
  31. free(seos_reader);
  32. }
  33. bool seos_reader_request_sio(SeosReader* seos_reader) {
  34. SecureMessaging* secure_messaging = seos_reader->secure_messaging;
  35. furi_assert(secure_messaging);
  36. Iso14443_4aPoller* iso14443_4a_poller = seos_reader->iso14443_4a_poller;
  37. BitBuffer* tx_buffer = seos_reader->tx_buffer;
  38. BitBuffer* rx_buffer = seos_reader->rx_buffer;
  39. Iso14443_4aError error;
  40. uint8_t message[] = {0x5c, 0x02, 0xff, 0x00};
  41. secure_messaging_wrap_apdu(secure_messaging, message, sizeof(message), tx_buffer);
  42. seos_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  43. error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
  44. if(error != Iso14443_4aErrorNone) {
  45. FURI_LOG_W(TAG, "iso14443_4a_poller_send_block error %d", error);
  46. return false;
  47. }
  48. bit_buffer_reset(tx_buffer);
  49. seos_log_bitbuffer(TAG, "NFC response(wrapped)", rx_buffer);
  50. secure_messaging_unwrap_rapdu(secure_messaging, rx_buffer);
  51. seos_log_bitbuffer(TAG, "NFC response(clear)", rx_buffer);
  52. // Skip fileId
  53. seos_reader->credential->sio_len = bit_buffer_get_byte(rx_buffer, 2);
  54. if(seos_reader->credential->sio_len > sizeof(seos_reader->credential->sio)) {
  55. FURI_LOG_W(TAG, "SIO too long to save");
  56. return false;
  57. }
  58. memcpy(
  59. seos_reader->credential->sio,
  60. bit_buffer_get_data(rx_buffer) + 3,
  61. seos_reader->credential->sio_len);
  62. return true;
  63. }
  64. void seos_reader_generate_cryptogram(
  65. SeosCredential* credential,
  66. AuthParameters* params,
  67. uint8_t* cryptogram) {
  68. seos_worker_diversify_key(
  69. SEOS_ADF1_READ,
  70. credential->diversifier,
  71. credential->diversifier_len,
  72. SEOS_ADF_OID,
  73. SEOS_ADF_OID_LEN,
  74. params->cipher,
  75. params->hash,
  76. params->key_no,
  77. true,
  78. params->priv_key);
  79. seos_worker_diversify_key(
  80. SEOS_ADF1_READ,
  81. credential->diversifier,
  82. credential->diversifier_len,
  83. SEOS_ADF_OID,
  84. SEOS_ADF_OID_LEN,
  85. params->cipher,
  86. params->hash,
  87. params->key_no,
  88. false,
  89. params->auth_key);
  90. uint8_t clear[32];
  91. memset(clear, 0, sizeof(clear));
  92. size_t index = 0;
  93. memcpy(clear + index, params->UID, sizeof(params->UID));
  94. index += sizeof(params->UID);
  95. memcpy(clear + index, params->rndICC, sizeof(params->rndICC));
  96. index += sizeof(params->rndICC);
  97. memcpy(clear + index, params->cNonce, sizeof(params->cNonce));
  98. index += sizeof(params->cNonce);
  99. uint8_t cmac[16];
  100. if(params->cipher == AES_128_CBC) {
  101. seos_worker_aes_encrypt(params->priv_key, sizeof(clear), clear, cryptogram);
  102. aes_cmac(params->auth_key, sizeof(params->auth_key), cryptogram, index, cmac);
  103. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  104. seos_worker_des_encrypt(params->priv_key, sizeof(clear), clear, cryptogram);
  105. des_cmac(params->auth_key, sizeof(params->auth_key), cryptogram, index, cmac);
  106. } else {
  107. FURI_LOG_W(TAG, "Cipher not matched");
  108. }
  109. memcpy(cryptogram + sizeof(clear), cmac, SEOS_WORKER_CMAC_SIZE);
  110. }
  111. bool seos_reader_verify_cryptogram(AuthParameters* params, const uint8_t* cryptogram) {
  112. // cryptogram is 40 bytes: 32 byte encrypted + 8 byte cmac
  113. size_t encrypted_len = 32;
  114. uint8_t* mac = (uint8_t*)cryptogram + encrypted_len;
  115. uint8_t cmac[16];
  116. if(params->cipher == AES_128_CBC) {
  117. aes_cmac(
  118. params->auth_key, sizeof(params->auth_key), (uint8_t*)cryptogram, encrypted_len, cmac);
  119. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  120. des_cmac(
  121. params->auth_key, sizeof(params->auth_key), (uint8_t*)cryptogram, encrypted_len, cmac);
  122. } else {
  123. FURI_LOG_W(TAG, "Cipher not matched");
  124. }
  125. if(memcmp(cmac, mac, SEOS_WORKER_CMAC_SIZE) != 0) {
  126. FURI_LOG_W(TAG, "Incorrect cryptogram mac %02x... vs %02x...", cmac[0], mac[0]);
  127. return false;
  128. }
  129. uint8_t clear[32];
  130. memset(clear, 0, sizeof(clear));
  131. if(params->cipher == AES_128_CBC) {
  132. seos_worker_aes_decrypt(params->priv_key, encrypted_len, cryptogram, clear);
  133. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  134. seos_worker_des_decrypt(params->priv_key, encrypted_len, cryptogram, clear);
  135. } else {
  136. FURI_LOG_W(TAG, "Cipher not matched");
  137. }
  138. // rndICC[8], UID[8], rNonce[16]
  139. uint8_t* rndICC = clear;
  140. if(memcmp(rndICC, params->rndICC, sizeof(params->rndICC)) != 0) {
  141. FURI_LOG_W(TAG, "Incorrect rndICC returned");
  142. return false;
  143. }
  144. uint8_t* UID = clear + 8;
  145. if(memcmp(UID, params->UID, sizeof(params->UID)) != 0) {
  146. FURI_LOG_W(TAG, "Incorrect UID returned");
  147. return false;
  148. }
  149. memcpy(params->rNonce, clear + 8 + 8, sizeof(params->rNonce));
  150. return true;
  151. }
  152. NfcCommand seos_reader_select_aid(SeosReader* seos_reader) {
  153. Iso14443_4aPoller* iso14443_4a_poller = seos_reader->iso14443_4a_poller;
  154. BitBuffer* tx_buffer = seos_reader->tx_buffer;
  155. BitBuffer* rx_buffer = seos_reader->rx_buffer;
  156. NfcCommand ret = NfcCommandContinue;
  157. Iso14443_4aError error;
  158. bit_buffer_append_bytes(tx_buffer, select, sizeof(select));
  159. error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
  160. if(error != Iso14443_4aErrorNone) {
  161. FURI_LOG_W(TAG, "iso14443_4a_poller_send_block error %d", error);
  162. return NfcCommandStop;
  163. }
  164. bit_buffer_reset(tx_buffer);
  165. seos_log_bitbuffer(TAG, "NFC response", rx_buffer);
  166. // TODO: validate response
  167. if(memcmp(
  168. bit_buffer_get_data(rx_buffer) + bit_buffer_get_size_bytes(rx_buffer) - sizeof(success),
  169. success,
  170. sizeof(success)) != 0) {
  171. FURI_LOG_W(TAG, "Non-success response");
  172. return NfcCommandStop;
  173. }
  174. if(memcmp(bit_buffer_get_data(rx_buffer), SEOS_APPLET_FCI, sizeof(SEOS_APPLET_FCI)) != 0) {
  175. FURI_LOG_W(TAG, "Unexpected select AID response");
  176. return NfcCommandStop;
  177. }
  178. return ret;
  179. }
  180. NfcCommand seos_reader_select_adf(SeosReader* seos_reader) {
  181. Iso14443_4aPoller* iso14443_4a_poller = seos_reader->iso14443_4a_poller;
  182. BitBuffer* tx_buffer = seos_reader->tx_buffer;
  183. BitBuffer* rx_buffer = seos_reader->rx_buffer;
  184. NfcCommand ret = NfcCommandContinue;
  185. Iso14443_4aError error;
  186. bit_buffer_append_bytes(tx_buffer, select_adf_header, sizeof(select_adf_header));
  187. bit_buffer_append_byte(tx_buffer, SEOS_ADF_OID_LEN);
  188. bit_buffer_append_bytes(tx_buffer, SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  189. bit_buffer_append_byte(tx_buffer, 0x00); // Le
  190. error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
  191. if(error != Iso14443_4aErrorNone) {
  192. FURI_LOG_W(TAG, "iso14443_4a_poller_send_block error %d", error);
  193. return NfcCommandStop;
  194. }
  195. bit_buffer_reset(tx_buffer);
  196. return ret;
  197. }
  198. bool seos_reader_select_adf_response(
  199. BitBuffer* rx_buffer,
  200. size_t offset,
  201. SeosCredential* credential,
  202. AuthParameters* params) {
  203. seos_log_bitbuffer(TAG, "response", rx_buffer);
  204. // cd 02 0206
  205. // 85 38 41c01a89db89aecf 4b35b4f18dc4045b2a3d65cdd1c1944e8c8548f786e6c51128a5c8546a27120a7e44ba0f4cd7218a026ea1a73a9211a9
  206. // 8e 08 20f830009042cb85
  207. uint8_t expected_header[] = {0xcd, 0x02};
  208. if(bit_buffer_get_size_bytes(rx_buffer) < sizeof(expected_header)) {
  209. FURI_LOG_W(TAG, "Invalid response length");
  210. return false;
  211. }
  212. // handle when the buffer starts with other stuff
  213. const uint8_t* rx_data = bit_buffer_get_data(rx_buffer) + offset;
  214. if(memcmp(rx_data, expected_header, sizeof(expected_header)) != 0) {
  215. FURI_LOG_W(TAG, "Invalid response");
  216. return false;
  217. }
  218. params->cipher = rx_data[2];
  219. params->hash = rx_data[3];
  220. size_t bufLen = 0;
  221. uint8_t clear[0x40];
  222. if(params->cipher == AES_128_CBC) {
  223. size_t ivLen = 16;
  224. bufLen = rx_data[5] - ivLen;
  225. uint8_t* iv = (uint8_t*)rx_data + 6;
  226. uint8_t* enc = (uint8_t*)rx_data + 6 + ivLen;
  227. mbedtls_aes_context ctx;
  228. mbedtls_aes_init(&ctx);
  229. mbedtls_aes_setkey_dec(&ctx, SEOS_ADF1_PRIV_ENC, sizeof(SEOS_ADF1_PRIV_ENC) * 8);
  230. mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, bufLen, iv, enc, clear);
  231. mbedtls_aes_free(&ctx);
  232. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  233. size_t ivLen = 8;
  234. bufLen = rx_data[5] - ivLen;
  235. uint8_t* iv = (uint8_t*)rx_data + 6;
  236. uint8_t* enc = (uint8_t*)rx_data + 6 + ivLen;
  237. mbedtls_des3_context ctx;
  238. mbedtls_des3_init(&ctx);
  239. mbedtls_des3_set2key_dec(&ctx, SEOS_ADF1_PRIV_ENC);
  240. mbedtls_des3_crypt_cbc(&ctx, MBEDTLS_DES_DECRYPT, bufLen, iv, enc, clear);
  241. mbedtls_des3_free(&ctx);
  242. }
  243. // 06112b0601040181e438010102011801010202 cf 07 3d4c010c71cfa7 e2d0b41a00cc5e494c8d52b6e562592399fe614a
  244. if(clear[0] != 0x06) {
  245. FURI_LOG_W(TAG, "Missing expected 0x06 at start of clear");
  246. return false;
  247. }
  248. size_t oidLen = clear[1];
  249. if(clear[2 + oidLen] != 0xCF) {
  250. FURI_LOG_W(TAG, "Missing expected 0xCF after OID");
  251. return false;
  252. }
  253. credential->diversifier_len = clear[2 + oidLen + 1];
  254. if(credential->diversifier_len > sizeof(credential->diversifier)) {
  255. FURI_LOG_W(TAG, "diversifier too large");
  256. return false;
  257. }
  258. uint8_t* diversifier = clear + 2 + oidLen + 2;
  259. memcpy(credential->diversifier, diversifier, credential->diversifier_len);
  260. char display[SEOS_WORKER_MAX_BUFFER_SIZE * 2 + 1];
  261. memset(display, 0, sizeof(display));
  262. for(uint8_t i = 0; i < credential->diversifier_len; i++) {
  263. snprintf(display + (i * 2), sizeof(display), "%02x", diversifier[i]);
  264. }
  265. FURI_LOG_D(TAG, "diversifier: %s", display);
  266. return true;
  267. }
  268. NfcCommand seos_reader_general_authenticate_1(SeosReader* seos_reader) {
  269. Iso14443_4aPoller* iso14443_4a_poller = seos_reader->iso14443_4a_poller;
  270. BitBuffer* tx_buffer = seos_reader->tx_buffer;
  271. BitBuffer* rx_buffer = seos_reader->rx_buffer;
  272. NfcCommand ret = NfcCommandContinue;
  273. Iso14443_4aError error;
  274. general_authenticate_1[3] = seos_reader->params.key_no;
  275. bit_buffer_append_bytes(tx_buffer, general_authenticate_1, sizeof(general_authenticate_1));
  276. seos_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  277. error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
  278. if(error != Iso14443_4aErrorNone) {
  279. FURI_LOG_W(TAG, "iso14443_4a_poller_send_block error %d", error);
  280. return NfcCommandStop;
  281. }
  282. bit_buffer_reset(tx_buffer);
  283. seos_log_bitbuffer(TAG, "NFC response", rx_buffer);
  284. // 7c0a8108018cde7d6049edb09000
  285. uint8_t expected_header[] = {0x7c, 0x0a, 0x81, 0x08};
  286. const uint8_t* rx_data = bit_buffer_get_data(rx_buffer);
  287. if(memcmp(rx_data, expected_header, sizeof(expected_header)) != 0) {
  288. FURI_LOG_W(TAG, "Invalid response");
  289. return NfcCommandStop;
  290. }
  291. memcpy(seos_reader->params.rndICC, rx_data + 4, 8);
  292. return ret;
  293. }
  294. NfcCommand seos_reader_general_authenticate_2(SeosReader* seos_reader) {
  295. Iso14443_4aPoller* iso14443_4a_poller = seos_reader->iso14443_4a_poller;
  296. BitBuffer* tx_buffer = seos_reader->tx_buffer;
  297. BitBuffer* rx_buffer = seos_reader->rx_buffer;
  298. NfcCommand ret = NfcCommandContinue;
  299. Iso14443_4aError error;
  300. uint8_t cryptogram[32 + 8];
  301. memset(cryptogram, 0, sizeof(cryptogram));
  302. seos_reader_generate_cryptogram(seos_reader->credential, &seos_reader->params, cryptogram);
  303. uint8_t ga_header[] = {
  304. 0x00, 0x87, 0x00, seos_reader->params.key_no, 0x2c, 0x7c, 0x2a, 0x82, 0x28};
  305. bit_buffer_append_bytes(tx_buffer, ga_header, sizeof(ga_header));
  306. bit_buffer_append_bytes(tx_buffer, cryptogram, sizeof(cryptogram));
  307. seos_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  308. error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
  309. if(error != Iso14443_4aErrorNone) {
  310. FURI_LOG_W(TAG, "iso14443_4a_poller_send_block error %d", error);
  311. return NfcCommandStop;
  312. }
  313. bit_buffer_reset(tx_buffer);
  314. seos_log_bitbuffer(TAG, "NFC response", rx_buffer);
  315. const uint8_t* rx_data = bit_buffer_get_data(rx_buffer);
  316. if(rx_data[0] != 0x7C || rx_data[2] != 0x82) {
  317. FURI_LOG_W(TAG, "Invalid rx_data");
  318. return NfcCommandStop;
  319. }
  320. if(rx_data[3] == 40) {
  321. if(!seos_reader_verify_cryptogram(&seos_reader->params, rx_data + 4)) {
  322. FURI_LOG_W(TAG, "Card cryptogram failed verification");
  323. return NfcCommandStop;
  324. }
  325. FURI_LOG_I(TAG, "Authenticated");
  326. } else {
  327. FURI_LOG_W(TAG, "Unhandled card cryptogram size %d", rx_data[3]);
  328. }
  329. seos_reader->secure_messaging = secure_messaging_alloc(&seos_reader->params);
  330. return ret;
  331. }
  332. NfcCommand seos_state_machine(Seos* seos, Iso14443_4aPoller* iso14443_4a_poller) {
  333. furi_assert(seos);
  334. NfcCommand ret = NfcCommandContinue;
  335. SeosReader* seos_reader = seos_reader_alloc(&seos->credential, iso14443_4a_poller);
  336. seos->seos_reader = seos_reader;
  337. do {
  338. ret = seos_reader_select_aid(seos_reader);
  339. if(ret == NfcCommandStop) break;
  340. ret = seos_reader_select_adf(seos_reader);
  341. if(ret == NfcCommandStop) break;
  342. if(!seos_reader_select_adf_response(
  343. seos_reader->rx_buffer, 0, seos_reader->credential, &seos_reader->params)) {
  344. break;
  345. }
  346. ret = seos_reader_general_authenticate_1(seos_reader);
  347. if(ret == NfcCommandStop) break;
  348. ret = seos_reader_general_authenticate_2(seos_reader);
  349. if(ret == NfcCommandStop) break;
  350. if(seos_reader_request_sio(seos_reader)) {
  351. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventReaderSuccess);
  352. }
  353. } while(false);
  354. // An error occurred
  355. if(ret == NfcCommandStop) {
  356. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventReaderError);
  357. }
  358. seos_reader_free(seos_reader);
  359. return NfcCommandStop;
  360. }
  361. NfcCommand seos_worker_poller_callback(NfcGenericEvent event, void* context) {
  362. furi_assert(event.protocol == NfcProtocolIso14443_4a);
  363. NfcCommand ret = NfcCommandContinue;
  364. Seos* seos = context;
  365. const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
  366. Iso14443_4aPoller* iso14443_4a_poller = event.instance;
  367. if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
  368. // view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventPollerDetect);
  369. nfc_device_set_data(
  370. seos->nfc_device, NfcProtocolIso14443_4a, nfc_poller_get_data(seos->poller));
  371. ret = seos_state_machine(seos, iso14443_4a_poller);
  372. // furi_thread_set_current_priority(FuriThreadPriorityLowest);
  373. } else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) {
  374. Iso14443_4aPollerEventData* data = iso14443_4a_event->data;
  375. Iso14443_4aError error = data->error;
  376. FURI_LOG_W(TAG, "Iso14443_4aError %i", error);
  377. // I was hoping to catch MFC here, but it seems to be treated the same (None) as no card being present.
  378. switch(error) {
  379. case Iso14443_4aErrorNone:
  380. break;
  381. case Iso14443_4aErrorNotPresent:
  382. break;
  383. case Iso14443_4aErrorProtocol:
  384. ret = NfcCommandStop;
  385. break;
  386. case Iso14443_4aErrorTimeout:
  387. break;
  388. }
  389. }
  390. return ret;
  391. }