seos_reader.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  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. // TODO: support value from keys file
  9. static uint8_t select_adf[] = {0x80, 0xa5, 0x04, 0x00, 0x13, 0x06, 0x11, 0x2b, 0x06,
  10. 0x01, 0x04, 0x01, 0x81, 0xe4, 0x38, 0x01, 0x01, 0x02,
  11. 0x01, 0x18, 0x01, 0x01, 0x02, 0x02, 0x00};
  12. static uint8_t general_authenticate_1[] =
  13. {0x00, 0x87, 0x00, 0x01, 0x04, 0x7c, 0x02, 0x81, 0x00, 0x00};
  14. SeosReader* seos_reader_alloc(SeosCredential* credential, Iso14443_4aPoller* iso14443_4a_poller) {
  15. SeosReader* seos_reader = malloc(sizeof(SeosReader));
  16. memset(seos_reader, 0, sizeof(SeosReader));
  17. seos_reader->params.key_no = 1;
  18. seos_reader->secure_messaging = NULL;
  19. memset(seos_reader->params.cNonce, 0x0c, sizeof(seos_reader->params.cNonce));
  20. memset(seos_reader->params.UID, 0x0d, sizeof(seos_reader->params.UID));
  21. seos_reader->credential = credential;
  22. seos_reader->iso14443_4a_poller = iso14443_4a_poller;
  23. seos_reader->tx_buffer = bit_buffer_alloc(SEOS_WORKER_MAX_BUFFER_SIZE);
  24. seos_reader->rx_buffer = bit_buffer_alloc(SEOS_WORKER_MAX_BUFFER_SIZE);
  25. return seos_reader;
  26. }
  27. void seos_reader_free(SeosReader* seos_reader) {
  28. furi_assert(seos_reader);
  29. bit_buffer_free(seos_reader->tx_buffer);
  30. bit_buffer_free(seos_reader->rx_buffer);
  31. if(seos_reader->secure_messaging) {
  32. secure_messaging_free(seos_reader->secure_messaging);
  33. }
  34. free(seos_reader);
  35. }
  36. bool seos_reader_request_sio(SeosReader* seos_reader) {
  37. SecureMessaging* secure_messaging = seos_reader->secure_messaging;
  38. furi_assert(secure_messaging);
  39. Iso14443_4aPoller* iso14443_4a_poller = seos_reader->iso14443_4a_poller;
  40. BitBuffer* tx_buffer = seos_reader->tx_buffer;
  41. BitBuffer* rx_buffer = seos_reader->rx_buffer;
  42. Iso14443_4aError error;
  43. uint8_t message[] = {0x5c, 0x02, 0xff, 0x00};
  44. secure_messaging_wrap_apdu(secure_messaging, message, sizeof(message), tx_buffer);
  45. seos_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  46. error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
  47. if(error != Iso14443_4aErrorNone) {
  48. FURI_LOG_W(TAG, "iso14443_4a_poller_send_block error %d", error);
  49. return false;
  50. }
  51. bit_buffer_reset(tx_buffer);
  52. seos_log_bitbuffer(TAG, "NFC response(wrapped)", rx_buffer);
  53. secure_messaging_unwrap_rapdu(secure_messaging, rx_buffer);
  54. seos_log_bitbuffer(TAG, "NFC response(clear)", rx_buffer);
  55. // Skip fileId
  56. seos_reader->credential->sio_len = bit_buffer_get_byte(rx_buffer, 2);
  57. if(seos_reader->credential->sio_len > sizeof(seos_reader->credential->sio)) {
  58. FURI_LOG_W(TAG, "SIO too long to save");
  59. return false;
  60. }
  61. memcpy(
  62. seos_reader->credential->sio,
  63. bit_buffer_get_data(rx_buffer) + 3,
  64. seos_reader->credential->sio_len);
  65. return true;
  66. }
  67. void seos_reader_generate_cryptogram(
  68. SeosCredential* credential,
  69. AuthParameters* params,
  70. uint8_t* cryptogram) {
  71. seos_worker_diversify_key(
  72. SEOS_ADF1_READ,
  73. credential->diversifier,
  74. credential->diversifier_len,
  75. SEOS_ADF_OID,
  76. SEOS_ADF_OID_LEN,
  77. params->cipher,
  78. params->hash,
  79. params->key_no,
  80. true,
  81. params->priv_key);
  82. seos_worker_diversify_key(
  83. SEOS_ADF1_READ,
  84. credential->diversifier,
  85. credential->diversifier_len,
  86. SEOS_ADF_OID,
  87. SEOS_ADF_OID_LEN,
  88. params->cipher,
  89. params->hash,
  90. params->key_no,
  91. false,
  92. params->auth_key);
  93. uint8_t clear[32];
  94. memset(clear, 0, sizeof(clear));
  95. size_t index = 0;
  96. memcpy(clear + index, params->UID, sizeof(params->UID));
  97. index += sizeof(params->UID);
  98. memcpy(clear + index, params->rndICC, sizeof(params->rndICC));
  99. index += sizeof(params->rndICC);
  100. memcpy(clear + index, params->cNonce, sizeof(params->cNonce));
  101. index += sizeof(params->cNonce);
  102. uint8_t cmac[16];
  103. if(params->cipher == AES_128_CBC) {
  104. seos_worker_aes_encrypt(params->priv_key, sizeof(clear), clear, cryptogram);
  105. aes_cmac(params->auth_key, sizeof(params->auth_key), cryptogram, index, cmac);
  106. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  107. seos_worker_des_encrypt(params->priv_key, sizeof(clear), clear, cryptogram);
  108. des_cmac(params->auth_key, sizeof(params->auth_key), cryptogram, index, cmac);
  109. } else {
  110. FURI_LOG_W(TAG, "Cipher not matched");
  111. }
  112. memcpy(cryptogram + sizeof(clear), cmac, SEOS_WORKER_CMAC_SIZE);
  113. }
  114. bool seos_reader_verify_cryptogram(AuthParameters* params, const uint8_t* cryptogram) {
  115. // cryptogram is 40 bytes: 32 byte encrypted + 8 byte cmac
  116. size_t encrypted_len = 32;
  117. uint8_t* mac = (uint8_t*)cryptogram + encrypted_len;
  118. uint8_t cmac[16];
  119. if(params->cipher == AES_128_CBC) {
  120. aes_cmac(
  121. params->auth_key, sizeof(params->auth_key), (uint8_t*)cryptogram, encrypted_len, cmac);
  122. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  123. des_cmac(
  124. params->auth_key, sizeof(params->auth_key), (uint8_t*)cryptogram, encrypted_len, cmac);
  125. } else {
  126. FURI_LOG_W(TAG, "Cipher not matched");
  127. }
  128. if(memcmp(cmac, mac, SEOS_WORKER_CMAC_SIZE) != 0) {
  129. FURI_LOG_W(TAG, "Incorrect cryptogram mac %02x... vs %02x...", cmac[0], mac[0]);
  130. return false;
  131. }
  132. uint8_t clear[32];
  133. memset(clear, 0, sizeof(clear));
  134. if(params->cipher == AES_128_CBC) {
  135. seos_worker_aes_decrypt(params->priv_key, encrypted_len, cryptogram, clear);
  136. } else if(params->cipher == TWO_KEY_3DES_CBC_MODE) {
  137. seos_worker_des_decrypt(params->priv_key, encrypted_len, cryptogram, clear);
  138. } else {
  139. FURI_LOG_W(TAG, "Cipher not matched");
  140. }
  141. // rndICC[8], UID[8], rNonce[16]
  142. uint8_t* rndICC = clear;
  143. if(memcmp(rndICC, params->rndICC, sizeof(params->rndICC)) != 0) {
  144. FURI_LOG_W(TAG, "Incorrect rndICC returned");
  145. return false;
  146. }
  147. uint8_t* UID = clear + 8;
  148. if(memcmp(UID, params->UID, sizeof(params->UID)) != 0) {
  149. FURI_LOG_W(TAG, "Incorrect UID returned");
  150. return false;
  151. }
  152. memcpy(params->rNonce, clear + 8 + 8, sizeof(params->rNonce));
  153. return true;
  154. }
  155. NfcCommand seos_reader_select_aid(SeosReader* seos_reader) {
  156. Iso14443_4aPoller* iso14443_4a_poller = seos_reader->iso14443_4a_poller;
  157. BitBuffer* tx_buffer = seos_reader->tx_buffer;
  158. BitBuffer* rx_buffer = seos_reader->rx_buffer;
  159. NfcCommand ret = NfcCommandContinue;
  160. Iso14443_4aError error;
  161. bit_buffer_append_bytes(tx_buffer, select, sizeof(select));
  162. error = iso14443_4a_poller_send_block(iso14443_4a_poller, tx_buffer, rx_buffer);
  163. if(error != Iso14443_4aErrorNone) {
  164. FURI_LOG_W(TAG, "iso14443_4a_poller_send_block error %d", error);
  165. return NfcCommandStop;
  166. }
  167. bit_buffer_reset(tx_buffer);
  168. seos_log_bitbuffer(TAG, "NFC response", rx_buffer);
  169. // TODO: validate response
  170. if(memcmp(
  171. bit_buffer_get_data(rx_buffer) + bit_buffer_get_size_bytes(rx_buffer) - sizeof(success),
  172. success,
  173. sizeof(success)) != 0) {
  174. FURI_LOG_W(TAG, "Non-success response");
  175. return NfcCommandStop;
  176. }
  177. if(memcmp(bit_buffer_get_data(rx_buffer), SEOS_APPLET_FCI, sizeof(SEOS_APPLET_FCI)) != 0) {
  178. FURI_LOG_W(TAG, "Unexpected select AID response");
  179. return NfcCommandStop;
  180. }
  181. return ret;
  182. }
  183. NfcCommand seos_reader_select_adf(SeosReader* seos_reader) {
  184. Iso14443_4aPoller* iso14443_4a_poller = seos_reader->iso14443_4a_poller;
  185. BitBuffer* tx_buffer = seos_reader->tx_buffer;
  186. BitBuffer* rx_buffer = seos_reader->rx_buffer;
  187. NfcCommand ret = NfcCommandContinue;
  188. Iso14443_4aError error;
  189. bit_buffer_append_bytes(tx_buffer, select_adf, sizeof(select_adf));
  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. }