passy_reader.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. #include "passy_reader.h"
  2. #define TAG "PassyReader"
  3. static uint8_t passport_aid[] = {0xA0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01};
  4. static uint8_t select_header[] = {0x00, 0xA4, 0x04, 0x0C};
  5. static uint8_t get_challenge[] = {0x00, 0x84, 0x00, 0x00, 0x08};
  6. static uint8_t SW_success[] = {0x90, 0x00};
  7. size_t asn1_length(uint8_t data[3]) {
  8. if(data[0] <= 0x7F) {
  9. return data[0];
  10. } else if(data[0] == 0x81) {
  11. return data[1];
  12. } else if(data[0] == 0x82) {
  13. return (data[1] << 8) | data[2];
  14. }
  15. return 0;
  16. }
  17. PassyReader* passy_reader_alloc(Passy* passy, Iso14443_4bPoller* iso14443_4b_poller) {
  18. PassyReader* passy_reader = malloc(sizeof(PassyReader));
  19. memset(passy_reader, 0, sizeof(PassyReader));
  20. passy_reader->iso14443_4b_poller = iso14443_4b_poller;
  21. passy_reader->DG1 = passy->DG1;
  22. passy_reader->tx_buffer = bit_buffer_alloc(PASSY_READER_MAX_BUFFER_SIZE);
  23. passy_reader->rx_buffer = bit_buffer_alloc(PASSY_READER_MAX_BUFFER_SIZE);
  24. char passport_number[11];
  25. memset(passport_number, 0, sizeof(passport_number));
  26. memcpy(passport_number, passy->passport_number, strlen(passy->passport_number));
  27. passport_number[strlen(passy->passport_number)] = passy_checksum(passy->passport_number);
  28. FURI_LOG_I(TAG, "Passport number: %s", passport_number);
  29. char date_of_birth[8];
  30. memset(date_of_birth, 0, sizeof(date_of_birth));
  31. memcpy(date_of_birth, passy->date_of_birth, strlen(passy->date_of_birth));
  32. date_of_birth[strlen(passy->date_of_birth)] = passy_checksum(passy->date_of_birth);
  33. FURI_LOG_I(TAG, "Date of birth: %s", date_of_birth);
  34. char date_of_expiry[8];
  35. memset(date_of_expiry, 0, sizeof(date_of_expiry));
  36. memcpy(date_of_expiry, passy->date_of_expiry, strlen(passy->date_of_expiry));
  37. date_of_expiry[strlen(passy->date_of_expiry)] = passy_checksum(passy->date_of_expiry);
  38. FURI_LOG_I(TAG, "Date of expiry: %s", date_of_expiry);
  39. passy_reader->secure_messaging = secure_messaging_alloc(
  40. (uint8_t*)passport_number, (uint8_t*)date_of_birth, (uint8_t*)date_of_expiry);
  41. return passy_reader;
  42. }
  43. void passy_reader_free(PassyReader* passy_reader) {
  44. furi_assert(passy_reader);
  45. bit_buffer_free(passy_reader->tx_buffer);
  46. bit_buffer_free(passy_reader->rx_buffer);
  47. if(passy_reader->secure_messaging) {
  48. secure_messaging_free(passy_reader->secure_messaging);
  49. }
  50. free(passy_reader);
  51. }
  52. NfcCommand passy_reader_select_application(PassyReader* passy_reader) {
  53. NfcCommand ret = NfcCommandContinue;
  54. BitBuffer* tx_buffer = passy_reader->tx_buffer;
  55. BitBuffer* rx_buffer = passy_reader->rx_buffer;
  56. Iso14443_4bPoller* iso14443_4b_poller = passy_reader->iso14443_4b_poller;
  57. Iso14443_4bError error;
  58. bit_buffer_append_bytes(tx_buffer, select_header, sizeof(select_header));
  59. bit_buffer_append_byte(tx_buffer, sizeof(passport_aid));
  60. bit_buffer_append_bytes(tx_buffer, passport_aid, sizeof(passport_aid));
  61. bit_buffer_append_byte(tx_buffer, 0x00); // Le
  62. error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  63. if(error != Iso14443_4bErrorNone) {
  64. FURI_LOG_W(TAG, "iso14443_4b_poller_send_block error %d", error);
  65. return NfcCommandStop;
  66. }
  67. bit_buffer_reset(tx_buffer);
  68. passy_log_bitbuffer(TAG, "NFC response", rx_buffer);
  69. // Check SW
  70. size_t length = bit_buffer_get_size_bytes(rx_buffer);
  71. const uint8_t* data = bit_buffer_get_data(rx_buffer);
  72. if(length < 2) {
  73. FURI_LOG_W(TAG, "Invalid response length %d", length);
  74. return NfcCommandStop;
  75. }
  76. if(memcmp(data + length - 2, SW_success, sizeof(SW_success)) != 0) {
  77. FURI_LOG_W(TAG, "Invalid SW %02x %02x", data[length - 2], data[length - 1]);
  78. return NfcCommandStop;
  79. }
  80. return ret;
  81. }
  82. NfcCommand passy_reader_get_challenge(PassyReader* passy_reader) {
  83. NfcCommand ret = NfcCommandContinue;
  84. BitBuffer* tx_buffer = passy_reader->tx_buffer;
  85. BitBuffer* rx_buffer = passy_reader->rx_buffer;
  86. Iso14443_4bPoller* iso14443_4b_poller = passy_reader->iso14443_4b_poller;
  87. Iso14443_4bError error;
  88. bit_buffer_append_bytes(tx_buffer, get_challenge, sizeof(get_challenge));
  89. error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  90. if(error != Iso14443_4bErrorNone) {
  91. FURI_LOG_W(TAG, "iso14443_4b_poller_send_block error %d", error);
  92. return NfcCommandStop;
  93. }
  94. bit_buffer_reset(tx_buffer);
  95. passy_log_bitbuffer(TAG, "NFC response", rx_buffer);
  96. // Check SW
  97. size_t length = bit_buffer_get_size_bytes(rx_buffer);
  98. const uint8_t* data = bit_buffer_get_data(rx_buffer);
  99. if(length < 2) {
  100. FURI_LOG_W(TAG, "Invalid response length %d", length);
  101. return NfcCommandStop;
  102. }
  103. if(memcmp(data + length - 2, SW_success, sizeof(SW_success)) != 0) {
  104. FURI_LOG_W(TAG, "Invalid SW %02x %02x", data[length - 2], data[length - 1]);
  105. return NfcCommandStop;
  106. }
  107. SecureMessaging* secure_messaging = passy_reader->secure_messaging;
  108. const uint8_t* rnd_icc = data;
  109. memcpy(secure_messaging->rndICC, rnd_icc, 8);
  110. return ret;
  111. }
  112. NfcCommand passy_reader_authenticate(PassyReader* passy_reader) {
  113. NfcCommand ret = NfcCommandContinue;
  114. BitBuffer* tx_buffer = passy_reader->tx_buffer;
  115. BitBuffer* rx_buffer = passy_reader->rx_buffer;
  116. Iso14443_4bPoller* iso14443_4b_poller = passy_reader->iso14443_4b_poller;
  117. Iso14443_4bError error;
  118. // TODO: move into secure_messaging
  119. SecureMessaging* secure_messaging = passy_reader->secure_messaging;
  120. uint8_t S[32];
  121. memset(S, 0, sizeof(S));
  122. uint8_t eifd[32];
  123. memcpy(S, secure_messaging->rndIFD, sizeof(secure_messaging->rndIFD));
  124. memcpy(
  125. S + sizeof(secure_messaging->rndIFD),
  126. secure_messaging->rndICC,
  127. sizeof(secure_messaging->rndICC));
  128. memcpy(
  129. S + sizeof(secure_messaging->rndIFD) + sizeof(secure_messaging->rndICC),
  130. secure_messaging->Kifd,
  131. sizeof(secure_messaging->Kifd));
  132. uint8_t iv[8];
  133. memset(iv, 0, sizeof(iv));
  134. mbedtls_des3_context ctx;
  135. mbedtls_des3_init(&ctx);
  136. mbedtls_des3_set2key_enc(&ctx, secure_messaging->KENC);
  137. mbedtls_des3_crypt_cbc(&ctx, MBEDTLS_DES_ENCRYPT, sizeof(S), iv, S, eifd);
  138. mbedtls_des3_free(&ctx);
  139. passy_log_buffer(TAG, "S", S, sizeof(S));
  140. passy_log_buffer(TAG, "eifd", eifd, sizeof(eifd));
  141. uint8_t mifd[8];
  142. passy_mac(secure_messaging->KMAC, eifd, sizeof(eifd), mifd, false);
  143. passy_log_buffer(TAG, "mifd", mifd, sizeof(mifd));
  144. uint8_t authenticate_header[] = {0x00, 0x82, 0x00, 0x00};
  145. bit_buffer_append_bytes(tx_buffer, authenticate_header, sizeof(authenticate_header));
  146. bit_buffer_append_byte(tx_buffer, sizeof(eifd) + sizeof(mifd));
  147. bit_buffer_append_bytes(tx_buffer, eifd, sizeof(eifd));
  148. bit_buffer_append_bytes(tx_buffer, mifd, sizeof(mifd));
  149. bit_buffer_append_byte(tx_buffer, 0x28); // Le
  150. passy_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  151. error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  152. if(error != Iso14443_4bErrorNone) {
  153. FURI_LOG_W(TAG, "iso14443_4b_poller_send_block error %d", error);
  154. return NfcCommandStop;
  155. }
  156. bit_buffer_reset(tx_buffer);
  157. passy_log_bitbuffer(TAG, "NFC response", rx_buffer);
  158. // Check SW
  159. size_t length = bit_buffer_get_size_bytes(rx_buffer);
  160. const uint8_t* data = bit_buffer_get_data(rx_buffer);
  161. if(length < 2) {
  162. FURI_LOG_W(TAG, "Invalid response length %d", length);
  163. return NfcCommandStop;
  164. }
  165. if(memcmp(data + length - 2, SW_success, sizeof(SW_success)) != 0) {
  166. FURI_LOG_W(TAG, "Invalid SW %02x %02x", data[length - 2], data[length - 1]);
  167. return NfcCommandStop;
  168. }
  169. const uint8_t* mac = data + length - 2 - 8;
  170. uint8_t calculated_mac[8];
  171. passy_mac(secure_messaging->KMAC, (uint8_t*)data, length - 8 - 2, calculated_mac, false);
  172. if(memcmp(mac, calculated_mac, sizeof(calculated_mac)) != 0) {
  173. FURI_LOG_W(TAG, "Invalid MAC");
  174. return NfcCommandStop;
  175. }
  176. uint8_t decrypted[32];
  177. do {
  178. uint8_t iv[8];
  179. memset(iv, 0, sizeof(iv));
  180. mbedtls_des3_context ctx;
  181. mbedtls_des3_init(&ctx);
  182. mbedtls_des3_set2key_dec(&ctx, secure_messaging->KENC);
  183. mbedtls_des3_crypt_cbc(&ctx, MBEDTLS_DES_DECRYPT, length - 2 - 8, iv, data, decrypted);
  184. mbedtls_des3_free(&ctx);
  185. } while(false);
  186. passy_log_buffer(TAG, "decrypted", decrypted, sizeof(decrypted));
  187. uint8_t* rnd_icc = decrypted;
  188. uint8_t* rnd_ifd = decrypted + 8;
  189. uint8_t* Kicc = decrypted + 16;
  190. if(memcmp(rnd_icc, secure_messaging->rndICC, sizeof(secure_messaging->rndICC)) != 0) {
  191. FURI_LOG_W(TAG, "Invalid rndICC");
  192. return NfcCommandStop;
  193. }
  194. memcpy(secure_messaging->Kicc, Kicc, sizeof(secure_messaging->Kicc));
  195. memcpy(secure_messaging->SSC + 0, rnd_icc + 4, 4);
  196. memcpy(secure_messaging->SSC + 4, rnd_ifd + 4, 4);
  197. return ret;
  198. }
  199. NfcCommand passy_reader_select_file(PassyReader* passy_reader, uint16_t file_id) {
  200. NfcCommand ret = NfcCommandContinue;
  201. BitBuffer* tx_buffer = passy_reader->tx_buffer;
  202. BitBuffer* rx_buffer = passy_reader->rx_buffer;
  203. Iso14443_4bPoller* iso14443_4b_poller = passy_reader->iso14443_4b_poller;
  204. Iso14443_4bError error;
  205. uint8_t select_0101[] = {0x00, 0xa4, 0x02, 0x0c, 0x02, 0x00, 0x00};
  206. select_0101[5] = (file_id >> 8) & 0xFF;
  207. select_0101[6] = file_id & 0xFF;
  208. secure_messaging_wrap_apdu(
  209. passy_reader->secure_messaging, select_0101, sizeof(select_0101), tx_buffer);
  210. passy_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  211. error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  212. if(error != Iso14443_4bErrorNone) {
  213. FURI_LOG_W(TAG, "iso14443_4b_poller_send_block error %d", error);
  214. return NfcCommandStop;
  215. }
  216. bit_buffer_reset(tx_buffer);
  217. passy_log_bitbuffer(TAG, "NFC response", rx_buffer);
  218. // Check SW
  219. size_t length = bit_buffer_get_size_bytes(rx_buffer);
  220. const uint8_t* data = bit_buffer_get_data(rx_buffer);
  221. if(length < 2) {
  222. FURI_LOG_W(TAG, "Invalid response length %d", length);
  223. return NfcCommandStop;
  224. }
  225. if(memcmp(data + length - 2, SW_success, sizeof(SW_success)) != 0) {
  226. FURI_LOG_W(TAG, "Invalid SW %02x %02x", data[length - 2], data[length - 1]);
  227. return NfcCommandStop;
  228. }
  229. secure_messaging_unwrap_rapdu(passy_reader->secure_messaging, rx_buffer);
  230. passy_log_bitbuffer(TAG, "NFC response (decrypted)", rx_buffer);
  231. return ret;
  232. }
  233. NfcCommand passy_reader_read_binary(
  234. PassyReader* passy_reader,
  235. uint8_t offset,
  236. uint8_t Le,
  237. uint8_t* output_buffer) {
  238. NfcCommand ret = NfcCommandContinue;
  239. BitBuffer* tx_buffer = passy_reader->tx_buffer;
  240. BitBuffer* rx_buffer = passy_reader->rx_buffer;
  241. Iso14443_4bPoller* iso14443_4b_poller = passy_reader->iso14443_4b_poller;
  242. Iso14443_4bError error;
  243. uint8_t read_binary[] = {0x00, 0xB0, 0x00, offset, Le};
  244. secure_messaging_wrap_apdu(
  245. passy_reader->secure_messaging, read_binary, sizeof(read_binary), tx_buffer);
  246. passy_log_bitbuffer(TAG, "NFC transmit", tx_buffer);
  247. error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  248. if(error != Iso14443_4bErrorNone) {
  249. FURI_LOG_W(TAG, "iso14443_4b_poller_send_block error %d", error);
  250. return NfcCommandStop;
  251. }
  252. bit_buffer_reset(tx_buffer);
  253. passy_log_bitbuffer(TAG, "NFC response", rx_buffer);
  254. // Check SW
  255. size_t length = bit_buffer_get_size_bytes(rx_buffer);
  256. const uint8_t* data = bit_buffer_get_data(rx_buffer);
  257. if(length < 2) {
  258. FURI_LOG_W(TAG, "Invalid response length %d", length);
  259. return NfcCommandStop;
  260. }
  261. if(memcmp(data + length - 2, SW_success, sizeof(SW_success)) != 0) {
  262. FURI_LOG_W(TAG, "Invalid SW %02x %02x", data[length - 2], data[length - 1]);
  263. return NfcCommandStop;
  264. }
  265. secure_messaging_unwrap_rapdu(passy_reader->secure_messaging, rx_buffer);
  266. passy_log_bitbuffer(TAG, "NFC response (decrypted)", rx_buffer);
  267. const uint8_t* decrypted_data = bit_buffer_get_data(rx_buffer);
  268. memcpy(output_buffer, decrypted_data, Le);
  269. return ret;
  270. }
  271. NfcCommand passy_reader_state_machine(Passy* passy, PassyReader* passy_reader) {
  272. furi_assert(passy_reader);
  273. NfcCommand ret = NfcCommandContinue;
  274. do {
  275. ret = passy_reader_select_application(passy_reader);
  276. if(ret != NfcCommandContinue) {
  277. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  278. break;
  279. }
  280. ret = passy_reader_get_challenge(passy_reader);
  281. if(ret != NfcCommandContinue) {
  282. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  283. break;
  284. }
  285. ret = passy_reader_authenticate(passy_reader);
  286. if(ret != NfcCommandContinue) {
  287. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  288. break;
  289. }
  290. FURI_LOG_I(TAG, "Mututal authentication success");
  291. secure_messaging_calculate_session_keys(passy_reader->secure_messaging);
  292. view_dispatcher_send_custom_event(
  293. passy->view_dispatcher, PassyCustomEventReaderAuthenticated);
  294. ret = passy_reader_select_file(passy_reader, 0x0101);
  295. if(ret != NfcCommandContinue) {
  296. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  297. break;
  298. }
  299. bit_buffer_reset(passy->DG1);
  300. uint8_t header[4];
  301. ret = passy_reader_read_binary(passy_reader, 0x00, 0x04, header);
  302. if(ret != NfcCommandContinue) {
  303. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  304. break;
  305. }
  306. size_t body_size = asn1_length(header + 1);
  307. uint8_t body_offset = 0x04;
  308. do {
  309. view_dispatcher_send_custom_event(
  310. passy->view_dispatcher, PassyCustomEventReaderReading);
  311. uint8_t chunk[0x20];
  312. uint8_t Le = MIN(sizeof(chunk), (size_t)(body_size - body_offset));
  313. ret = passy_reader_read_binary(passy_reader, body_offset, Le, chunk);
  314. if(ret != NfcCommandContinue) {
  315. view_dispatcher_send_custom_event(
  316. passy->view_dispatcher, PassyCustomEventReaderError);
  317. break;
  318. }
  319. bit_buffer_append_bytes(passy_reader->DG1, chunk, sizeof(chunk));
  320. body_offset += sizeof(chunk);
  321. } while(body_offset < body_size);
  322. passy_log_bitbuffer(TAG, "DG1", passy_reader->DG1);
  323. ret = passy_reader_select_file(passy_reader, 0x0102);
  324. if(ret != NfcCommandContinue) {
  325. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  326. break;
  327. }
  328. ret = passy_reader_read_binary(passy_reader, 0x00, 0x04, header);
  329. if(ret != NfcCommandContinue) {
  330. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderError);
  331. break;
  332. }
  333. body_size = asn1_length(header + 1);
  334. FURI_LOG_I(TAG, "DG2 length: %d", body_size);
  335. // Everything done
  336. ret = NfcCommandStop;
  337. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderSuccess);
  338. } while(false);
  339. return ret;
  340. }
  341. NfcCommand passy_reader_poller_callback(NfcGenericEvent event, void* context) {
  342. furi_assert(event.protocol == NfcProtocolIso14443_4b);
  343. Passy* passy = context;
  344. NfcCommand ret = NfcCommandContinue;
  345. const Iso14443_4bPollerEvent* iso14443_4b_event = event.event_data;
  346. Iso14443_4bPoller* iso14443_4b_poller = event.instance;
  347. FURI_LOG_D(TAG, "iso14443_4b_event->type %i", iso14443_4b_event->type);
  348. PassyReader* passy_reader = passy_reader_alloc(passy, iso14443_4b_poller);
  349. if(iso14443_4b_event->type == Iso14443_4bPollerEventTypeReady) {
  350. view_dispatcher_send_custom_event(passy->view_dispatcher, PassyCustomEventReaderDetected);
  351. nfc_device_set_data(
  352. passy->nfc_device, NfcProtocolIso14443_4b, nfc_poller_get_data(passy->poller));
  353. ret = passy_reader_state_machine(passy, passy_reader);
  354. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  355. } else if(iso14443_4b_event->type == Iso14443_4bPollerEventTypeError) {
  356. Iso14443_4bPollerEventData* data = iso14443_4b_event->data;
  357. Iso14443_4bError error = data->error;
  358. FURI_LOG_W(TAG, "Iso14443_4bError %i", error);
  359. switch(error) {
  360. case Iso14443_4bErrorNone:
  361. break;
  362. case Iso14443_4bErrorNotPresent:
  363. break;
  364. case Iso14443_4bErrorProtocol:
  365. ret = NfcCommandStop;
  366. break;
  367. case Iso14443_4bErrorTimeout:
  368. break;
  369. }
  370. }
  371. passy_reader_free(passy_reader);
  372. return ret;
  373. }