seos_native_peripheral.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. #include "seos_native_peripheral_i.h"
  2. #define TAG "SeosNativePeripheral"
  3. #define MESSAGE_QUEUE_SIZE 10
  4. static uint8_t standard_seos_aid[] = {0xa0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x01, 0x01, 0x00, 0x01};
  5. static uint8_t cd02[] = {0xcd, 0x02};
  6. static uint8_t general_authenticate_1[] =
  7. {0x00, 0x87, 0x00, 0x01, 0x04, 0x7c, 0x02, 0x81, 0x00, 0x00};
  8. static uint8_t ga1_response[] = {0x7c, 0x0a, 0x81, 0x08};
  9. // Emulation
  10. static uint8_t success[] = {0x90, 0x00};
  11. static uint8_t file_not_found[] = {0x6A, 0x82};
  12. static uint8_t select_header[] = {0x00, 0xa4, 0x04, 0x00};
  13. static uint8_t select_adf_header[] = {0x80, 0xa5, 0x04, 0x00};
  14. static uint8_t general_authenticate_2_header[] = {0x00, 0x87, 0x00, 0x01};
  15. static uint8_t secure_messaging_header[] = {0x0c, 0xcb, 0x3f, 0xff};
  16. int32_t seos_native_peripheral_task(void* context);
  17. typedef struct {
  18. size_t len;
  19. uint8_t buf[BLE_SVC_SEOS_CHAR_VALUE_LEN_MAX];
  20. } NativePeripheralMessage;
  21. static void seos_ble_connection_status_callback(BtStatus status, void* context) {
  22. furi_assert(context);
  23. SeosNativePeripheral* seos_native_peripheral = context;
  24. if(status == BtStatusConnected) {
  25. view_dispatcher_send_custom_event(
  26. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventConnected);
  27. } else if(status == BtStatusAdvertising) {
  28. view_dispatcher_send_custom_event(
  29. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventAdvertising);
  30. }
  31. }
  32. static uint16_t seos_svc_callback(SeosServiceEvent event, void* context) {
  33. SeosNativePeripheral* seos_native_peripheral = context;
  34. uint16_t bytes_available = 0;
  35. if(event.event == SeosServiceEventTypeDataReceived) {
  36. uint32_t space = furi_message_queue_get_space(seos_native_peripheral->messages);
  37. if(space > 0) {
  38. NativePeripheralMessage message = {.len = event.data.size};
  39. memcpy(message.buf, event.data.buffer, event.data.size);
  40. if(furi_mutex_acquire(seos_native_peripheral->mq_mutex, FuriWaitForever) ==
  41. FuriStatusOk) {
  42. furi_message_queue_put(
  43. seos_native_peripheral->messages, &message, FuriWaitForever);
  44. furi_mutex_release(seos_native_peripheral->mq_mutex);
  45. }
  46. if(space < MESSAGE_QUEUE_SIZE / 2) {
  47. FURI_LOG_D(TAG, "Queue message. %ld remaining", space);
  48. }
  49. bytes_available = (space - 1) * sizeof(NativePeripheralMessage);
  50. } else {
  51. FURI_LOG_E(TAG, "No space in message queue");
  52. }
  53. }
  54. return bytes_available;
  55. }
  56. SeosNativePeripheral* seos_native_peripheral_alloc(Seos* seos) {
  57. SeosNativePeripheral* seos_native_peripheral = malloc(sizeof(SeosNativePeripheral));
  58. memset(seos_native_peripheral, 0, sizeof(SeosNativePeripheral));
  59. seos_native_peripheral->seos = seos;
  60. seos_native_peripheral->credential = seos->credential;
  61. seos_native_peripheral->bt = furi_record_open(RECORD_BT);
  62. seos_native_peripheral->phase = SELECT_AID;
  63. seos_native_peripheral->secure_messaging = NULL;
  64. seos_native_peripheral->params.key_no = 1;
  65. memset(
  66. seos_native_peripheral->params.cNonce,
  67. 0x0c,
  68. sizeof(seos_native_peripheral->params.cNonce));
  69. memset(seos_native_peripheral->params.UID, 0x0d, sizeof(seos_native_peripheral->params.UID));
  70. seos_native_peripheral->thread = furi_thread_alloc_ex(
  71. "SeosNativePeripheralWorker",
  72. 5 * 1024,
  73. seos_native_peripheral_task,
  74. seos_native_peripheral);
  75. seos_native_peripheral->messages =
  76. furi_message_queue_alloc(MESSAGE_QUEUE_SIZE, sizeof(NativePeripheralMessage));
  77. seos_native_peripheral->mq_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  78. return seos_native_peripheral;
  79. }
  80. void seos_native_peripheral_free(SeosNativePeripheral* seos_native_peripheral) {
  81. furi_assert(seos_native_peripheral);
  82. furi_record_close(RECORD_BT);
  83. furi_message_queue_free(seos_native_peripheral->messages);
  84. furi_mutex_free(seos_native_peripheral->mq_mutex);
  85. furi_thread_free(seos_native_peripheral->thread);
  86. free(seos_native_peripheral);
  87. }
  88. void seos_native_peripheral_start(SeosNativePeripheral* seos_native_peripheral, FlowMode mode) {
  89. seos_native_peripheral->flow_mode = mode;
  90. if(seos_native_peripheral->flow_mode == FLOW_CRED) {
  91. seos_native_peripheral->params.key_no = 0;
  92. seos_native_peripheral->params.cipher = TWO_KEY_3DES_CBC_MODE;
  93. seos_native_peripheral->params.hash = SHA1;
  94. memset(
  95. seos_native_peripheral->params.rndICC,
  96. 0x0d,
  97. sizeof(seos_native_peripheral->params.rndICC));
  98. memset(
  99. seos_native_peripheral->params.rNonce,
  100. 0x0c,
  101. sizeof(seos_native_peripheral->params.rNonce));
  102. memset(
  103. seos_native_peripheral->params.UID, 0x00, sizeof(seos_native_peripheral->params.UID));
  104. memset(
  105. seos_native_peripheral->params.cNonce,
  106. 0x00,
  107. sizeof(seos_native_peripheral->params.cNonce));
  108. }
  109. bt_disconnect(seos_native_peripheral->bt);
  110. BleProfileParams params = {
  111. .mode = mode,
  112. };
  113. // Wait 2nd core to update nvm storage
  114. furi_delay_ms(200);
  115. seos_native_peripheral->ble_profile =
  116. bt_profile_start(seos_native_peripheral->bt, ble_profile_seos, &params);
  117. furi_check(seos_native_peripheral->ble_profile);
  118. bt_set_status_changed_callback(
  119. seos_native_peripheral->bt, seos_ble_connection_status_callback, seos_native_peripheral);
  120. ble_profile_seos_set_event_callback(
  121. seos_native_peripheral->ble_profile,
  122. sizeof(seos_native_peripheral->event_buffer),
  123. seos_svc_callback,
  124. seos_native_peripheral);
  125. furi_hal_bt_start_advertising();
  126. view_dispatcher_send_custom_event(
  127. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventAdvertising);
  128. furi_thread_start(seos_native_peripheral->thread);
  129. }
  130. void seos_native_peripheral_stop(SeosNativePeripheral* seos_native_peripheral) {
  131. furi_hal_bt_stop_advertising();
  132. bt_set_status_changed_callback(seos_native_peripheral->bt, NULL, NULL);
  133. bt_disconnect(seos_native_peripheral->bt);
  134. // Wait 2nd core to update nvm storage
  135. furi_delay_ms(200);
  136. bt_keys_storage_set_default_path(seos_native_peripheral->bt);
  137. furi_check(bt_profile_restore_default(seos_native_peripheral->bt));
  138. furi_thread_flags_set(furi_thread_get_id(seos_native_peripheral->thread), WorkerEvtStop);
  139. furi_thread_join(seos_native_peripheral->thread);
  140. }
  141. void seos_native_peripheral_process_message_cred(
  142. SeosNativePeripheral* seos_native_peripheral,
  143. NativePeripheralMessage message) {
  144. Seos* seos = seos_native_peripheral->seos;
  145. BitBuffer* response = bit_buffer_alloc(128); // TODO: MTU
  146. uint8_t* data = message.buf;
  147. if(data[0] != BLE_START && data[0] != 0xe1) {
  148. FURI_LOG_W(TAG, "Unexpected start of BLE packet");
  149. }
  150. const uint8_t* apdu = data + 1; // Match name to nfc version for easier copying
  151. if(memcmp(apdu, select_header, sizeof(select_header)) == 0) {
  152. if(memcmp(apdu + sizeof(select_header) + 1, standard_seos_aid, sizeof(standard_seos_aid)) ==
  153. 0) {
  154. seos_emulator_select_aid(response);
  155. bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
  156. } else {
  157. bit_buffer_append_bytes(response, (uint8_t*)file_not_found, sizeof(file_not_found));
  158. }
  159. } else if(memcmp(apdu, select_adf_header, sizeof(select_adf_header)) == 0) {
  160. // +1 to skip APDU length byte
  161. const uint8_t* oid_list = apdu + sizeof(select_adf_header) + 1;
  162. size_t oid_list_len = apdu[sizeof(select_adf_header)];
  163. if(seos_emulator_select_adf(
  164. oid_list,
  165. oid_list_len,
  166. &seos_native_peripheral->params,
  167. seos_native_peripheral->credential,
  168. response)) {
  169. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventADFMatched);
  170. } else {
  171. FURI_LOG_W(TAG, "Failed to match any ADF OID");
  172. }
  173. } else if(memcmp(apdu, general_authenticate_1, sizeof(general_authenticate_1)) == 0) {
  174. seos_emulator_general_authenticate_1(response, seos_native_peripheral->params);
  175. bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
  176. } else if(memcmp(apdu, general_authenticate_2_header, sizeof(general_authenticate_2_header)) == 0) {
  177. if(!seos_emulator_general_authenticate_2(
  178. apdu,
  179. message.len - 1,
  180. seos_native_peripheral->credential,
  181. &seos_native_peripheral->params,
  182. response)) {
  183. FURI_LOG_W(TAG, "Failure in General Authenticate 2");
  184. } else {
  185. bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
  186. }
  187. view_dispatcher_send_custom_event(
  188. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventAuthenticated);
  189. // Prepare for future communication
  190. seos_native_peripheral->secure_messaging =
  191. secure_messaging_alloc(&seos_native_peripheral->params);
  192. } else if(memcmp(apdu, secure_messaging_header, sizeof(secure_messaging_header)) == 0) {
  193. uint8_t request_sio[] = {0x5c, 0x02, 0xff, 0x00};
  194. if(seos_native_peripheral->secure_messaging) {
  195. FURI_LOG_D(TAG, "Unwrap secure message");
  196. // c0 0ccb3fff 16 8508fa8395d30de4e8e097008e085da7edbd833b002d00
  197. // Ignore 1 BLE_START byte
  198. size_t bytes_to_ignore = 1;
  199. BitBuffer* tmp = bit_buffer_alloc(message.len);
  200. bit_buffer_append_bytes(
  201. tmp, message.buf + bytes_to_ignore, message.len - bytes_to_ignore);
  202. seos_log_bitbuffer(TAG, "received(wrapped)", tmp);
  203. secure_messaging_unwrap_apdu(seos_native_peripheral->secure_messaging, tmp);
  204. seos_log_bitbuffer(TAG, "received(clear)", tmp);
  205. const uint8_t* message = bit_buffer_get_data(tmp);
  206. if(memcmp(message, request_sio, sizeof(request_sio)) == 0) {
  207. view_dispatcher_send_custom_event(
  208. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventSIORequested);
  209. BitBuffer* sio_file = bit_buffer_alloc(128);
  210. bit_buffer_append_bytes(sio_file, message + 2, 2); // fileId
  211. bit_buffer_append_byte(sio_file, seos_native_peripheral->credential->sio_len);
  212. bit_buffer_append_bytes(
  213. sio_file,
  214. seos_native_peripheral->credential->sio,
  215. seos_native_peripheral->credential->sio_len);
  216. secure_messaging_wrap_rapdu(
  217. seos_native_peripheral->secure_messaging,
  218. (uint8_t*)bit_buffer_get_data(sio_file),
  219. bit_buffer_get_size_bytes(sio_file),
  220. response);
  221. bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
  222. bit_buffer_free(sio_file);
  223. }
  224. bit_buffer_free(tmp);
  225. } else {
  226. uint8_t no_sm[] = {0x69, 0x88};
  227. bit_buffer_append_bytes(response, no_sm, sizeof(no_sm));
  228. }
  229. } else if(data[0] == 0xe1) {
  230. // ignore
  231. } else {
  232. FURI_LOG_W(TAG, "no match for message");
  233. }
  234. if(bit_buffer_get_size_bytes(response) > 0) {
  235. BitBuffer* tx = bit_buffer_alloc(1 + 2 + 1 + bit_buffer_get_size_bytes(response));
  236. bit_buffer_append_byte(tx, BLE_START);
  237. bit_buffer_append_bytes(
  238. tx, bit_buffer_get_data(response), bit_buffer_get_size_bytes(response));
  239. ble_profile_seos_tx(
  240. seos_native_peripheral->ble_profile,
  241. (uint8_t*)bit_buffer_get_data(tx),
  242. bit_buffer_get_size_bytes(tx));
  243. bit_buffer_free(tx);
  244. }
  245. bit_buffer_free(response);
  246. }
  247. void seos_native_peripheral_process_message_reader(
  248. SeosNativePeripheral* seos_native_peripheral,
  249. NativePeripheralMessage message) {
  250. BitBuffer* response = bit_buffer_alloc(128); // TODO: MTU
  251. uint8_t* data = message.buf;
  252. uint8_t* rx_data = data + 1; // Match name to nfc version for easier copying
  253. if(data[0] != BLE_START && data[0] != 0xe1) {
  254. FURI_LOG_W(TAG, "Unexpected start of BLE packet");
  255. }
  256. if(memcmp(data + 5, standard_seos_aid, sizeof(standard_seos_aid)) == 0) { // response to select
  257. FURI_LOG_I(TAG, "Select ADF");
  258. uint8_t select_adf_header[] = {
  259. 0x80, 0xa5, 0x04, 0x00, (uint8_t)SEOS_ADF_OID_LEN + 2, 0x06, (uint8_t)SEOS_ADF_OID_LEN};
  260. bit_buffer_append_bytes(response, select_adf_header, sizeof(select_adf_header));
  261. bit_buffer_append_bytes(response, SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  262. seos_native_peripheral->phase = SELECT_ADF;
  263. } else if(memcmp(data + 1, cd02, sizeof(cd02)) == 0) {
  264. BitBuffer* attribute_value = bit_buffer_alloc(message.len);
  265. bit_buffer_append_bytes(attribute_value, message.buf, message.len);
  266. if(seos_reader_select_adf_response(
  267. attribute_value,
  268. 1,
  269. seos_native_peripheral->credential,
  270. &seos_native_peripheral->params)) {
  271. // Craft response
  272. general_authenticate_1[3] = seos_native_peripheral->params.key_no;
  273. bit_buffer_append_bytes(
  274. response, general_authenticate_1, sizeof(general_authenticate_1));
  275. seos_native_peripheral->phase = GENERAL_AUTHENTICATION_1;
  276. }
  277. bit_buffer_free(attribute_value);
  278. } else if(memcmp(data + 1, ga1_response, sizeof(ga1_response)) == 0) {
  279. memcpy(seos_native_peripheral->params.rndICC, data + 5, 8);
  280. // Craft response
  281. uint8_t cryptogram[32 + 8];
  282. memset(cryptogram, 0, sizeof(cryptogram));
  283. seos_reader_generate_cryptogram(
  284. seos_native_peripheral->credential, &seos_native_peripheral->params, cryptogram);
  285. uint8_t ga_header[] = {
  286. 0x00,
  287. 0x87,
  288. 0x00,
  289. seos_native_peripheral->params.key_no,
  290. sizeof(cryptogram) + 4,
  291. 0x7c,
  292. sizeof(cryptogram) + 2,
  293. 0x82,
  294. sizeof(cryptogram)};
  295. bit_buffer_append_bytes(response, ga_header, sizeof(ga_header));
  296. bit_buffer_append_bytes(response, cryptogram, sizeof(cryptogram));
  297. seos_native_peripheral->phase = GENERAL_AUTHENTICATION_2;
  298. } else if(rx_data[0] == 0x7C && rx_data[2] == 0x82) { // ga2 response
  299. if(rx_data[3] == 40) {
  300. if(!seos_reader_verify_cryptogram(&seos_native_peripheral->params, rx_data + 4)) {
  301. FURI_LOG_W(TAG, "Card cryptogram failed verification");
  302. bit_buffer_free(response);
  303. return;
  304. }
  305. FURI_LOG_I(TAG, "Authenticated");
  306. view_dispatcher_send_custom_event(
  307. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventAuthenticated);
  308. } else {
  309. FURI_LOG_W(TAG, "Unhandled card cryptogram size %d", rx_data[3]);
  310. }
  311. seos_native_peripheral->secure_messaging =
  312. secure_messaging_alloc(&seos_native_peripheral->params);
  313. SecureMessaging* secure_messaging = seos_native_peripheral->secure_messaging;
  314. uint8_t message[] = {0x5c, 0x02, 0xff, 0x00};
  315. secure_messaging_wrap_apdu(secure_messaging, message, sizeof(message), response);
  316. seos_native_peripheral->phase = REQUEST_SIO;
  317. view_dispatcher_send_custom_event(
  318. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventSIORequested);
  319. } else if(seos_native_peripheral->phase == REQUEST_SIO) {
  320. // TODO: consider seos_reader_request_sio
  321. SecureMessaging* secure_messaging = seos_native_peripheral->secure_messaging;
  322. SeosCredential* credential = seos_native_peripheral->credential;
  323. AuthParameters* params = &seos_native_peripheral->params;
  324. BitBuffer* rx_buffer = bit_buffer_alloc(message.len - 1);
  325. bit_buffer_append_bytes(rx_buffer, rx_data, message.len - 1);
  326. seos_log_bitbuffer(TAG, "BLE response(wrapped)", rx_buffer);
  327. secure_messaging_unwrap_rapdu(secure_messaging, rx_buffer);
  328. seos_log_bitbuffer(TAG, "BLE response(clear)", rx_buffer);
  329. // Skip fileId
  330. credential->sio_len = bit_buffer_get_byte(rx_buffer, 2);
  331. if(credential->sio_len > sizeof(credential->sio)) {
  332. FURI_LOG_W(TAG, "SIO too long to save");
  333. bit_buffer_free(response);
  334. return;
  335. }
  336. memcpy(credential->sio, bit_buffer_get_data(rx_buffer) + 3, credential->sio_len);
  337. memcpy(credential->priv_key, params->priv_key, sizeof(credential->priv_key));
  338. memcpy(credential->auth_key, params->auth_key, sizeof(credential->auth_key));
  339. credential->adf_oid_len = SEOS_ADF_OID_LEN;
  340. memcpy(credential->adf_oid, SEOS_ADF_OID, sizeof(credential->adf_oid));
  341. FURI_LOG_I(TAG, "SIO Captured, %d bytes", credential->sio_len);
  342. Seos* seos = seos_native_peripheral->seos;
  343. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventReaderSuccess);
  344. bit_buffer_free(rx_buffer);
  345. seos_native_peripheral->phase = SELECT_AID;
  346. } else if(data[0] == 0xe1) {
  347. //ignore
  348. } else {
  349. FURI_LOG_W(TAG, "No match for write request");
  350. seos_log_buffer(TAG, "No match for reader incoming", message.buf, message.len);
  351. }
  352. if(bit_buffer_get_size_bytes(response) > 0) {
  353. BitBuffer* tx = bit_buffer_alloc(1 + 2 + 1 + bit_buffer_get_size_bytes(response));
  354. bit_buffer_append_byte(tx, BLE_START);
  355. bit_buffer_append_bytes(
  356. tx, bit_buffer_get_data(response), bit_buffer_get_size_bytes(response));
  357. ble_profile_seos_tx(
  358. seos_native_peripheral->ble_profile,
  359. (uint8_t*)bit_buffer_get_data(tx),
  360. bit_buffer_get_size_bytes(tx));
  361. bit_buffer_free(tx);
  362. }
  363. bit_buffer_free(response);
  364. }
  365. int32_t seos_native_peripheral_task(void* context) {
  366. SeosNativePeripheral* seos_native_peripheral = (SeosNativePeripheral*)context;
  367. bool running = true;
  368. while(running) {
  369. uint32_t events = furi_thread_flags_get();
  370. if(events & WorkerEvtStop) {
  371. running = false;
  372. break;
  373. }
  374. if(furi_mutex_acquire(seos_native_peripheral->mq_mutex, 1) == FuriStatusOk) {
  375. uint32_t count = furi_message_queue_get_count(seos_native_peripheral->messages);
  376. if(count > 0) {
  377. if(count > MESSAGE_QUEUE_SIZE / 2) {
  378. FURI_LOG_I(TAG, "Dequeue message [%ld messages]", count);
  379. }
  380. NativePeripheralMessage message = {};
  381. FuriStatus status = furi_message_queue_get(
  382. seos_native_peripheral->messages, &message, FuriWaitForever);
  383. if(status != FuriStatusOk) {
  384. FURI_LOG_W(TAG, "furi_message_queue_get fail %d", status);
  385. }
  386. if(seos_native_peripheral->flow_mode == FLOW_READER) {
  387. seos_native_peripheral_process_message_reader(seos_native_peripheral, message);
  388. } else if(seos_native_peripheral->flow_mode == FLOW_CRED) {
  389. seos_native_peripheral_process_message_cred(seos_native_peripheral, message);
  390. }
  391. }
  392. furi_mutex_release(seos_native_peripheral->mq_mutex);
  393. } else {
  394. FURI_LOG_W(TAG, "Failed to acquire mutex");
  395. }
  396. // A beat for event flags
  397. furi_delay_ms(1);
  398. }
  399. return 0;
  400. }