From 89fab427c4e1a3de0c8a54eb003d4f27d57c2e37 Mon Sep 17 00:00:00 2001 From: zvecr Date: Mon, 11 Apr 2022 00:43:18 +0100 Subject: [PATCH] stub out secure as its own feature --- builddefs/common_features.mk | 1 + builddefs/generic_features.mk | 1 + data/xap/xap_0.1.0.hjson | 16 +++++- lib/python/qmk/cli/xap/xap.py | 15 +++++- quantum/keyboard.c | 8 +++ quantum/process_keycode/process_secure.c | 18 +++++++ quantum/process_keycode/process_secure.h | 9 ++++ quantum/quantum.c | 3 ++ quantum/quantum.h | 5 ++ quantum/secure.c | 66 ++++++++++++++++++++++++ quantum/secure.h | 27 ++++++++++ quantum/xap/xap.c | 22 ++++++-- quantum/xap/xap.h | 2 + quantum/xap/xap_handlers.c | 16 ++++++ 14 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 quantum/process_keycode/process_secure.c create mode 100644 quantum/process_keycode/process_secure.h create mode 100644 quantum/secure.c create mode 100644 quantum/secure.h diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 77d5aa25e3..52bf40228a 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -802,6 +802,7 @@ ifeq ($(strip $(XAP_ENABLE)), yes) OPT_DEFS += -DXAP_ENABLE DYNAMIC_KEYMAP_ENABLE := yes + SECURE_ENABLE := yes EMBED_INFO_JSON := yes VPATH += $(QUANTUM_DIR)/xap SRC += $(QUANTUM_DIR)/xap/xap.c $(QUANTUM_DIR)/xap/xap_handlers.c diff --git a/builddefs/generic_features.mk b/builddefs/generic_features.mk index 53d4e16fd4..0475a2ff09 100644 --- a/builddefs/generic_features.mk +++ b/builddefs/generic_features.mk @@ -32,6 +32,7 @@ GENERIC_FEATURES = \ KEY_OVERRIDE \ LEADER \ PROGRAMMABLE_BUTTON \ + SECURE \ SPACE_CADET \ SWAP_HANDS \ TAP_DANCE \ diff --git a/data/xap/xap_0.1.0.hjson b/data/xap/xap_0.1.0.hjson index e9506b5c7b..3d094eb375 100755 --- a/data/xap/xap_0.1.0.hjson +++ b/data/xap/xap_0.1.0.hjson @@ -172,7 +172,21 @@ * any other value should be interpreted as disabled ''' return_type: u8 - return_value: secure_status + return_execute: secure_status + } + 0x04: { + type: command + name: Secure Unlock + define: SECURE_UNLOCK + description: Initiate secure route unlock sequence + return_execute: secure_unlock + } + 0x05: { + type: command + name: Secure Lock + define: SECURE_LOCK + description: Disable secure routes + return_execute: secure_lock } } }, diff --git a/lib/python/qmk/cli/xap/xap.py b/lib/python/qmk/cli/xap/xap.py index e61f7fe48b..36979bf47c 100644 --- a/lib/python/qmk/cli/xap/xap.py +++ b/lib/python/qmk/cli/xap/xap.py @@ -185,9 +185,14 @@ def xap_broadcast_listen(device): cli.log.info("Stopping...") +def xap_unlock(device): + _xap_transaction(device, 0x00, 0x04) + + @cli.argument('-d', '--device', help='device to select - uses format :.') @cli.argument('-i', '--index', default=0, help='device index to select.') @cli.argument('-l', '--list', arg_only=True, action='store_true', help='List available devices.') +@cli.argument('action', nargs='?', arg_only=True) @cli.subcommand('Acquire debugging information from usb XAP devices.', hidden=False if cli.config.user.developer else True) def xap(cli): """Acquire debugging information from XAP devices @@ -210,4 +215,12 @@ def xap(cli): cli.log.info("Connected to:%04x:%04x %s %s", dev['vendor_id'], dev['product_id'], dev['manufacturer_string'], dev['product_string']) # xap_doit(device) - xap_broadcast_listen(device) + if cli.args.action == 'unlock': + xap_unlock(device) + cli.log.info("Done") + + elif cli.args.action == 'listen': + xap_broadcast_listen(device) + + elif not cli.args.action: + xap_broadcast_listen(device) \ No newline at end of file diff --git a/quantum/keyboard.c b/quantum/keyboard.c index fc8a2fe8e3..5a80330b55 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c @@ -562,6 +562,14 @@ void quantum_task(void) { #ifdef AUTO_SHIFT_ENABLE autoshift_matrix_scan(); #endif + +#ifdef SECURE_ENABLE + secure_task(); +#endif + +#ifdef XAP_ENABLE + xap_event_task(); +#endif } /** \brief Keyboard task: Do keyboard routine jobs diff --git a/quantum/process_keycode/process_secure.c b/quantum/process_keycode/process_secure.c new file mode 100644 index 0000000000..af06906344 --- /dev/null +++ b/quantum/process_keycode/process_secure.c @@ -0,0 +1,18 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "secure.h" +#include "process_secure.h" + +bool process_secure(uint16_t keycode, keyrecord_t *record) { + if (secure_is_unlocking()) { + if (!record->event.pressed) { + secure_keypress_event(record->event.key.row, record->event.key.col); + } + + // Normal keypresses should be disabled until the sequence is completed + return false; + } + + return true; +} diff --git a/quantum/process_keycode/process_secure.h b/quantum/process_keycode/process_secure.h new file mode 100644 index 0000000000..7f6821f0d8 --- /dev/null +++ b/quantum/process_keycode/process_secure.h @@ -0,0 +1,9 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "action.h" + +bool process_secure(uint16_t keycode, keyrecord_t *record); diff --git a/quantum/quantum.c b/quantum/quantum.c index d4e91ddd37..eedc004a30 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -245,6 +245,9 @@ bool process_record_quantum(keyrecord_t *record) { #endif #if defined(VIA_ENABLE) process_record_via(keycode, record) && +#endif +#if defined(SECURE_ENABLE) + process_secure(keycode, record) && #endif process_record_kb(keycode, record) && #if defined(SEQUENCER_ENABLE) diff --git a/quantum/quantum.h b/quantum/quantum.h index ff3679bb5e..122e886ad2 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -196,6 +196,11 @@ extern layer_state_t layer_state; # include "process_dynamic_macro.h" #endif +#ifdef SECURE_ENABLE +# include "secure.h" +# include "process_secure.h" +#endif + #ifdef DYNAMIC_KEYMAP_ENABLE # include "dynamic_keymap.h" #endif diff --git a/quantum/secure.c b/quantum/secure.c new file mode 100644 index 0000000000..26a3246ccf --- /dev/null +++ b/quantum/secure.c @@ -0,0 +1,66 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "secure.h" +#include "timer.h" + +#ifndef SECURE_UNLOCK_TIMEOUT +# define SECURE_UNLOCK_TIMEOUT 5000 +#endif + +#ifndef SECURE_IDLE_TIMEOUT +# define SECURE_IDLE_TIMEOUT 60000 +#endif + +secure_status_t secure_status = SECURE_LOCKED; +static uint32_t unlock_time = 0; +static uint32_t idle_time = 0; + +secure_status_t secure_get_status(void) { + return secure_status; +} + +bool secure_is_unlocking(void) { + return secure_status == SECURE_PENDING; +} + +void secure_lock(void) { + secure_status = SECURE_LOCKED; +} + +void secure_unlock(void) { + secure_status = SECURE_UNLOCKED; + idle_time = timer_read32(); +} + +void secure_request_unlock(void) { + if (secure_status == SECURE_LOCKED) { + secure_status = SECURE_PENDING; + unlock_time = timer_read32(); + } +} + +void secure_keypress_event(uint8_t row, uint8_t col) { + // TODO: check keypress is actually part of unlock sequence + secure_unlock(); +} + +void secure_task(void) { +#if SECURE_UNLOCK_TIMEOUT != 0 + // handle unlock timeout + if (secure_status == SECURE_PENDING) { + if (timer_elapsed32(unlock_time) >= SECURE_UNLOCK_TIMEOUT) { + secure_lock(); + } + } +#endif + +#if SECURE_IDLE_TIMEOUT != 0 + // handle idle timeout + if (secure_status == SECURE_UNLOCKED) { + if (timer_elapsed32(idle_time) >= SECURE_IDLE_TIMEOUT) { + secure_lock(); + } + } +#endif +} diff --git a/quantum/secure.h b/quantum/secure.h new file mode 100644 index 0000000000..ba5fd6cbff --- /dev/null +++ b/quantum/secure.h @@ -0,0 +1,27 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +typedef enum { + SECURE_LOCKED, + SECURE_PENDING, + SECURE_UNLOCKED, +} secure_status_t; + +secure_status_t secure_get_status(void); + +bool secure_is_unlocking(void); + +void secure_lock(void); + +void secure_unlock(void); + +void secure_request_unlock(void); + +void secure_keypress_event(uint8_t row, uint8_t col); + +void secure_task(void); diff --git a/quantum/xap/xap.c b/quantum/xap/xap.c index 00901b0423..806ce7f160 100644 --- a/quantum/xap/xap.c +++ b/quantum/xap/xap.c @@ -16,6 +16,7 @@ #include #include +#include "secure.h" #include "info_json_gz.h" bool get_info_json_chunk(uint16_t offset, uint8_t *data, uint8_t data_len) { @@ -27,8 +28,6 @@ bool get_info_json_chunk(uint16_t offset, uint8_t *data, uint8_t data_len) { return true; } -uint8_t secure_status = 2; - #define QSTR2(z) #z #define QSTR(z) QSTR2(z) @@ -86,11 +85,18 @@ void xap_execute_route(xap_token_t token, const xap_route_t *routes, size_t max_ xap_route_t route; memcpy_P(&route, &routes[id], sizeof(xap_route_t)); - if (route.flags.is_secure && secure_status != 2) { + if (route.flags.is_secure && secure_get_status() != SECURE_UNLOCKED) { xap_respond_failure(token, XAP_RESPONSE_FLAG_SECURE_FAILURE); return; } + // TODO: All other subsystems are disabled during unlock. + // how to flag status route as still allowed? + // if (!route.flags.is_secure && secure_get_status() == SECURE_PENDING) { + // xap_respond_failure(token, XAP_RESPONSE_FLAG_UNLOCK_IN_PROGRESS); + // return; + // } + switch (route.flags.type) { case XAP_ROUTE: if (route.child_routes != NULL && route.child_routes_len > 0 && data_len > 0) { @@ -134,3 +140,13 @@ void xap_execute_route(xap_token_t token, const xap_route_t *routes, size_t max_ void xap_receive(xap_token_t token, const uint8_t *data, size_t length) { xap_execute_route(token, xap_route_table, sizeof(xap_route_table) / sizeof(xap_route_t), data, length); } + +void xap_event_task(void) { + static secure_status_t last_status = -1; + + secure_status_t status = secure_get_status(); + if (last_status != status) { + last_status = status; + xap_broadcast_secure_status(status); + } +} diff --git a/quantum/xap/xap.h b/quantum/xap/xap.h index 76e5095492..b1ecd8cb9c 100644 --- a/quantum/xap/xap.h +++ b/quantum/xap/xap.h @@ -36,3 +36,5 @@ bool xap_respond_data_P(xap_token_t token, const void *data, size_t length); void xap_send(xap_token_t token, xap_response_flags_t response_flags, const void *data, size_t length); void xap_broadcast(uint8_t type, const void *data, size_t length); + +void xap_event_task(void); diff --git a/quantum/xap/xap_handlers.c b/quantum/xap/xap_handlers.c index 70cd2fb272..e16a586dbb 100644 --- a/quantum/xap/xap_handlers.c +++ b/quantum/xap/xap_handlers.c @@ -16,6 +16,7 @@ #include #include +#include "secure.h" void xap_respond_success(xap_token_t token) { xap_send(token, XAP_RESPONSE_FLAG_SUCCESS, NULL, 0); @@ -59,6 +60,21 @@ bool xap_respond_get_info_json_chunk(xap_token_t token, const void *data, size_t return xap_respond_data(token, &ret, sizeof(ret)); } +bool xap_respond_secure_status(xap_token_t token, const void *data, size_t length) { + uint8_t ret = secure_get_status(); + return xap_respond_data(token, &ret, sizeof(ret)); +} + +bool xap_respond_secure_unlock(xap_token_t token, const void *data, size_t length) { + secure_request_unlock(); + return xap_respond_data(token, NULL, 0); +} + +bool xap_respond_secure_lock(xap_token_t token, const void *data, size_t length) { + secure_lock(); + return xap_respond_data(token, NULL, 0); +} + // TODO: how to set this if "custom" is just an empty stub #ifndef BOOTLOADER_JUMP_SUPPORTED # define BOOTLOADER_JUMP_SUPPORTED