瀏覽代碼

Emulate credential over native peripheral

Eric Betts 10 月之前
父節點
當前提交
2944c272ea
共有 4 個文件被更改,包括 178 次插入15 次删除
  1. 0 2
      seos_characteristic.c
  2. 162 3
      seos_native_peripheral.c
  3. 1 0
      seos_native_peripheral.h
  4. 15 10
      seos_service.c

+ 0 - 2
seos_characteristic.c

@@ -184,8 +184,6 @@ void seos_characteristic_cred_flow(
     SeosCharacteristic* seos_characteristic,
     BitBuffer* attribute_value,
     BitBuffer* payload) {
-    UNUSED(seos_characteristic);
-
     const uint8_t* data = bit_buffer_get_data(attribute_value);
     const uint8_t* apdu = data + 1; // Match name to nfc version for easier copying
 

+ 162 - 3
seos_native_peripheral.c

@@ -10,6 +10,15 @@ static uint8_t general_authenticate_1[] =
     {0x00, 0x87, 0x00, 0x01, 0x04, 0x7c, 0x02, 0x81, 0x00, 0x00};
 static uint8_t ga1_response[] = {0x7c, 0x0a, 0x81, 0x08};
 
+// Emulation
+static uint8_t success[] = {0x90, 0x00};
+static uint8_t file_not_found[] = {0x6A, 0x82};
+
+static uint8_t select_header[] = {0x00, 0xa4, 0x04, 0x00};
+static uint8_t select_adf_header[] = {0x80, 0xa5, 0x04, 0x00};
+static uint8_t general_authenticate_2_header[] = {0x00, 0x87, 0x00, 0x01};
+static uint8_t secure_messaging_header[] = {0x0c, 0xcb, 0x3f, 0xff};
+
 int32_t seos_native_peripheral_task(void* context);
 
 typedef struct {
@@ -99,7 +108,28 @@ void seos_native_peripheral_free(SeosNativePeripheral* seos_native_peripheral) {
 }
 
 void seos_native_peripheral_start(SeosNativePeripheral* seos_native_peripheral, FlowMode mode) {
-    UNUSED(mode);
+    seos_native_peripheral->flow_mode = mode;
+    if(seos_native_peripheral->flow_mode == FLOW_CRED) {
+        seos_native_peripheral->params.key_no = 0;
+        seos_native_peripheral->params.cipher = TWO_KEY_3DES_CBC_MODE;
+        seos_native_peripheral->params.hash = SHA1;
+
+        memset(
+            seos_native_peripheral->params.rndICC,
+            0x0d,
+            sizeof(seos_native_peripheral->params.rndICC));
+        memset(
+            seos_native_peripheral->params.rNonce,
+            0x0c,
+            sizeof(seos_native_peripheral->params.rNonce));
+        memset(
+            seos_native_peripheral->params.UID, 0x00, sizeof(seos_native_peripheral->params.UID));
+        memset(
+            seos_native_peripheral->params.cNonce,
+            0x00,
+            sizeof(seos_native_peripheral->params.cNonce));
+    }
+
     bt_disconnect(seos_native_peripheral->bt);
 
     BleProfileParams params = {
@@ -140,7 +170,132 @@ void seos_native_peripheral_stop(SeosNativePeripheral* seos_native_peripheral) {
     furi_thread_join(seos_native_peripheral->thread);
 }
 
-void seos_native_peripheral_process_message(
+void seos_native_peripheral_process_message_cred(
+    SeosNativePeripheral* seos_native_peripheral,
+    NativePeripheralMessage message) {
+    BitBuffer* response = bit_buffer_alloc(128); // TODO: MTU
+
+    uint8_t* data = message.buf;
+    if(data[0] != BLE_START && data[0] != 0xe1) {
+        FURI_LOG_W(TAG, "Unexpected start of BLE packet");
+    }
+
+    const uint8_t* apdu = data + 1; // Match name to nfc version for easier copying
+
+    if(memcmp(apdu, select_header, sizeof(select_header)) == 0) {
+        if(memcmp(apdu + sizeof(select_header) + 1, standard_seos_aid, sizeof(standard_seos_aid)) ==
+           0) {
+            seos_emulator_select_aid(response);
+            bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
+        } else {
+            bit_buffer_append_bytes(response, (uint8_t*)file_not_found, sizeof(file_not_found));
+        }
+    } else if(memcmp(apdu, select_adf_header, sizeof(select_adf_header)) == 0) {
+        // is our adf in the list?
+        // +1 to skip APDU length byte
+        void* p = memmem(
+            apdu + sizeof(select_adf_header) + 1,
+            apdu[sizeof(select_adf_header)],
+            SEOS_ADF_OID,
+            SEOS_ADF_OID_LEN);
+        if(p) {
+            seos_log_buffer(TAG, "Matched ADF", p, SEOS_ADF_OID_LEN);
+
+            seos_emulator_select_adf(
+                &seos_native_peripheral->params, seos_native_peripheral->credential, response);
+            bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
+        } else {
+            FURI_LOG_W(TAG, "Failed to match any ADF OID");
+        }
+
+    } else if(memcmp(apdu, general_authenticate_1, sizeof(general_authenticate_1)) == 0) {
+        seos_emulator_general_authenticate_1(response, seos_native_peripheral->params);
+        bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
+    } else if(memcmp(apdu, general_authenticate_2_header, sizeof(general_authenticate_2_header)) == 0) {
+        if(!seos_emulator_general_authenticate_2(
+               apdu,
+               message.len - 1,
+               seos_native_peripheral->credential,
+               &seos_native_peripheral->params,
+               response)) {
+            FURI_LOG_W(TAG, "Failure in General Authenticate 2");
+        } else {
+            bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
+        }
+
+        view_dispatcher_send_custom_event(
+            seos_native_peripheral->seos->view_dispatcher, SeosCustomEventAuthenticated);
+        // Prepare for future communication
+        seos_native_peripheral->secure_messaging =
+            secure_messaging_alloc(&seos_native_peripheral->params);
+    } else if(memcmp(apdu, secure_messaging_header, sizeof(secure_messaging_header)) == 0) {
+        uint8_t request_sio[] = {0x5c, 0x02, 0xff, 0x00};
+
+        if(seos_native_peripheral->secure_messaging) {
+            FURI_LOG_D(TAG, "Unwrap secure message");
+
+            // c0 0ccb3fff 16 8508fa8395d30de4e8e097008e085da7edbd833b002d00
+            // Ignore 1 BLE_START byte
+            size_t bytes_to_ignore = 1;
+            BitBuffer* tmp = bit_buffer_alloc(message.len);
+            bit_buffer_append_bytes(
+                tmp, message.buf + bytes_to_ignore, message.len - bytes_to_ignore);
+
+            seos_log_bitbuffer(TAG, "received(wrapped)", tmp);
+            secure_messaging_unwrap_apdu(seos_native_peripheral->secure_messaging, tmp);
+            seos_log_bitbuffer(TAG, "received(clear)", tmp);
+
+            const uint8_t* message = bit_buffer_get_data(tmp);
+            if(memcmp(message, request_sio, sizeof(request_sio)) == 0) {
+                view_dispatcher_send_custom_event(
+                    seos_native_peripheral->seos->view_dispatcher, SeosCustomEventSIORequested);
+
+                BitBuffer* sio_file = bit_buffer_alloc(128);
+                bit_buffer_append_bytes(sio_file, message + 2, 2); // fileId
+                bit_buffer_append_byte(sio_file, seos_native_peripheral->credential->sio_len);
+                bit_buffer_append_bytes(
+                    sio_file,
+                    seos_native_peripheral->credential->sio,
+                    seos_native_peripheral->credential->sio_len);
+
+                secure_messaging_wrap_rapdu(
+                    seos_native_peripheral->secure_messaging,
+                    (uint8_t*)bit_buffer_get_data(sio_file),
+                    bit_buffer_get_size_bytes(sio_file),
+                    response);
+                bit_buffer_append_bytes(response, (uint8_t*)success, sizeof(success));
+
+                bit_buffer_free(sio_file);
+            }
+
+            bit_buffer_free(tmp);
+        } else {
+            uint8_t no_sm[] = {0x69, 0x88};
+            bit_buffer_append_bytes(response, no_sm, sizeof(no_sm));
+        }
+    } else if(data[0] == 0xe1) {
+        // ignore
+    } else {
+        FURI_LOG_W(TAG, "no match for message");
+    }
+
+    if(bit_buffer_get_size_bytes(response) > 0) {
+        BitBuffer* tx = bit_buffer_alloc(1 + 2 + 1 + bit_buffer_get_size_bytes(response));
+
+        bit_buffer_append_byte(tx, BLE_START);
+        bit_buffer_append_bytes(
+            tx, bit_buffer_get_data(response), bit_buffer_get_size_bytes(response));
+        ble_profile_seos_tx(
+            seos_native_peripheral->ble_profile,
+            (uint8_t*)bit_buffer_get_data(tx),
+            bit_buffer_get_size_bytes(tx));
+        bit_buffer_free(tx);
+    }
+
+    bit_buffer_free(response);
+}
+
+void seos_native_peripheral_process_message_reader(
     SeosNativePeripheral* seos_native_peripheral,
     NativePeripheralMessage message) {
     BitBuffer* response = bit_buffer_alloc(128); // TODO: MTU
@@ -300,7 +455,11 @@ int32_t seos_native_peripheral_task(void* context) {
                     FURI_LOG_W(TAG, "furi_message_queue_get fail %d", status);
                 }
 
-                seos_native_peripheral_process_message(seos_native_peripheral, message);
+                if(seos_native_peripheral->flow_mode == FLOW_READER) {
+                    seos_native_peripheral_process_message_reader(seos_native_peripheral, message);
+                } else if(seos_native_peripheral->flow_mode == FLOW_CRED) {
+                    seos_native_peripheral_process_message_cred(seos_native_peripheral, message);
+                }
             }
             furi_mutex_release(seos_native_peripheral->mq_mutex);
         } else {

+ 1 - 0
seos_native_peripheral.h

@@ -16,6 +16,7 @@ typedef struct {
     AuthParameters params;
     SecureMessaging* secure_messaging;
     SeosCredential* credential;
+    FlowMode flow_mode;
 
     FuriMessageQueue* messages;
     FuriMutex* mq_mutex;

+ 15 - 10
seos_service.c

@@ -62,6 +62,7 @@ struct BleServiceSeos {
     SeosServiceEventCallback callback;
     void* context;
     GapSvcEventHandler* event_handler;
+    FlowMode mode;
 };
 
 static BleEventAckStatus ble_svc_seos_event_handler(void* event, void* context) {
@@ -80,20 +81,23 @@ static BleEventAckStatus ble_svc_seos_event_handler(void* event, void* context)
                seos_svc->chars[SeosSvcGattCharacteristicRxTx].handle + 2) {
                 // Descriptor handle
                 ret = BleEventAckFlowEnable;
+                FURI_LOG_D(TAG, "Descriptor event %d bytes", attribute_modified->Attr_Data_Length);
+
                 if(attribute_modified->Attr_Data_Length == 2) {
                     uint16_t* value = (uint16_t*)attribute_modified->Attr_Data;
                     if(*value == 1) { // ENABLE_NOTIFICATION_VALUE)
-                        SeosSvcDataWrapper report_data = {
-                            .data_ptr = select, .data_len = sizeof(select)};
-
-                        ble_gatt_characteristic_update(
-                            seos_svc->svc_handle,
-                            &seos_svc->chars[SeosSvcGattCharacteristicRxTx],
-                            &report_data);
+                        if(seos_svc->mode == FLOW_READER) {
+                            SeosSvcDataWrapper report_data = {
+                                .data_ptr = select, .data_len = sizeof(select)};
+
+                            ble_gatt_characteristic_update(
+                                seos_svc->svc_handle,
+                                &seos_svc->chars[SeosSvcGattCharacteristicRxTx],
+                                &report_data);
+                        } else if(seos_svc->mode == FLOW_CRED) {
+                            FURI_LOG_D(TAG, "No action for FLOW_CRED after subscribe");
+                        }
                     }
-                } else {
-                    FURI_LOG_D(
-                        TAG, "descriptor event %d bytes", attribute_modified->Attr_Data_Length);
                 }
             } else if(
                 attribute_modified->Attr_Handle ==
@@ -141,6 +145,7 @@ static BleEventAckStatus ble_svc_seos_event_handler(void* event, void* context)
 
 BleServiceSeos* ble_svc_seos_start(FlowMode mode) {
     BleServiceSeos* seos_svc = malloc(sizeof(BleServiceSeos));
+    seos_svc->mode = mode;
 
     seos_svc->event_handler =
         ble_event_dispatcher_register_svc_handler(ble_svc_seos_event_handler, seos_svc);