Implement XAP 'secure' core requirements (#16843)
Co-authored-by: Drashna Jaelre <drashna@live.com> Co-authored-by: Stefan Kerkmann <karlk90@pm.me>
This commit is contained in:
		| @@ -32,6 +32,7 @@ GENERIC_FEATURES = \ | |||||||
|     KEY_OVERRIDE \ |     KEY_OVERRIDE \ | ||||||
|     LEADER \ |     LEADER \ | ||||||
|     PROGRAMMABLE_BUTTON \ |     PROGRAMMABLE_BUTTON \ | ||||||
|  |     SECURE \ | ||||||
|     SPACE_CADET \ |     SPACE_CADET \ | ||||||
|     SWAP_HANDS \ |     SWAP_HANDS \ | ||||||
|     TAP_DANCE \ |     TAP_DANCE \ | ||||||
|   | |||||||
| @@ -80,7 +80,8 @@ OTHER_OPTION_NAMES = \ | |||||||
|   LED_MIRRORED \ |   LED_MIRRORED \ | ||||||
|   RGBLIGHT_FULL_POWER \ |   RGBLIGHT_FULL_POWER \ | ||||||
|   LTO_ENABLE \ |   LTO_ENABLE \ | ||||||
|   PROGRAMMABLE_BUTTON_ENABLE |   PROGRAMMABLE_BUTTON_ENABLE \ | ||||||
|  |   SECURE_ENABLE | ||||||
|  |  | ||||||
| define NAME_ECHO | define NAME_ECHO | ||||||
|        @printf "  %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)" |        @printf "  %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)" | ||||||
|   | |||||||
| @@ -78,6 +78,9 @@ | |||||||
|     "QMK_KEYS_PER_SCAN": {"info_key": "qmk.keys_per_scan", "value_type": "int"}, |     "QMK_KEYS_PER_SCAN": {"info_key": "qmk.keys_per_scan", "value_type": "int"}, | ||||||
|     "QMK_LED": {"info_key": "qmk_lufa_bootloader.led"}, |     "QMK_LED": {"info_key": "qmk_lufa_bootloader.led"}, | ||||||
|     "QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"}, |     "QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"}, | ||||||
|  |     "SECURE_UNLOCK_SEQUENCE": {"info_key": "secure.unlock_sequence", "value_type": "array.array.int", "to_json": false}, | ||||||
|  |     "SECURE_UNLOCK_TIMEOUT": {"info_key": "secure.unlock_timeout", "value_type": "int"}, | ||||||
|  |     "SECURE_IDLE_TIMEOUT": {"info_key": "secure.idle_timeout", "value_type": "int"}, | ||||||
|     "SENDSTRING_BELL": {"info_key": "audio.macro_beep", "value_type": "bool"}, |     "SENDSTRING_BELL": {"info_key": "audio.macro_beep", "value_type": "bool"}, | ||||||
|     "SPLIT_MODS_ENABLE": {"info_key": "split.transport.sync_modifiers", "value_type": "bool"}, |     "SPLIT_MODS_ENABLE": {"info_key": "split.transport.sync_modifiers", "value_type": "bool"}, | ||||||
|     "SPLIT_TRANSPORT_MIRROR": {"info_key": "split.transport.sync_matrix_state", "value_type": "bool"}, |     "SPLIT_TRANSPORT_MIRROR": {"info_key": "split.transport.sync_matrix_state", "value_type": "bool"}, | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|     "MOUSEKEY_ENABLE": {"info_key": "mouse_key.enabled", "value_type": "bool"}, |     "MOUSEKEY_ENABLE": {"info_key": "mouse_key.enabled", "value_type": "bool"}, | ||||||
|     "NO_USB_STARTUP_CHECK": {"info_key": "usb.no_startup_check", "value_type": "bool"}, |     "NO_USB_STARTUP_CHECK": {"info_key": "usb.no_startup_check", "value_type": "bool"}, | ||||||
|     "PIN_COMPATIBLE": {"info_key": "pin_compatible"}, |     "PIN_COMPATIBLE": {"info_key": "pin_compatible"}, | ||||||
|  |     "SECURE_ENABLE": {"info_key": "secure.enabled", "value_type": "bool"}, | ||||||
|     "SPLIT_KEYBOARD": {"info_key": "split.enabled", "value_type": "bool"}, |     "SPLIT_KEYBOARD": {"info_key": "split.enabled", "value_type": "bool"}, | ||||||
|     "SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "to_c": false}, |     "SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "to_c": false}, | ||||||
|     "WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"} |     "WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"} | ||||||
|   | |||||||
| @@ -244,6 +244,30 @@ | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "secure": { | ||||||
|  |             "type": "object", | ||||||
|  |             "additionalProperties": false, | ||||||
|  |             "properties": { | ||||||
|  |                 "enabled": {"type": "boolean"}, | ||||||
|  |                 "unlock_timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | ||||||
|  |                 "idle_timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | ||||||
|  |                 "unlock_sequence": { | ||||||
|  |                     "type": "array", | ||||||
|  |                     "minLength": 1, | ||||||
|  |                     "maxLength": 5, | ||||||
|  |                     "items": { | ||||||
|  |                         "type": "array", | ||||||
|  |                         "minItems": 2, | ||||||
|  |                         "maxItems": 2, | ||||||
|  |                         "items": { | ||||||
|  |                             "type": "number", | ||||||
|  |                             "min": 0, | ||||||
|  |                             "multipleOf": 1 | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "split": { |         "split": { | ||||||
|             "type": "object", |             "type": "object", | ||||||
|             "additionalProperties": false, |             "additionalProperties": false, | ||||||
|   | |||||||
| @@ -94,7 +94,12 @@ def generate_config_items(kb_info_json, config_h_lines): | |||||||
|         except KeyError: |         except KeyError: | ||||||
|             continue |             continue | ||||||
|  |  | ||||||
|         if key_type.startswith('array'): |         if key_type.startswith('array.array'): | ||||||
|  |             config_h_lines.append('') | ||||||
|  |             config_h_lines.append(f'#ifndef {config_key}') | ||||||
|  |             config_h_lines.append(f'#   define {config_key} {{ {", ".join(["{" + ",".join(list(map(str, x))) + "}" for x in config_value])} }}') | ||||||
|  |             config_h_lines.append(f'#endif // {config_key}') | ||||||
|  |         elif key_type.startswith('array'): | ||||||
|             config_h_lines.append('') |             config_h_lines.append('') | ||||||
|             config_h_lines.append(f'#ifndef {config_key}') |             config_h_lines.append(f'#ifndef {config_key}') | ||||||
|             config_h_lines.append(f'#   define {config_key} {{ {", ".join(map(str, config_value))} }}') |             config_h_lines.append(f'#   define {config_key} {{ {", ".join(map(str, config_value))} }}') | ||||||
|   | |||||||
| @@ -168,28 +168,46 @@ def _extract_pins(pins): | |||||||
|     return [_pin_name(pin) for pin in pins.split(',')] |     return [_pin_name(pin) for pin in pins.split(',')] | ||||||
|  |  | ||||||
|  |  | ||||||
| def _extract_direct_matrix(direct_pins): | def _extract_2d_array(raw): | ||||||
|  |     """Return a 2d array of strings | ||||||
|     """ |     """ | ||||||
|     """ |     out_array = [] | ||||||
|     direct_pin_array = [] |  | ||||||
|  |  | ||||||
|     while direct_pins[-1] != '}': |     while raw[-1] != '}': | ||||||
|         direct_pins = direct_pins[:-1] |         raw = raw[:-1] | ||||||
|  |  | ||||||
|     for row in direct_pins.split('},{'): |     for row in raw.split('},{'): | ||||||
|         if row.startswith('{'): |         if row.startswith('{'): | ||||||
|             row = row[1:] |             row = row[1:] | ||||||
|  |  | ||||||
|         if row.endswith('}'): |         if row.endswith('}'): | ||||||
|             row = row[:-1] |             row = row[:-1] | ||||||
|  |  | ||||||
|         direct_pin_array.append([]) |         out_array.append([]) | ||||||
|  |  | ||||||
|         for pin in row.split(','): |         for val in row.split(','): | ||||||
|             if pin == 'NO_PIN': |             out_array[-1].append(val) | ||||||
|                 pin = None |  | ||||||
|  |  | ||||||
|             direct_pin_array[-1].append(pin) |     return out_array | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _extract_2d_int_array(raw): | ||||||
|  |     """Return a 2d array of ints | ||||||
|  |     """ | ||||||
|  |     ret = _extract_2d_array(raw) | ||||||
|  |  | ||||||
|  |     return [list(map(int, x)) for x in ret] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _extract_direct_matrix(direct_pins): | ||||||
|  |     """extract direct_matrix | ||||||
|  |     """ | ||||||
|  |     direct_pin_array = _extract_2d_array(direct_pins) | ||||||
|  |  | ||||||
|  |     for i in range(len(direct_pin_array)): | ||||||
|  |         for j in range(len(direct_pin_array[i])): | ||||||
|  |             if direct_pin_array[i][j] == 'NO_PIN': | ||||||
|  |                 direct_pin_array[i][j] = None | ||||||
|  |  | ||||||
|     return direct_pin_array |     return direct_pin_array | ||||||
|  |  | ||||||
| @@ -207,6 +225,21 @@ def _extract_audio(info_data, config_c): | |||||||
|         info_data['audio'] = {'pins': audio_pins} |         info_data['audio'] = {'pins': audio_pins} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _extract_secure_unlock(info_data, config_c): | ||||||
|  |     """Populate data about the secure unlock sequence | ||||||
|  |     """ | ||||||
|  |     unlock = config_c.get('SECURE_UNLOCK_SEQUENCE', '').replace(' ', '')[1:-1] | ||||||
|  |     if unlock: | ||||||
|  |         unlock_array = _extract_2d_int_array(unlock) | ||||||
|  |         if 'secure' not in info_data: | ||||||
|  |             info_data['secure'] = {} | ||||||
|  |  | ||||||
|  |         if 'unlock_sequence' in info_data['secure']: | ||||||
|  |             _log_warning(info_data, 'Secure unlock sequence is specified in both config.h (SECURE_UNLOCK_SEQUENCE) and info.json (secure.unlock_sequence) (Value: %s), the config.h value wins.' % info_data['secure']['unlock_sequence']) | ||||||
|  |  | ||||||
|  |         info_data['secure']['unlock_sequence'] = unlock_array | ||||||
|  |  | ||||||
|  |  | ||||||
| def _extract_split_main(info_data, config_c): | def _extract_split_main(info_data, config_c): | ||||||
|     """Populate data about the split configuration |     """Populate data about the split configuration | ||||||
|     """ |     """ | ||||||
| @@ -466,6 +499,7 @@ def _extract_config_h(info_data, config_c): | |||||||
|     # Pull data that easily can't be mapped in json |     # Pull data that easily can't be mapped in json | ||||||
|     _extract_matrix_info(info_data, config_c) |     _extract_matrix_info(info_data, config_c) | ||||||
|     _extract_audio(info_data, config_c) |     _extract_audio(info_data, config_c) | ||||||
|  |     _extract_secure_unlock(info_data, config_c) | ||||||
|     _extract_split_main(info_data, config_c) |     _extract_split_main(info_data, config_c) | ||||||
|     _extract_split_transport(info_data, config_c) |     _extract_split_transport(info_data, config_c) | ||||||
|     _extract_split_right_pins(info_data, config_c) |     _extract_split_right_pins(info_data, config_c) | ||||||
|   | |||||||
| @@ -562,6 +562,10 @@ void quantum_task(void) { | |||||||
| #ifdef AUTO_SHIFT_ENABLE | #ifdef AUTO_SHIFT_ENABLE | ||||||
|     autoshift_matrix_scan(); |     autoshift_matrix_scan(); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef SECURE_ENABLE | ||||||
|  |     secure_task(); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| /** \brief Keyboard task: Do keyboard routine jobs | /** \brief Keyboard task: Do keyboard routine jobs | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								quantum/process_keycode/process_secure.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								quantum/process_keycode/process_secure.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | // Copyright 2022 QMK | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #include "secure.h" | ||||||
|  | #include "process_secure.h" | ||||||
|  | #include "quantum_keycodes.h" | ||||||
|  |  | ||||||
|  | bool preprocess_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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool process_secure(uint16_t keycode, keyrecord_t *record) { | ||||||
|  | #ifndef SECURE_DISABLE_KEYCODES | ||||||
|  |     if (!record->event.pressed) { | ||||||
|  |         if (keycode == SECURE_LOCK) { | ||||||
|  |             secure_lock(); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if (keycode == SECURE_UNLOCK) { | ||||||
|  |             secure_unlock(); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if (keycode == SECURE_TOGGLE) { | ||||||
|  |             secure_is_locked() ? secure_unlock() : secure_lock(); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |     return true; | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								quantum/process_keycode/process_secure.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								quantum/process_keycode/process_secure.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | // Copyright 2022 QMK | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include "action.h" | ||||||
|  |  | ||||||
|  | /** \brief Intercept keycodes and detect unlock sequences | ||||||
|  |  */ | ||||||
|  | bool preprocess_secure(uint16_t keycode, keyrecord_t *record); | ||||||
|  |  | ||||||
|  | /** \brief Handle any secure specific keycodes | ||||||
|  |  */ | ||||||
|  | bool process_secure(uint16_t keycode, keyrecord_t *record); | ||||||
| @@ -212,6 +212,12 @@ bool process_record_quantum(keyrecord_t *record) { | |||||||
|     //   return false; |     //   return false; | ||||||
|     // } |     // } | ||||||
|  |  | ||||||
|  | #if defined(SECURE_ENABLE) | ||||||
|  |     if (!preprocess_secure(keycode, record)) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef VELOCIKEY_ENABLE | #ifdef VELOCIKEY_ENABLE | ||||||
|     if (velocikey_enabled() && record->event.pressed) { |     if (velocikey_enabled() && record->event.pressed) { | ||||||
|         velocikey_accelerate(); |         velocikey_accelerate(); | ||||||
| @@ -247,6 +253,9 @@ bool process_record_quantum(keyrecord_t *record) { | |||||||
|             process_record_via(keycode, record) && |             process_record_via(keycode, record) && | ||||||
| #endif | #endif | ||||||
|             process_record_kb(keycode, record) && |             process_record_kb(keycode, record) && | ||||||
|  | #if defined(SECURE_ENABLE) | ||||||
|  |             process_secure(keycode, record) && | ||||||
|  | #endif | ||||||
| #if defined(SEQUENCER_ENABLE) | #if defined(SEQUENCER_ENABLE) | ||||||
|             process_sequencer(keycode, record) && |             process_sequencer(keycode, record) && | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -200,6 +200,11 @@ extern layer_state_t layer_state; | |||||||
| #    include "process_dynamic_macro.h" | #    include "process_dynamic_macro.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef SECURE_ENABLE | ||||||
|  | #    include "secure.h" | ||||||
|  | #    include "process_secure.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef DYNAMIC_KEYMAP_ENABLE | #ifdef DYNAMIC_KEYMAP_ENABLE | ||||||
| #    include "dynamic_keymap.h" | #    include "dynamic_keymap.h" | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -597,6 +597,10 @@ enum quantum_keycodes { | |||||||
|  |  | ||||||
|     QK_MAKE, |     QK_MAKE, | ||||||
|  |  | ||||||
|  |     SECURE_LOCK, | ||||||
|  |     SECURE_UNLOCK, | ||||||
|  |     SECURE_TOGGLE, | ||||||
|  |  | ||||||
|     // Start of custom keycode range for keyboards and keymaps - always leave at the end |     // Start of custom keycode range for keyboards and keymaps - always leave at the end | ||||||
|     SAFE_RANGE |     SAFE_RANGE | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										87
									
								
								quantum/secure.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								quantum/secure.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | // 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 | ||||||
|  |  | ||||||
|  | #ifndef SECURE_UNLOCK_SEQUENCE | ||||||
|  | #    define SECURE_UNLOCK_SEQUENCE \ | ||||||
|  |         {                          \ | ||||||
|  |             { 0, 0 }               \ | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static 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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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_activity_event(void) { | ||||||
|  |     if (secure_status == SECURE_UNLOCKED) { | ||||||
|  |         idle_time = timer_read32(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void secure_keypress_event(uint8_t row, uint8_t col) { | ||||||
|  |     static const uint8_t sequence[][2] = SECURE_UNLOCK_SEQUENCE; | ||||||
|  |     static const uint8_t sequence_len  = sizeof(sequence) / sizeof(sequence[0]); | ||||||
|  |  | ||||||
|  |     static uint8_t offset = 0; | ||||||
|  |     if ((sequence[offset][0] == row) && (sequence[offset][1] == col)) { | ||||||
|  |         offset++; | ||||||
|  |         if (offset == sequence_len) { | ||||||
|  |             offset = 0; | ||||||
|  |             secure_unlock(); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         offset = 0; | ||||||
|  |         secure_lock(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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 | ||||||
|  | } | ||||||
							
								
								
									
										67
									
								
								quantum/secure.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								quantum/secure.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | // Copyright 2022 QMK | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | /** \file | ||||||
|  |  * | ||||||
|  |  * Exposes a set of functionality to act as a virtual padlock for your device | ||||||
|  |  * ... As long as that padlock is made of paper and its currently raining. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | /** \brief Available secure states | ||||||
|  |  */ | ||||||
|  | typedef enum { | ||||||
|  |     SECURE_LOCKED, | ||||||
|  |     SECURE_PENDING, | ||||||
|  |     SECURE_UNLOCKED, | ||||||
|  | } secure_status_t; | ||||||
|  |  | ||||||
|  | /** \brief Query current secure state | ||||||
|  |  */ | ||||||
|  | secure_status_t secure_get_status(void); | ||||||
|  |  | ||||||
|  | /** \brief Helper to check if unlocking is currently locked | ||||||
|  |  */ | ||||||
|  | #define secure_is_locked() (secure_get_status() == SECURE_LOCKED) | ||||||
|  |  | ||||||
|  | /** \brief Helper to check if unlocking is currently in progress | ||||||
|  |  */ | ||||||
|  | #define secure_is_unlocking() (secure_get_status() == SECURE_PENDING) | ||||||
|  |  | ||||||
|  | /** \brief Helper to check if unlocking is currently unlocked | ||||||
|  |  */ | ||||||
|  | #define secure_is_unlocked() (secure_get_status() == SECURE_UNLOCKED) | ||||||
|  |  | ||||||
|  | /** \brief Lock down the device | ||||||
|  |  */ | ||||||
|  | void secure_lock(void); | ||||||
|  |  | ||||||
|  | /** \brief Force unlock the device | ||||||
|  |  * | ||||||
|  |  * \warning bypasses user unlock sequence | ||||||
|  |  */ | ||||||
|  | void secure_unlock(void); | ||||||
|  |  | ||||||
|  | /** \brief Begin listening for an unlock sequence | ||||||
|  |  */ | ||||||
|  | void secure_request_unlock(void); | ||||||
|  |  | ||||||
|  | /** \brief Flag to the secure subsystem that user activity has happened | ||||||
|  |  * | ||||||
|  |  * Call when some user activity has happened and the device should remain unlocked | ||||||
|  |  */ | ||||||
|  | void secure_activity_event(void); | ||||||
|  |  | ||||||
|  | /** \brief Flag to the secure subsystem that user has triggered a keypress | ||||||
|  |  * | ||||||
|  |  * Call to trigger processing of the unlock sequence | ||||||
|  |  */ | ||||||
|  | void secure_keypress_event(uint8_t row, uint8_t col); | ||||||
|  |  | ||||||
|  | /** \brief Handle various secure subsystem background tasks | ||||||
|  |  */ | ||||||
|  | void secure_task(void); | ||||||
		Reference in New Issue
	
	Block a user