luks: Support disk unlock using a TKey

Add a -t option to the 'luks unlock' command to allow a TKey to be used
to unlock a disk. The password is used as the user-supplied secret (USS)
in this case.

Series-to: concept
Cover-letter:
luks: Integrate support for a TKey
This series illustrates how to use a Tillitis TKey to unlock an
encrypted disk. This has the advantage that the key depends on a
physical key in the user's posession as well as the usual passphrase.

The TKey handles the key derivation, so this series includes logic to
skip that step when a TKey is used.

The 'luks unlock' command provides a -t flag to use a TKey.

It also provides a small pytest fix to ease conflicts with Labgrid
integration.
END

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
Series-links: 1:63
This commit is contained in:
Simon Glass
2025-11-16 10:51:45 -07:00
parent 8d033bde28
commit 5e381f02ee
2 changed files with 119 additions and 11 deletions

View File

@@ -8,8 +8,11 @@
#include <blk.h> #include <blk.h>
#include <command.h> #include <command.h>
#include <dm.h> #include <dm.h>
#include <hexdump.h>
#include <luks.h> #include <luks.h>
#include <part.h> #include <part.h>
#include <tkey.h>
#include <u-boot/sha256.h>
static int do_luks_detect(struct cmd_tbl *cmdtp, int flag, int argc, static int do_luks_detect(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]) char *const argv[])
@@ -57,18 +60,86 @@ static int do_luks_info(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_SUCCESS; return CMD_RET_SUCCESS;
} }
/**
* unlock_with_tkey() - Unlock LUKS partition using TKey-derived key
*
* This function uses TKey to derive a disk encryption key from the
* provided passphrase (used as USS) and uses it to unlock the LUKS partition.
*
* @dev_desc: Block device descriptor
* @info: Partition information
* @passphrase: Passphrase to use as USS for TKey
* @master_key: Buffer to receive unlocked master key
* @key_size: Pointer to receive key size
* Return: 0 on success, -ve on error
*/
static int unlock_with_tkey(struct blk_desc *dev_desc,
struct disk_partition *info, const char *passphrase,
u8 *master_key, u32 *key_size)
{
u8 tkey_disk_key[TKEY_DISK_KEY_SIZE];
u8 pubkey[TKEY_PUBKEY_SIZE];
struct udevice *tkey_dev;
int ret;
printf("Using TKey for disk encryption key\n");
/* Find TKey device */
ret = uclass_first_device_err(UCLASS_TKEY, &tkey_dev);
if (ret) {
printf("Failed to find TKey device (err %dE)\n", ret);
return ret;
}
/* Derive disk key using TKey with passphrase as USS */
printf("Loading TKey signer app (%lx bytes) with USS...\n",
TKEY_SIGNER_SIZE);
ret = tkey_derive_disk_key(tkey_dev, (const u8 *)__signer_1_0_0_begin,
TKEY_SIGNER_SIZE, (const u8 *)passphrase,
strlen(passphrase), tkey_disk_key, pubkey,
NULL);
if (ret) {
printf("Failed to derive TKey disk key (err %dE)\n", ret);
return ret;
}
printf("TKey public key: ");
print_hex_dump(" ", DUMP_PREFIX_NONE, 16, 1, pubkey,
TKEY_PUBKEY_SIZE, false);
printf("TKey disk key derived successfully\n");
printf("TKey derived disk key: ");
print_hex_dump(" ", DUMP_PREFIX_NONE, 16, 1, tkey_disk_key,
TKEY_DISK_KEY_SIZE, false);
ret = luks_unlock(dev_desc->bdev, info, tkey_disk_key,
TKEY_DISK_KEY_SIZE, true, master_key, key_size);
/* Wipe TKey disk key */
memset(tkey_disk_key, '\0', sizeof(tkey_disk_key));
return ret;
}
static int do_luks_unlock(struct cmd_tbl *cmdtp, int flag, int argc, static int do_luks_unlock(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]) char *const argv[])
{ {
struct blk_desc *dev_desc; struct blk_desc *dev_desc;
struct disk_partition info; struct disk_partition info;
struct udevice *blkmap_dev; struct udevice *blkmap_dev;
const char *passphrase; const char *passphrase = NULL;
bool use_tkey = false;
int part, ret, version; int part, ret, version;
u8 master_key[128]; u8 master_key[128];
char label[64]; char label[64];
u32 key_size; u32 key_size;
/* Check for -t flag */
if (!strcmp(argv[1], "-t")) {
use_tkey = true;
argc--;
argv++;
}
if (argc != 4) if (argc != 4)
return CMD_RET_USAGE; return CMD_RET_USAGE;
@@ -78,6 +149,10 @@ static int do_luks_unlock(struct cmd_tbl *cmdtp, int flag, int argc,
passphrase = argv[3]; passphrase = argv[3];
log_debug("Partition start %llx blks %llx blksz%lx\n",
(unsigned long long)info.start, (unsigned long long)info.size,
(ulong)dev_desc->blksz);
/* Verify it's a LUKS partition */ /* Verify it's a LUKS partition */
version = luks_get_version(dev_desc->bdev, &info); version = luks_get_version(dev_desc->bdev, &info);
if (version < 0) { if (version < 0) {
@@ -87,9 +162,15 @@ static int do_luks_unlock(struct cmd_tbl *cmdtp, int flag, int argc,
printf("Unlocking LUKS%d partition...\n", version); printf("Unlocking LUKS%d partition...\n", version);
/* Unlock the partition to get the master key */ if (use_tkey) {
ret = luks_unlock(dev_desc->bdev, &info, (const u8 *)passphrase, ret = unlock_with_tkey(dev_desc, &info, passphrase, master_key,
strlen(passphrase), false, master_key, &key_size); &key_size);
} else {
/* Unlock with passphrase */
ret = luks_unlock(dev_desc->bdev, &info,(const u8 *)passphrase,
strlen(passphrase), false, master_key,
&key_size);
}
if (ret) { if (ret) {
printf("Failed to unlock LUKS partition (err %dE)\n", ret); printf("Failed to unlock LUKS partition (err %dE)\n", ret);
return CMD_RET_FAILURE; return CMD_RET_FAILURE;
@@ -121,10 +202,11 @@ cleanup:
static char luks_help_text[] = static char luks_help_text[] =
"detect <interface> <dev[:part]> - detect if partition is LUKS encrypted\n" "detect <interface> <dev[:part]> - detect if partition is LUKS encrypted\n"
"luks info <interface> <dev[:part]> - show LUKS header information\n" "luks info <interface> <dev[:part]> - show LUKS header information\n"
"luks unlock <interface> <dev[:part]> <passphrase> - unlock LUKS partition\n"; "luks unlock [-t] <interface> <dev[:part]> <passphrase> - unlock LUKS partition\n"
" -t: Use TKey hardware security token with passphrase as USS\n";
U_BOOT_CMD_WITH_SUBCMDS(luks, "LUKS (Linux Unified Key Setup) operations", U_BOOT_CMD_WITH_SUBCMDS(luks, "LUKS (Linux Unified Key Setup) operations",
luks_help_text, luks_help_text,
U_BOOT_SUBCMD_MKENT(detect, 3, 1, do_luks_detect), U_BOOT_SUBCMD_MKENT(detect, 3, 1, do_luks_detect),
U_BOOT_SUBCMD_MKENT(info, 3, 1, do_luks_info), U_BOOT_SUBCMD_MKENT(info, 3, 1, do_luks_info),
U_BOOT_SUBCMD_MKENT(unlock, 4, 1, do_luks_unlock)); U_BOOT_SUBCMD_MKENT(unlock, 5, 1, do_luks_unlock));

View File

@@ -13,7 +13,7 @@ Synopsis
luks detect <interface> <dev[:part]> luks detect <interface> <dev[:part]>
luks info <interface> <dev[:part]> luks info <interface> <dev[:part]>
luks unlock <interface> <dev[:part]> <passphrase> luks unlock [-t] <interface> <dev[:part]> <passphrase>
Description Description
----------- -----------
@@ -88,12 +88,17 @@ dev[:part]
luks unlock luks unlock
~~~~~~~~~~~ ~~~~~~~~~~~
Unlock a LUKS encrypted partition using a passphrase. This command: Unlock a LUKS encrypted partition using a passphrase or TKey hardware token.
This command:
1. Verifies the partition is LUKS encrypted (LUKS1 or LUKS2) 1. Verifies the partition is LUKS encrypted (LUKS1 or LUKS2)
2. Parses LUKS2 JSON metadata (if LUKS2) using FDT conversion 2. Parses LUKS2 JSON metadata (if LUKS2) using FDT conversion
3. Derives the encryption key using PBKDF2 or Argon2id with the provided 3. Derives the encryption key:
passphrase
- **Without -t**: Uses PBKDF2 or Argon2id with the provided passphrase
- **With -t**: Uses TKey hardware token with passphrase as USS (User-Supplied
Secret) to derive a disk encryption key
4. Attempts to unlock each active key slot 4. Attempts to unlock each active key slot
5. Verifies the master key against the stored digest 5. Verifies the master key against the stored digest
6. Creates a blkmap device providing on-the-fly decryption 6. Creates a blkmap device providing on-the-fly decryption
@@ -118,6 +123,11 @@ be used to access files on the unlocked partition.
* **Argon2id**: Memory-hard KDF resistant to GPU attacks (LUKS2 only, requires * **Argon2id**: Memory-hard KDF resistant to GPU attacks (LUKS2 only, requires
CONFIG_ARGON2) CONFIG_ARGON2)
-t
Optional flag to use TKey hardware security token. When specified, the
passphrase is used as the USS (User-Supplied Secret) to derive a disk
encryption key from the TKey's public key.
interface interface
The storage interface type (e.g., mmc, usb, scsi) The storage interface type (e.g., mmc, usb, scsi)
@@ -125,7 +135,8 @@ dev[:part]
The device number and optional partition number The device number and optional partition number
passphrase passphrase
The passphrase to unlock the LUKS partition. Note that the passphrase is The passphrase to unlock the LUKS partition. When using -t flag, this is
used as the USS for TKey key derivation. Note that the passphrase is
passed as a command-line argument and may be visible in command history. passed as a command-line argument and may be visible in command history.
Consider using environment variables to minimize exposure. Consider using environment variables to minimize exposure.
@@ -228,6 +239,17 @@ Unlock and load a kernel from encrypted partition::
=> bootz ${kernel_addr_r} - ${fdt_addr_r} => bootz ${kernel_addr_r} - ${fdt_addr_r}
Unlock using TKey hardware token::
=> luks unlock -t mmc 0:2 mypassword
Using TKey for disk encryption key
Loading TKey signer app (7168 bytes) with USS...
TKey public key: 3a b2 c4 ... (32 bytes)
TKey disk key derived successfully
Unlocking LUKS2 partition...
Successfully unlocked with key slot 0!
Unlocked LUKS partition as blkmap device 'luks-mmc-0:2'
Configuration Configuration
------------- -------------
@@ -254,6 +276,10 @@ For Argon2id support (modern LUKS2 KDF)::
CONFIG_ARGON2=y # Argon2 password hashing (adds ~50KB to binary) CONFIG_ARGON2=y # Argon2 password hashing (adds ~50KB to binary)
For TKey hardware token support (requires -t flag)::
CONFIG_TKEY=y # TKey hardware security token support
Return value Return value
------------ ------------