bootctl: Add the logic for disk unlock using a TKey

The unlock process is quite different with a TKey, since we need to load
the signing app with the user's passphrase as the USS. If the TKey is
not already in firmware mode we must prompt the user to remove and
re-insert it.

The easiest way to implement this is via a state machine. Add the
required logic:

- detect key presence and absence
- prompt for removal and insertion
- send the app, while keeping the UI responsive
- unlock the disk once the TKey provides a key
- report success or failure to the user

Ensure that the logic is only used if CONFIG_TKEY and CONFIG_LUKS are
both enabled.

Co-developed-by: Claude <claude@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
Simon Glass
2025-11-18 15:31:09 -07:00
parent 40be1fd57d
commit 29e684deda
2 changed files with 721 additions and 1 deletions

View File

@@ -10,9 +10,43 @@
#define __bootctl_logic_h
#include <bootctl/oslist.h>
#include <tkey.h>
struct udevice;
/**
* enum unlock_state - State of the disk unlock process
*
* @UNS_IDLE: No unlock in progress
* @UNS_WAITING_PASS: Waiting for user to enter passphrase
* @UNS_UNLOCK_NORMAL: Unlocking with direct passphrase
* @UNS_TKEY_START: Unlocking with TKey
* @UNS_TKEY_WAIT_REMOVE: Waiting for TKey to be removed (after wrong passphrase)
* @UNS_TKEY_WAIT_INSERT: Waiting for TKey to be inserted (after removal)
* @UNS_TKEY_INSERTED: TKey inserted, starting app load
* @UNS_TKEY_LOADING: Loading TKey app
* @UNS_TKEY_READY: TKey key derived, ready to unlock
* @UNS_TKEY_UNLOCK: Unlocking LUKS partition
* @UNS_UNLOCK_RESULT: Processing unlock result (success or failure)
* @UNS_BAD_PASS: Unlock failed, showing error message
* @UNS_OK: Unlock succeeded, showing success message
*/
enum unlock_state {
UNS_IDLE,
UNS_WAITING_PASS,
UNS_UNLOCK_NORMAL,
UNS_TKEY_START,
UNS_TKEY_WAIT_REMOVE,
UNS_TKEY_WAIT_INSERT,
UNS_TKEY_INSERTED,
UNS_TKEY_LOADING,
UNS_TKEY_READY,
UNS_TKEY_UNLOCK,
UNS_UNLOCK_RESULT,
UNS_BAD_PASS,
UNS_OK,
};
/**
* struct logic_priv - Information maintained by the boot logic as it works
*
@@ -27,6 +61,7 @@ struct udevice;
* @opt_autoboot: true to autoboot the default OS after a timeout
* @opt_measure: true to measure loaded images, etc.
* @opt_slow_refresh: refresh the UI only when needed
* @opt_tkey: true to use TKey for unlocking encrypted volumes
*
* @state_loaded: true if the state information has been loaded
* @scanning: true if scanning for new OSes
@@ -40,6 +75,14 @@ struct udevice;
* @selected_seq: sequence number of OS waiting for passphrase, or -1 if none
* @ready_to_boot: true if success message shown, ready to boot on next poll
*
* @tkey: TKey device (pointer never changes once set)
* @tkey_present: true if TKey is physically present and accessible
* @tkey_load_ctx: TKey app loading context for iterative loading
* @tkey_disk_key: Buffer to store derived disk key from TKey
* @ustate: Current state of the disk unlock process
* @unlock_result: Result of disk unlock (0 = OK, -ve on error)
* @time_error: monotonic time when error message display started
*
* @iter: oslist iterator, used to find new OSes
* @meas: TPM-measurement device
* @oslist: provides OSes to boot; we iterate through each osinfo driver to find
@@ -57,6 +100,7 @@ struct logic_priv {
bool opt_autoboot;
bool opt_measure;
bool opt_slow_refresh;
bool opt_tkey;
bool state_loaded;
bool state_saved;
@@ -71,6 +115,14 @@ struct logic_priv {
int selected_seq;
bool ready_to_boot;
struct udevice *tkey;
bool tkey_present;
struct tkey_load_ctx tkey_load_ctx;
u8 tkey_disk_key[TKEY_DISK_KEY_SIZE];
enum unlock_state ustate;
int unlock_result;
ulong time_error;
struct oslist_iter iter;
struct udevice *meas;
struct udevice *oslist;