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:
94
cmd/luks.c
94
cmd/luks.c
@@ -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));
|
||||||
|
|||||||
@@ -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
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user