From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1kdhZZ-0002ri-1v for mharc-grub-devel@gnu.org; Fri, 13 Nov 2020 17:29:37 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:42820) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kdhZX-0002rC-7L for grub-devel@gnu.org; Fri, 13 Nov 2020 17:29:35 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:27704) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kdhZV-0005aa-9E for grub-devel@gnu.org; Fri, 13 Nov 2020 17:29:34 -0500 Received: from pps.filterd (m0098417.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 0ADM3rjE184953; Fri, 13 Nov 2020 17:29:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=0t5HOzYoYBvYm7BJ1CA4iky2uUSs4G3VyuZBZb/b0y8=; b=K39rMUdSnzcSSgNAmhgjzjzgTl5KtzCfgW3U0Rbxl9GDRNyfh5o8yGFkGRtJrBQIU0q7 9fdzPSL9KSqVglu5rMAQvkx/eIISNwr7AMbk/zSy+88GSY5JF0yvpB7uWchn+yj5zd1T 98fmttBtl2KFZUo+VlsxC3hkGS/voingc2mIJnyboSktt95L55qNDrktDPznMnEp7KMI hljulug4quYtd3b2uE8w5pvDqIG3yxPEfzG4SZcXiyqGRRFGMW5RpC2J51GiWTrJuCXV RenxXZmViEWq5h9ObfDQFp+K1DzXQpdAyHHT7iaQrELtr58qs1eMyUXQfIXb+88Sz0PB Cg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 34sxt4yfe7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 13 Nov 2020 17:29:30 -0500 Received: from m0098417.ppops.net (m0098417.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.36/8.16.0.36) with SMTP id 0ADMJCS6037426; Fri, 13 Nov 2020 17:29:30 -0500 Received: from ppma03dal.us.ibm.com (b.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.11]) by mx0a-001b2d01.pphosted.com with ESMTP id 34sxt4yfdv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 13 Nov 2020 17:29:30 -0500 Received: from pps.filterd (ppma03dal.us.ibm.com [127.0.0.1]) by ppma03dal.us.ibm.com (8.16.0.42/8.16.0.42) with SMTP id 0ADMRavL025248; Fri, 13 Nov 2020 22:29:29 GMT Received: from b03cxnp08025.gho.boulder.ibm.com (b03cxnp08025.gho.boulder.ibm.com [9.17.130.17]) by ppma03dal.us.ibm.com with ESMTP id 34nk7aksqw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 13 Nov 2020 22:29:29 +0000 Received: from b03ledav004.gho.boulder.ibm.com (b03ledav004.gho.boulder.ibm.com [9.17.130.235]) by b03cxnp08025.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 0ADMTJMg4391558 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 13 Nov 2020 22:29:19 GMT Received: from b03ledav004.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A83247805F; Fri, 13 Nov 2020 22:29:25 +0000 (GMT) Received: from b03ledav004.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 644C17805E; Fri, 13 Nov 2020 22:29:23 +0000 (GMT) Received: from jarvis.int.hansenpartnership.com (unknown [9.85.145.64]) by b03ledav004.gho.boulder.ibm.com (Postfix) with ESMTP; Fri, 13 Nov 2020 22:29:23 +0000 (GMT) From: James Bottomley To: grub-devel@gnu.org Cc: dovmurik@linux.vnet.ibm.com, Dov.Murik1@il.ibm.com, ashish.kalra@amd.com, brijesh.singh@amd.com, tobin@ibm.com, david.kaplan@amd.com, jon.grimm@amd.com, thomas.lendacky@amd.com, jejb@linux.ibm.com, frankeh@us.ibm.com, "Dr . David Alan Gilbert" Subject: [PATCH v2 3/3] efi: Add API for retrieving the AMD SEV injected secret for cryptodisk Date: Fri, 13 Nov 2020 14:25:10 -0800 Message-Id: <20201113222510.16958-4-jejb@linux.ibm.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201113222510.16958-1-jejb@linux.ibm.com> References: <20201113222510.16958-1-jejb@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.312, 18.0.737 definitions=2020-11-13_19:2020-11-13, 2020-11-13 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 bulkscore=0 spamscore=0 malwarescore=0 priorityscore=1501 adultscore=0 impostorscore=0 mlxlogscore=999 clxscore=1015 suspectscore=1 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2009150000 definitions=main-2011130141 Received-SPF: pass client-ip=148.163.158.5; envelope-from=jejb@linux.ibm.com; helo=mx0b-001b2d01.pphosted.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/11/13 16:04:08 X-ACL-Warn: Detected OS = Linux 3.x [generic] X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 13 Nov 2020 22:29:35 -0000 This module is designed to provide a sevsecret command which interrogates the EFI configuration table to find the location of the sev secret injection and tries to register the secret with the cryptodisk. The secret is stored in an injection area, usually a page in size. The layout of the secret injection area is a header |GRUB_EFI_SEVSECRET_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 --- v2: use callback to print failure message and destroy secret --- grub-core/Makefile.core.def | 8 ++ grub-core/disk/efi/sevsecret.c | 132 +++++++++++++++++++++++++++++++++ include/grub/efi/api.h | 15 ++++ 3 files changed, 155 insertions(+) create mode 100644 grub-core/disk/efi/sevsecret.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index b5f47fc41..76ae5d8fc 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -784,6 +784,14 @@ module = { enable = efi; }; +module = { + name = sevsecret; + + common = disk/efi/sevsecret.c; + + enable = efi; +}; + module = { name = lsefimmap; diff --git a/grub-core/disk/efi/sevsecret.c b/grub-core/disk/efi/sevsecret.c new file mode 100644 index 000000000..da59dd1ad --- /dev/null +++ b/grub-core/disk/efi/sevsecret.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_efi_packed_guid_t sevsecret_guid = GRUB_EFI_SEVSECRET_TABLE_GUID; +static grub_efi_packed_guid_t tableheader_guid = GRUB_EFI_SEVSECRET_TABLE_HEADER_GUID; +static grub_efi_packed_guid_t diskpasswd_guid = GRUB_EFI_DISKPASSWD_GUID; + +/* + * EFI places the secret in the lower 4GB, so it uses a UINT32 + * for the pointer which we have to transform to the correct type + */ +struct sev_secret { + grub_uint32_t base; + grub_uint32_t size; +}; + +struct secret_header { + grub_efi_packed_guid_t guid; + grub_uint32_t len; +}; + +struct secret_entry { + grub_efi_packed_guid_t guid; + grub_uint32_t len; + char data[0]; +}; + +static grub_err_t +grub_efi_sevsecret_cb (int have_it, void *arg) +{ + struct secret_entry *e = arg; + + /* destroy the secret */ + grub_memset (e, 0, e->len); + + if (have_it) + return GRUB_ERR_NONE; + + return grub_error (GRUB_ERR_ACCESS_DENIED, "SEV password failed to unlock any volumes"); +} + +static grub_err_t +grub_efi_sevsecret_find (struct sev_secret *s) +{ + 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, "SEV 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, "SEV secret area does not start with correct guid\n"); + if (h->len < sizeof (*h)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "SEV 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, "SEV 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 (e->data[end - 1] != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "SEV secret area disk encryption password is not zero terminated\n"); + + return grub_cryptodisk_set_secret (e->data, grub_efi_sevsecret_cb, e); + } + ptr += e->len; + len -= e->len; + } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "SEV secret aread does not contain disk decryption password\n"); +} + +static grub_err_t +grub_efi_sevsecret_init (void) +{ + unsigned int i; + + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + { + grub_efi_packed_guid_t *guid = + &grub_efi_system_table->configuration_table[i].vendor_guid; + + if (! grub_memcmp (guid, &sevsecret_guid, sizeof (grub_efi_packed_guid_t))) { + struct sev_secret *s = + grub_efi_system_table->configuration_table[i].vendor_table; + + return grub_efi_sevsecret_find(s); + } + } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "No SEV secret found in the EFI configuration table"); +} + +static grub_err_t +grub_cmd_sevsecret (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + return grub_efi_sevsecret_init(); +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(sevsecret) +{ + cmd = grub_register_command ("sevsecret", grub_cmd_sevsecret, 0, + N_("Register a SEV secret with cryptomount if one exists")); +} + +GRUB_MOD_FINI(sevsecret) +{ + grub_unregister_command (cmd); +} diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index 1dcaa12f5..80eb880f8 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -299,6 +299,21 @@ { 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ } +#define GRUB_EFI_SEVSECRET_TABLE_GUID \ + { 0xadf956ad, 0xe98c, 0x484c, \ + { 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47} \ + } + +#define GRUB_EFI_SEVSECRET_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 } \ + } + #define GRUB_EFI_ACPI_TABLE_GUID \ { 0xeb9d2d30, 0x2d88, 0x11d3, \ { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ -- 2.26.2