summaryrefslogtreecommitdiff
path: root/lib/efi_loader
diff options
context:
space:
mode:
authorSughosh Ganu <sughosh.ganu@linaro.org>2020-12-30 19:27:09 +0530
committerHeinrich Schuchardt <xypron.glpk@gmx.de>2020-12-31 14:41:31 +0100
commit04be98bd6bcfccf3ab028fda0ca962dd00f61260 (patch)
tree3c5364e835613770b47a069ca9dd398ac0ac4ceb /lib/efi_loader
parentb4f20a5d83f0b8a5c30128966eabe68748631e66 (diff)
efi: capsule: Add support for uefi capsule authentication
Add support for authenticating uefi capsules. Most of the signature verification functionality is shared with the uefi secure boot feature. The root certificate containing the public key used for the signature verification is stored as part of the device tree blob. The root certificate is stored as an efi signature list(esl) file -- this file contains the x509 certificate which is the root certificate. Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Diffstat (limited to 'lib/efi_loader')
-rw-r--r--lib/efi_loader/Kconfig17
-rw-r--r--lib/efi_loader/efi_capsule.c122
-rw-r--r--lib/efi_loader/efi_signature.c4
3 files changed, 141 insertions, 2 deletions
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index e7804913574..fdf245dea30 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -153,6 +153,23 @@ config EFI_CAPSULE_FIRMWARE_MANAGEMENT
Select this option if you want to enable capsule-based
firmware update using Firmware Management Protocol.
+config EFI_CAPSULE_AUTHENTICATE
+ bool "Update Capsule authentication"
+ depends on EFI_CAPSULE_FIRMWARE
+ depends on EFI_CAPSULE_ON_DISK
+ depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
+ select SHA256
+ select RSA
+ select RSA_VERIFY
+ select RSA_VERIFY_WITH_PKEY
+ select X509_CERTIFICATE_PARSER
+ select PKCS7_MESSAGE_PARSER
+ select PKCS7_VERIFY
+ default n
+ help
+ Select this option if you want to enable capsule
+ authentication
+
config EFI_CAPSULE_FIRMWARE_FIT
bool "FMP driver for FIT image"
depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index 4ef25462678..dad1b0fcf7c 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -14,6 +14,10 @@
#include <mapmem.h>
#include <sort.h>
+#include <crypto/pkcs7.h>
+#include <crypto/pkcs7_parser.h>
+#include <linux/err.h>
+
const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
static const efi_guid_t efi_guid_firmware_management_capsule_id =
EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
@@ -191,6 +195,124 @@ skip:
return NULL;
}
+#if defined(CONFIG_EFI_CAPSULE_AUTHENTICATE)
+
+const efi_guid_t efi_guid_capsule_root_cert_guid =
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
+
+__weak int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len)
+{
+ /* The platform is supposed to provide
+ * a method for getting the public key
+ * stored in the form of efi signature
+ * list
+ */
+ return 0;
+}
+
+efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_size,
+ void **image, efi_uintn_t *image_size)
+{
+ u8 *buf;
+ int ret;
+ void *fdt_pkey, *pkey;
+ efi_uintn_t pkey_len;
+ uint64_t monotonic_count;
+ struct efi_signature_store *truststore;
+ struct pkcs7_message *capsule_sig;
+ struct efi_image_regions *regs;
+ struct efi_firmware_image_authentication *auth_hdr;
+ efi_status_t status;
+
+ status = EFI_SECURITY_VIOLATION;
+ capsule_sig = NULL;
+ truststore = NULL;
+ regs = NULL;
+
+ /* Sanity checks */
+ if (capsule == NULL || capsule_size == 0)
+ goto out;
+
+ auth_hdr = (struct efi_firmware_image_authentication *)capsule;
+ if (capsule_size < sizeof(*auth_hdr))
+ goto out;
+
+ if (auth_hdr->auth_info.hdr.dwLength <=
+ offsetof(struct win_certificate_uefi_guid, cert_data))
+ goto out;
+
+ if (guidcmp(&auth_hdr->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
+ goto out;
+
+ *image = (uint8_t *)capsule + sizeof(auth_hdr->monotonic_count) +
+ auth_hdr->auth_info.hdr.dwLength;
+ *image_size = capsule_size - auth_hdr->auth_info.hdr.dwLength -
+ sizeof(auth_hdr->monotonic_count);
+ memcpy(&monotonic_count, &auth_hdr->monotonic_count,
+ sizeof(monotonic_count));
+
+ /* data to be digested */
+ regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 2, 1);
+ if (!regs)
+ goto out;
+
+ regs->max = 2;
+ efi_image_region_add(regs, (uint8_t *)*image,
+ (uint8_t *)*image + *image_size, 1);
+
+ efi_image_region_add(regs, (uint8_t *)&monotonic_count,
+ (uint8_t *)&monotonic_count + sizeof(monotonic_count),
+ 1);
+
+ capsule_sig = efi_parse_pkcs7_header(auth_hdr->auth_info.cert_data,
+ auth_hdr->auth_info.hdr.dwLength
+ - sizeof(auth_hdr->auth_info),
+ &buf);
+ if (IS_ERR(capsule_sig)) {
+ debug("Parsing variable's pkcs7 header failed\n");
+ capsule_sig = NULL;
+ goto out;
+ }
+
+ ret = efi_get_public_key_data(&fdt_pkey, &pkey_len);
+ if (ret < 0)
+ goto out;
+
+ pkey = malloc(pkey_len);
+ if (!pkey)
+ goto out;
+
+ memcpy(pkey, fdt_pkey, pkey_len);
+ truststore = efi_build_signature_store(pkey, pkey_len);
+ if (!truststore)
+ goto out;
+
+ /* verify signature */
+ if (efi_signature_verify(regs, capsule_sig, truststore, NULL)) {
+ debug("Verified\n");
+ } else {
+ debug("Verifying variable's signature failed\n");
+ goto out;
+ }
+
+ status = EFI_SUCCESS;
+
+out:
+ efi_sigstore_free(truststore);
+ pkcs7_free_message(capsule_sig);
+ free(regs);
+
+ return status;
+}
+#else
+efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_size,
+ void **image, efi_uintn_t *image_size)
+{
+ return EFI_UNSUPPORTED;
+}
+#endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
+
+
/**
* efi_capsule_update_firmware - update firmware from capsule
* @capsule_data: Capsule
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index 87525bdc804..c7ec2754147 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -26,7 +26,7 @@ const efi_guid_t efi_guid_cert_x509 = EFI_CERT_X509_GUID;
const efi_guid_t efi_guid_cert_x509_sha256 = EFI_CERT_X509_SHA256_GUID;
const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
-#ifdef CONFIG_EFI_SECURE_BOOT
+#if defined(CONFIG_EFI_SECURE_BOOT) || defined(CONFIG_EFI_CAPSULE_AUTHENTICATE)
static u8 pkcs7_hdr[] = {
/* SEQUENCE */
0x30, 0x82, 0x05, 0xc7,
@@ -846,4 +846,4 @@ struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
return efi_build_signature_store(db, db_size);
}
-#endif /* CONFIG_EFI_SECURE_BOOT */
+#endif /* CONFIG_EFI_SECURE_BOOT || CONFIG_EFI_CAPSULE_AUTHENTICATE */