|
|
@@ -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 {
|