1
0
Fork 0

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:
Joel Challis 2022-04-16 19:13:05 +01:00 committed by GitHub
parent ae4d518352
commit 92a61aa0cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 312 additions and 13 deletions

View file

@ -562,6 +562,10 @@ void quantum_task(void) {
#ifdef AUTO_SHIFT_ENABLE
autoshift_matrix_scan();
#endif
#ifdef SECURE_ENABLE
secure_task();
#endif
}
/** \brief Keyboard task: Do keyboard routine jobs

View 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;
}

View 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);

View file

@ -212,6 +212,12 @@ bool process_record_quantum(keyrecord_t *record) {
// return false;
// }
#if defined(SECURE_ENABLE)
if (!preprocess_secure(keycode, record)) {
return false;
}
#endif
#ifdef VELOCIKEY_ENABLE
if (velocikey_enabled() && record->event.pressed) {
velocikey_accelerate();
@ -247,6 +253,9 @@ bool process_record_quantum(keyrecord_t *record) {
process_record_via(keycode, record) &&
#endif
process_record_kb(keycode, record) &&
#if defined(SECURE_ENABLE)
process_secure(keycode, record) &&
#endif
#if defined(SEQUENCER_ENABLE)
process_sequencer(keycode, record) &&
#endif

View file

@ -200,6 +200,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

View file

@ -597,6 +597,10 @@ enum quantum_keycodes {
QK_MAKE,
SECURE_LOCK,
SECURE_UNLOCK,
SECURE_TOGGLE,
// Start of custom keycode range for keyboards and keymaps - always leave at the end
SAFE_RANGE
};

87
quantum/secure.c Normal file
View 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
View 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);