seos_native_peripheral.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. int32_t seos_native_peripheral_task(void* context);
  10. typedef struct {
  11. size_t len;
  12. uint8_t buf[BLE_SVC_SEOS_CHAR_VALUE_LEN_MAX];
  13. } NativePeripheralMessage;
  14. static void seos_ble_connection_status_callback(BtStatus status, void* context) {
  15. furi_assert(context);
  16. SeosNativePeripheral* seos_native_peripheral = context;
  17. if(status == BtStatusConnected) {
  18. view_dispatcher_send_custom_event(
  19. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventConnected);
  20. } else if(status == BtStatusAdvertising) {
  21. view_dispatcher_send_custom_event(
  22. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventAdvertising);
  23. }
  24. }
  25. static uint16_t seos_svc_callback(SeosServiceEvent event, void* context) {
  26. SeosNativePeripheral* seos_native_peripheral = context;
  27. uint16_t bytes_available = 0;
  28. if(event.event == SeosServiceEventTypeDataReceived) {
  29. uint32_t space = furi_message_queue_get_space(seos_native_peripheral->messages);
  30. if(space > 0) {
  31. NativePeripheralMessage message = {.len = event.data.size};
  32. memcpy(message.buf, event.data.buffer, event.data.size);
  33. if(furi_mutex_acquire(seos_native_peripheral->mq_mutex, FuriWaitForever) ==
  34. FuriStatusOk) {
  35. furi_message_queue_put(
  36. seos_native_peripheral->messages, &message, FuriWaitForever);
  37. furi_mutex_release(seos_native_peripheral->mq_mutex);
  38. }
  39. if(space < MESSAGE_QUEUE_SIZE / 2) {
  40. FURI_LOG_D(TAG, "Queue message. %ld remaining", space);
  41. }
  42. bytes_available = (space - 1) * sizeof(NativePeripheralMessage);
  43. } else {
  44. FURI_LOG_E(TAG, "No space in message queue");
  45. }
  46. }
  47. return bytes_available;
  48. }
  49. SeosNativePeripheral* seos_native_peripheral_alloc(Seos* seos) {
  50. SeosNativePeripheral* seos_native_peripheral = malloc(sizeof(SeosNativePeripheral));
  51. memset(seos_native_peripheral, 0, sizeof(SeosNativePeripheral));
  52. seos_native_peripheral->seos = seos;
  53. seos_native_peripheral->credential = &seos->credential;
  54. seos_native_peripheral->bt = furi_record_open(RECORD_BT);
  55. seos_native_peripheral->phase = SELECT_AID;
  56. seos_native_peripheral->secure_messaging = NULL;
  57. seos_native_peripheral->params.key_no = 1;
  58. memset(
  59. seos_native_peripheral->params.cNonce,
  60. 0x0c,
  61. sizeof(seos_native_peripheral->params.cNonce));
  62. memset(seos_native_peripheral->params.UID, 0x0d, sizeof(seos_native_peripheral->params.UID));
  63. seos_native_peripheral->thread = furi_thread_alloc_ex(
  64. "SeosNativePeripheralWorker",
  65. 5 * 1024,
  66. seos_native_peripheral_task,
  67. seos_native_peripheral);
  68. seos_native_peripheral->messages =
  69. furi_message_queue_alloc(MESSAGE_QUEUE_SIZE, sizeof(NativePeripheralMessage));
  70. seos_native_peripheral->mq_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  71. return seos_native_peripheral;
  72. }
  73. void seos_native_peripheral_free(SeosNativePeripheral* seos_native_peripheral) {
  74. furi_assert(seos_native_peripheral);
  75. furi_record_close(RECORD_BT);
  76. furi_message_queue_free(seos_native_peripheral->messages);
  77. furi_mutex_free(seos_native_peripheral->mq_mutex);
  78. furi_thread_free(seos_native_peripheral->thread);
  79. free(seos_native_peripheral);
  80. }
  81. void seos_native_peripheral_start(SeosNativePeripheral* seos_native_peripheral, FlowMode mode) {
  82. UNUSED(mode);
  83. bt_disconnect(seos_native_peripheral->bt);
  84. BleProfileParams params = {
  85. .mode = mode,
  86. };
  87. // Wait 2nd core to update nvm storage
  88. furi_delay_ms(200);
  89. seos_native_peripheral->ble_profile =
  90. bt_profile_start(seos_native_peripheral->bt, ble_profile_seos, &params);
  91. furi_check(seos_native_peripheral->ble_profile);
  92. bt_set_status_changed_callback(
  93. seos_native_peripheral->bt, seos_ble_connection_status_callback, seos_native_peripheral);
  94. ble_profile_seos_set_event_callback(
  95. seos_native_peripheral->ble_profile,
  96. sizeof(seos_native_peripheral->event_buffer),
  97. seos_svc_callback,
  98. seos_native_peripheral);
  99. furi_hal_bt_start_advertising();
  100. view_dispatcher_send_custom_event(
  101. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventAdvertising);
  102. furi_thread_start(seos_native_peripheral->thread);
  103. }
  104. void seos_native_peripheral_stop(SeosNativePeripheral* seos_native_peripheral) {
  105. furi_hal_bt_stop_advertising();
  106. bt_set_status_changed_callback(seos_native_peripheral->bt, NULL, NULL);
  107. bt_disconnect(seos_native_peripheral->bt);
  108. // Wait 2nd core to update nvm storage
  109. furi_delay_ms(200);
  110. bt_keys_storage_set_default_path(seos_native_peripheral->bt);
  111. furi_check(bt_profile_restore_default(seos_native_peripheral->bt));
  112. furi_thread_flags_set(furi_thread_get_id(seos_native_peripheral->thread), WorkerEvtStop);
  113. furi_thread_join(seos_native_peripheral->thread);
  114. }
  115. void seos_native_peripheral_process_message(
  116. SeosNativePeripheral* seos_native_peripheral,
  117. NativePeripheralMessage message) {
  118. BitBuffer* response = bit_buffer_alloc(128); // TODO: MTU
  119. uint8_t* data = message.buf;
  120. uint8_t* rx_data = data + 1; // Match name to nfc version for easier copying
  121. if(data[0] != BLE_START && data[0] != 0xe1) {
  122. FURI_LOG_W(TAG, "Unexpected start of BLE packet");
  123. }
  124. if(memcmp(data + 5, standard_seos_aid, sizeof(standard_seos_aid)) == 0) { // response to select
  125. FURI_LOG_I(TAG, "Select ADF");
  126. uint8_t select_adf_header[] = {
  127. 0x80, 0xa5, 0x04, 0x00, (uint8_t)SEOS_ADF_OID_LEN + 2, 0x06, (uint8_t)SEOS_ADF_OID_LEN};
  128. bit_buffer_append_bytes(response, select_adf_header, sizeof(select_adf_header));
  129. bit_buffer_append_bytes(response, SEOS_ADF_OID, SEOS_ADF_OID_LEN);
  130. seos_native_peripheral->phase = SELECT_ADF;
  131. } else if(memcmp(data + 1, cd02, sizeof(cd02)) == 0) {
  132. BitBuffer* attribute_value = bit_buffer_alloc(message.len);
  133. bit_buffer_append_bytes(attribute_value, message.buf, message.len);
  134. if(seos_reader_select_adf_response(
  135. attribute_value,
  136. 1,
  137. seos_native_peripheral->credential,
  138. &seos_native_peripheral->params)) {
  139. // Craft response
  140. general_authenticate_1[3] = seos_native_peripheral->params.key_no;
  141. bit_buffer_append_bytes(
  142. response, general_authenticate_1, sizeof(general_authenticate_1));
  143. seos_native_peripheral->phase = GENERAL_AUTHENTICATION_1;
  144. }
  145. bit_buffer_free(attribute_value);
  146. } else if(memcmp(data + 1, ga1_response, sizeof(ga1_response)) == 0) {
  147. memcpy(seos_native_peripheral->params.rndICC, data + 5, 8);
  148. // Craft response
  149. uint8_t cryptogram[32 + 8];
  150. memset(cryptogram, 0, sizeof(cryptogram));
  151. seos_reader_generate_cryptogram(
  152. seos_native_peripheral->credential, &seos_native_peripheral->params, cryptogram);
  153. uint8_t ga_header[] = {
  154. 0x00,
  155. 0x87,
  156. 0x00,
  157. seos_native_peripheral->params.key_no,
  158. sizeof(cryptogram) + 4,
  159. 0x7c,
  160. sizeof(cryptogram) + 2,
  161. 0x82,
  162. sizeof(cryptogram)};
  163. bit_buffer_append_bytes(response, ga_header, sizeof(ga_header));
  164. bit_buffer_append_bytes(response, cryptogram, sizeof(cryptogram));
  165. seos_native_peripheral->phase = GENERAL_AUTHENTICATION_2;
  166. } else if(rx_data[0] == 0x7C && rx_data[2] == 0x82) { // ga2 response
  167. if(rx_data[3] == 40) {
  168. if(!seos_reader_verify_cryptogram(&seos_native_peripheral->params, rx_data + 4)) {
  169. FURI_LOG_W(TAG, "Card cryptogram failed verification");
  170. bit_buffer_free(response);
  171. return;
  172. }
  173. FURI_LOG_I(TAG, "Authenticated");
  174. view_dispatcher_send_custom_event(
  175. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventAuthenticated);
  176. } else {
  177. FURI_LOG_W(TAG, "Unhandled card cryptogram size %d", rx_data[3]);
  178. }
  179. seos_native_peripheral->secure_messaging =
  180. secure_messaging_alloc(&seos_native_peripheral->params);
  181. SecureMessaging* secure_messaging = seos_native_peripheral->secure_messaging;
  182. uint8_t message[] = {0x5c, 0x02, 0xff, 0x00};
  183. secure_messaging_wrap_apdu(secure_messaging, message, sizeof(message), response);
  184. seos_native_peripheral->phase = REQUEST_SIO;
  185. view_dispatcher_send_custom_event(
  186. seos_native_peripheral->seos->view_dispatcher, SeosCustomEventSIORequested);
  187. } else if(seos_native_peripheral->phase == REQUEST_SIO) {
  188. SecureMessaging* secure_messaging = seos_native_peripheral->secure_messaging;
  189. BitBuffer* rx_buffer = bit_buffer_alloc(message.len - 1);
  190. bit_buffer_append_bytes(rx_buffer, rx_data, message.len - 1);
  191. seos_log_bitbuffer(TAG, "BLE response(wrapped)", rx_buffer);
  192. secure_messaging_unwrap_rapdu(secure_messaging, rx_buffer);
  193. seos_log_bitbuffer(TAG, "BLE response(clear)", rx_buffer);
  194. // Skip fileId
  195. seos_native_peripheral->credential->sio_len = bit_buffer_get_byte(rx_buffer, 2);
  196. if(seos_native_peripheral->credential->sio_len >
  197. sizeof(seos_native_peripheral->credential->sio)) {
  198. FURI_LOG_W(TAG, "SIO too long to save");
  199. bit_buffer_free(response);
  200. return;
  201. }
  202. memcpy(
  203. seos_native_peripheral->credential->sio,
  204. bit_buffer_get_data(rx_buffer) + 3,
  205. seos_native_peripheral->credential->sio_len);
  206. FURI_LOG_I(TAG, "SIO Captured, %d bytes", seos_native_peripheral->credential->sio_len);
  207. Seos* seos = seos_native_peripheral->seos;
  208. view_dispatcher_send_custom_event(seos->view_dispatcher, SeosCustomEventReaderSuccess);
  209. bit_buffer_free(rx_buffer);
  210. seos_native_peripheral->phase = SELECT_AID;
  211. } else if(data[0] == 0xe1) {
  212. //ignore
  213. } else {
  214. FURI_LOG_W(TAG, "No match for write request");
  215. }
  216. if(bit_buffer_get_size_bytes(response) > 0) {
  217. BitBuffer* tx = bit_buffer_alloc(1 + 2 + 1 + bit_buffer_get_size_bytes(response));
  218. bit_buffer_append_byte(tx, BLE_START);
  219. bit_buffer_append_bytes(
  220. tx, bit_buffer_get_data(response), bit_buffer_get_size_bytes(response));
  221. ble_profile_seos_tx(
  222. seos_native_peripheral->ble_profile,
  223. (uint8_t*)bit_buffer_get_data(tx),
  224. bit_buffer_get_size_bytes(tx));
  225. bit_buffer_free(tx);
  226. }
  227. bit_buffer_free(response);
  228. }
  229. int32_t seos_native_peripheral_task(void* context) {
  230. SeosNativePeripheral* seos_native_peripheral = (SeosNativePeripheral*)context;
  231. bool running = true;
  232. while(running) {
  233. uint32_t events = furi_thread_flags_get();
  234. if(events & WorkerEvtStop) {
  235. running = false;
  236. break;
  237. }
  238. if(furi_mutex_acquire(seos_native_peripheral->mq_mutex, 1) == FuriStatusOk) {
  239. uint32_t count = furi_message_queue_get_count(seos_native_peripheral->messages);
  240. if(count > 0) {
  241. if(count > MESSAGE_QUEUE_SIZE / 2) {
  242. FURI_LOG_I(TAG, "Dequeue message [%ld messages]", count);
  243. }
  244. NativePeripheralMessage message = {};
  245. FuriStatus status = furi_message_queue_get(
  246. seos_native_peripheral->messages, &message, FuriWaitForever);
  247. if(status != FuriStatusOk) {
  248. FURI_LOG_W(TAG, "furi_message_queue_get fail %d", status);
  249. }
  250. seos_native_peripheral_process_message(seos_native_peripheral, message);
  251. }
  252. furi_mutex_release(seos_native_peripheral->mq_mutex);
  253. } else {
  254. FURI_LOG_W(TAG, "Failed to acquire mutex");
  255. }
  256. // A beat for event flags
  257. furi_delay_ms(1);
  258. }
  259. return 0;
  260. }