-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support use confidential computing provisioned secrets for disk decry…
…ption The code of this functionality is cherry-picked from https://mail.gnu.org/archive/html/grub-devel/2022-02/msg00064.html. Signed-off-by: hanliyang <[email protected]>
- Loading branch information
Showing
4 changed files
with
391 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,9 @@ | ||
grub2 (2.12-1deepin14) unstable; urgency=medium | ||
|
||
* Support use confidential computing provisioned secrets for disk decryption | ||
|
||
-- hanliyang <[email protected]> Fri, 15 Nov 2024 10:30:11 +0800 | ||
|
||
grub2 (2.12-1deepin13) unstable; urgency=medium | ||
|
||
* Support hygon tpcm | ||
|
162 changes: 162 additions & 0 deletions
162
debian/patches/deepin/0004-cryptodisk-add-OS-provided-secret-support.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
From 16b09bbdd2f2fa271daaf10fc4f3d1861f52ccf0 Mon Sep 17 00:00:00 2001 | ||
From: James Bottomley <[email protected]> | ||
Date: Mon, 11 Nov 2024 14:20:23 +0800 | ||
Subject: [PATCH 4/5] cryptodisk: add OS provided secret support | ||
|
||
cherry-picked from https://mail.gnu.org/archive/html/grub-devel/2022-02/msg00065.html. | ||
|
||
Make use of the new OS provided secrets API so that if the new '-s' | ||
option is passed in we try to extract the secret from the API rather | ||
than prompting for it. | ||
|
||
The primary consumer of this is AMD SEV, which has been programmed to | ||
provide an injectable secret to the encrypted virtual machine. OVMF | ||
provides the secret area and passes it into the EFI Configuration | ||
Tables. The grub EFI layer pulls the secret out and primes the | ||
secrets API with it. The upshot of all of this is that a SEV | ||
protected VM can do an encrypted boot with a protected boot secret. | ||
|
||
[ hly: The patch from James Bottomley can not work properly, fix it | ||
when backport the patch. ] | ||
|
||
Signed-off-by: James Bottomley <[email protected]> | ||
Signed-off-by: hanliyang <[email protected]> | ||
--- | ||
grub-core/disk/cryptodisk.c | 55 +++++++++++++++++++++++++++++++++++-- | ||
include/grub/cryptodisk.h | 14 ++++++++++ | ||
2 files changed, 66 insertions(+), 3 deletions(-) | ||
|
||
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c | ||
index 2246af5..86af122 100644 | ||
--- a/grub-core/disk/cryptodisk.c | ||
+++ b/grub-core/disk/cryptodisk.c | ||
@@ -44,7 +44,8 @@ enum | ||
OPTION_KEYFILE, | ||
OPTION_KEYFILE_OFFSET, | ||
OPTION_KEYFILE_SIZE, | ||
- OPTION_HEADER | ||
+ OPTION_HEADER, | ||
+ OPTION_SECRET | ||
}; | ||
|
||
static const struct grub_arg_option options[] = | ||
@@ -58,6 +59,7 @@ static const struct grub_arg_option options[] = | ||
{"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT}, | ||
{"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, ARG_TYPE_INT}, | ||
{"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING}, | ||
+ {"secret", 's', 0, N_("Get secret passphrase from named module and optional identifier"), 0, 0}, | ||
{0, 0, 0, 0, 0, 0} | ||
}; | ||
|
||
@@ -1020,6 +1022,9 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) | ||
|
||
#endif | ||
|
||
+/* variable to hold the list of secret providers */ | ||
+static struct grub_secret_entry *secret_providers; | ||
+ | ||
static void | ||
cryptodisk_close (grub_cryptodisk_t dev) | ||
{ | ||
@@ -1167,6 +1172,18 @@ grub_cryptodisk_scan_device_real (const char *name, | ||
return dev; | ||
} | ||
|
||
+void | ||
+grub_cryptodisk_add_secret_provider (struct grub_secret_entry *e) | ||
+{ | ||
+ grub_list_push(GRUB_AS_LIST_P (&secret_providers), GRUB_AS_LIST (e)); | ||
+} | ||
+ | ||
+void | ||
+grub_cryptodisk_remove_secret_provider (struct grub_secret_entry *e) | ||
+{ | ||
+ grub_list_remove (GRUB_AS_LIST (e)); | ||
+} | ||
+ | ||
#ifdef GRUB_UTIL | ||
#include <grub/util/misc.h> | ||
grub_err_t | ||
@@ -1265,7 +1282,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) | ||
struct grub_arg_list *state = ctxt->state; | ||
struct grub_cryptomount_args cargs = {0}; | ||
|
||
- if (argc < 1 && !state[OPTION_ALL].set && !state[OPTION_BOOT].set) | ||
+ if (argc < 1 && !state[OPTION_ALL].set && !state[OPTION_BOOT].set && !state[OPTION_SECRET].set) | ||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); | ||
|
||
if (grub_cryptodisk_list == NULL) | ||
@@ -1400,6 +1417,38 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) | ||
grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); | ||
return GRUB_ERR_NONE; | ||
} | ||
+ else if (state[OPTION_SECRET].set) /* secret module */ | ||
+ { | ||
+ struct grub_secret_entry *se = NULL; | ||
+ grub_err_t rc; | ||
+ | ||
+ if (argc < 1) | ||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "secret module must be specified"); | ||
+#ifndef GRUB_UTIL | ||
+ grub_dl_load (args[0]); | ||
+#endif | ||
+ se = grub_named_list_find (GRUB_AS_NAMED_LIST (secret_providers), args[0]); | ||
+ if (se == NULL) | ||
+ return grub_error (GRUB_ERR_INVALID_COMMAND, "No secret provider is found"); | ||
+ | ||
+ rc = se->get (args[1], &cargs.key_data); | ||
+ if (rc) | ||
+ return rc; | ||
+ | ||
+ cargs.key_len = grub_strlen((char *) cargs.key_data); | ||
+ | ||
+ cargs.check_boot = state[OPTION_BOOT].set; | ||
+ cargs.search_uuid = NULL; | ||
+ | ||
+ grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); | ||
+ | ||
+ if (state[OPTION_SECRET].set) | ||
+ { | ||
+ rc = se->put (args[1], 1, &cargs.key_data); | ||
+ } | ||
+ | ||
+ return rc; | ||
+ } | ||
else | ||
{ | ||
grub_disk_t disk; | ||
@@ -1590,7 +1639,7 @@ GRUB_MOD_INIT (cryptodisk) | ||
cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, | ||
N_("[ [-p password] | [-k keyfile" | ||
" [-O keyoffset] [-S keysize] ] ] [-H file]" | ||
- " <SOURCE|-u UUID|-a|-b>"), | ||
+ " <SOURCE|-u UUID|-a|-b|-s MOD [ID]>"), | ||
N_("Mount a crypto device."), options); | ||
grub_procfs_register ("luks_script", &luks_script); | ||
} | ||
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h | ||
index d94df68..1b609bf 100644 | ||
--- a/include/grub/cryptodisk.h | ||
+++ b/include/grub/cryptodisk.h | ||
@@ -187,4 +187,18 @@ grub_util_get_geli_uuid (const char *dev); | ||
grub_cryptodisk_t grub_cryptodisk_get_by_uuid (const char *uuid); | ||
grub_cryptodisk_t grub_cryptodisk_get_by_source_disk (grub_disk_t disk); | ||
|
||
+struct grub_secret_entry { | ||
+ /* as named list */ | ||
+ struct grub_secret_entry *next; | ||
+ struct grub_secret_entry **prev; | ||
+ const char *name; | ||
+ | ||
+ /* additional entries */ | ||
+ grub_err_t (*get) (const char *arg, grub_uint8_t **secret); | ||
+ grub_err_t (*put) (const char *arg, int have_it, grub_uint8_t **secret); | ||
+}; | ||
+ | ||
+void grub_cryptodisk_add_secret_provider (struct grub_secret_entry *e); | ||
+void grub_cryptodisk_remove_secret_provider (struct grub_secret_entry *e); | ||
+ | ||
#endif | ||
-- | ||
2.25.1 | ||
|
220 changes: 220 additions & 0 deletions
220
debian/patches/deepin/0005-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
From aaf8760725bddaf5c31b8561b0440043bb5a4c3c Mon Sep 17 00:00:00 2001 | ||
From: James Bottomley <[email protected]> | ||
Date: Mon, 11 Nov 2024 20:45:47 +0800 | ||
Subject: [PATCH 5/5] efi: Add API for retrieving the EFI secret for cryptodisk | ||
|
||
cherry-picked from https://mail.gnu.org/archive/html/grub-devel/2022-02/msg00066.html. | ||
|
||
This module is designed to provide an efisecret provider which | ||
interrogates the EFI configuration table to find the location of the | ||
confidential computing secret and tries to register the secret with | ||
the cryptodisk. | ||
|
||
The secret is stored in a boot allocated area, usually a page in size. | ||
The layout of the secret injection area is a header | ||
|
||
|GRUB_EFI_SECRET_TABLE_HEADER_GUID|len| | ||
|
||
with entries of the form | ||
|
||
|guid|len|data| | ||
|
||
the guid corresponding to the disk encryption passphrase is | ||
GRUB_EFI_DISKPASSWD_GUID and data must be a zero terminated string. | ||
To get a high entropy string that doesn't need large numbers of | ||
iterations, use a base64 encoding of 33 bytes of random data. | ||
|
||
Signed-off-by: James Bottomley <[email protected]> | ||
Signed-off-by: hanliyang <[email protected]> | ||
--- | ||
grub-core/Makefile.core.def | 8 ++ | ||
grub-core/disk/efi/efisecret.c | 131 +++++++++++++++++++++++++++++++++ | ||
include/grub/efi/api.h | 15 ++++ | ||
3 files changed, 154 insertions(+) | ||
create mode 100644 grub-core/disk/efi/efisecret.c | ||
|
||
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def | ||
index 5ee8199..83fb179 100644 | ||
--- a/grub-core/Makefile.core.def | ||
+++ b/grub-core/Makefile.core.def | ||
@@ -815,6 +815,14 @@ module = { | ||
enable = efi; | ||
}; | ||
|
||
+module = { | ||
+ name = efisecret; | ||
+ | ||
+ common = disk/efi/efisecret.c; | ||
+ | ||
+ enable = efi; | ||
+}; | ||
+ | ||
module = { | ||
name = lsefimmap; | ||
|
||
diff --git a/grub-core/disk/efi/efisecret.c b/grub-core/disk/efi/efisecret.c | ||
new file mode 100644 | ||
index 0000000..ca0bfa8 | ||
--- /dev/null | ||
+++ b/grub-core/disk/efi/efisecret.c | ||
@@ -0,0 +1,131 @@ | ||
+#include <grub/err.h> | ||
+#include <grub/misc.h> | ||
+#include <grub/cryptodisk.h> | ||
+#include <grub/efi/efi.h> | ||
+#include <grub/efi/api.h> | ||
+#include <grub/dl.h> | ||
+ | ||
+GRUB_MOD_LICENSE ("GPLv3+"); | ||
+ | ||
+#pragma GCC diagnostic ignored "-Wcast-align" | ||
+ | ||
+static grub_packed_guid_t secret_guid = GRUB_EFI_SECRET_TABLE_GUID; | ||
+static grub_packed_guid_t tableheader_guid = GRUB_EFI_SECRET_TABLE_HEADER_GUID; | ||
+static grub_packed_guid_t diskpasswd_guid = GRUB_EFI_DISKPASSWD_GUID; | ||
+ | ||
+struct efi_secret { | ||
+ grub_uint64_t base; | ||
+ grub_uint64_t size; | ||
+}; | ||
+ | ||
+struct secret_header { | ||
+ grub_packed_guid_t guid; | ||
+ grub_uint32_t len; | ||
+}; | ||
+ | ||
+struct secret_entry { | ||
+ grub_packed_guid_t guid; | ||
+ grub_uint32_t len; | ||
+ grub_uint8_t data[0]; | ||
+}; | ||
+ | ||
+static grub_err_t | ||
+grub_efi_secret_put (const char *arg __attribute__((unused)), int have_it, | ||
+ grub_uint8_t **ptr) | ||
+{ | ||
+ struct secret_entry *e = (struct secret_entry *)(*ptr - (long)&((struct secret_entry *)0)->data); | ||
+ int len = e->len; | ||
+ | ||
+ /* destroy the secret */ | ||
+ grub_memset (e, 0, len); | ||
+ /* put back the length to make sure the table is still traversable */ | ||
+ e->len = len; | ||
+ | ||
+ *ptr = NULL; | ||
+ | ||
+ if (have_it) | ||
+ return GRUB_ERR_NONE; | ||
+ | ||
+ return grub_error (GRUB_ERR_ACCESS_DENIED, "EFI secret failed to unlock any volumes"); | ||
+} | ||
+ | ||
+static grub_err_t | ||
+grub_efi_secret_find (struct efi_secret *s, grub_uint8_t **secret_ptr) | ||
+{ | ||
+ int len; | ||
+ struct secret_header *h; | ||
+ struct secret_entry *e; | ||
+ unsigned char *ptr = (unsigned char *)(unsigned long)s->base; | ||
+ | ||
+ /* the area must be big enough for a guid and a u32 length */ | ||
+ if (s->size < sizeof (*h)) | ||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area is too small"); | ||
+ | ||
+ h = (struct secret_header *)ptr; | ||
+ if (grub_memcmp(&h->guid, &tableheader_guid, sizeof (h->guid))) | ||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area does not start with correct guid\n"); | ||
+ if (h->len < sizeof (*h)) | ||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area is too small\n"); | ||
+ | ||
+ len = h->len - sizeof (*h); | ||
+ ptr += sizeof (*h); | ||
+ | ||
+ while (len >= (int)sizeof (*e)) { | ||
+ e = (struct secret_entry *)ptr; | ||
+ if (e->len < sizeof(*e) || e->len > (unsigned int)len) | ||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area is corrupt\n"); | ||
+ | ||
+ if (! grub_memcmp (&e->guid, &diskpasswd_guid, sizeof (e->guid))) { | ||
+ int end = e->len - sizeof(*e); | ||
+ | ||
+ /* | ||
+ * the passphrase must be a zero terminated string because the | ||
+ * password routines call grub_strlen () to find its size | ||
+ */ | ||
+ if (end < 2 || e->data[end - 1] != '\0') | ||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area disk encryption password is corrupt\n"); | ||
+ | ||
+ *secret_ptr = e->data; | ||
+ return GRUB_ERR_NONE; | ||
+ } | ||
+ ptr += e->len; | ||
+ len -= e->len; | ||
+ } | ||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area does not contain disk decryption password\n"); | ||
+} | ||
+ | ||
+static grub_err_t | ||
+grub_efi_secret_get (const char *arg __attribute__((unused)), grub_uint8_t **ptr) | ||
+{ | ||
+ unsigned int i; | ||
+ | ||
+ for (i = 0; i < grub_efi_system_table->num_table_entries; i++) | ||
+ { | ||
+ grub_packed_guid_t *guid = | ||
+ &grub_efi_system_table->configuration_table[i].vendor_guid; | ||
+ | ||
+ if (! grub_memcmp (guid, &secret_guid, sizeof (grub_packed_guid_t))) { | ||
+ struct efi_secret *s = | ||
+ grub_efi_system_table->configuration_table[i].vendor_table; | ||
+ | ||
+ return grub_efi_secret_find(s, ptr); | ||
+ } | ||
+ } | ||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "No secret found in the EFI configuration table"); | ||
+} | ||
+ | ||
+static struct grub_secret_entry secret = { | ||
+ .name = "efisecret", | ||
+ .get = grub_efi_secret_get, | ||
+ .put = grub_efi_secret_put, | ||
+}; | ||
+ | ||
+GRUB_MOD_INIT(efisecret) | ||
+{ | ||
+ grub_cryptodisk_add_secret_provider (&secret); | ||
+} | ||
+ | ||
+GRUB_MOD_FINI(efisecret) | ||
+{ | ||
+ grub_cryptodisk_remove_secret_provider (&secret); | ||
+} | ||
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h | ||
index a89bf3d..b718ecd 100644 | ||
--- a/include/grub/efi/api.h | ||
+++ b/include/grub/efi/api.h | ||
@@ -393,6 +393,21 @@ | ||
{0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } \ | ||
} | ||
|
||
+#define GRUB_EFI_SECRET_TABLE_GUID \ | ||
+ { 0xadf956ad, 0xe98c, 0x484c, \ | ||
+ { 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47} \ | ||
+ } | ||
+ | ||
+#define GRUB_EFI_SECRET_TABLE_HEADER_GUID \ | ||
+ { 0x1e74f542, 0x71dd, 0x4d66, \ | ||
+ { 0x96, 0x3e, 0xef, 0x42, 0x87, 0xff, 0x17, 0x3b } \ | ||
+ } | ||
+ | ||
+#define GRUB_EFI_DISKPASSWD_GUID \ | ||
+ { 0x736869e5, 0x84f0, 0x4973, \ | ||
+ { 0x92, 0xec, 0x06, 0x87, 0x9c, 0xe3, 0xda, 0x0b } \ | ||
+ } | ||
+ | ||
struct grub_efi_sal_system_table | ||
{ | ||
grub_uint32_t signature; | ||
-- | ||
2.25.1 | ||
|
Oops, something went wrong.