aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/crypto/pkcs7_verify.c37
-rw-r--r--lib/efi_loader/Kconfig31
-rw-r--r--lib/efi_loader/efi_bootmgr.c2
-rw-r--r--lib/efi_loader/efi_boottime.c25
-rw-r--r--lib/efi_loader/efi_capsule.c129
-rw-r--r--lib/efi_loader/efi_console.c12
-rw-r--r--lib/efi_loader/efi_firmware.c77
-rw-r--r--lib/efi_loader/efi_load_initrd.c8
-rw-r--r--lib/efi_loader/efi_setup.c5
-rw-r--r--lib/efi_loader/efi_signature.c192
-rw-r--r--lib/efi_loader/efi_string.c10
-rw-r--r--lib/efi_loader/efi_variable.c93
-rw-r--r--lib/efi_loader/efi_variable_tee.c20
13 files changed, 466 insertions, 175 deletions
diff --git a/lib/crypto/pkcs7_verify.c b/lib/crypto/pkcs7_verify.c
index 320ba49f79..58683ef614 100644
--- a/lib/crypto/pkcs7_verify.c
+++ b/lib/crypto/pkcs7_verify.c
@@ -50,8 +50,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
struct image_region regions[2];
int ret = 0;
- /* The digest was calculated already. */
- if (sig->digest)
+ /*
+ * [RFC2315 9.3]
+ * If the authenticated attributes are present,
+ * the message-digest is calculated on the
+ * attributes present in the
+ * authenticatedAttributes field and not just
+ * the contents field
+ */
+ if (!sinfo->authattrs && sig->digest)
return 0;
if (!sinfo->sig->hash_algo)
@@ -63,17 +70,25 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
else
return -ENOPKG;
- sig->digest = calloc(1, sig->digest_size);
- if (!sig->digest) {
- pr_warn("Sig %u: Out of memory\n", sinfo->index);
- return -ENOMEM;
- }
+ /*
+ * Calculate the hash only if the data is present.
+ * In case of authenticated variable and capsule,
+ * the hash has already been calculated on the
+ * efi_image_regions and populated
+ */
+ if (pkcs7->data) {
+ sig->digest = calloc(1, sig->digest_size);
+ if (!sig->digest) {
+ pr_warn("Sig %u: Out of memory\n", sinfo->index);
+ return -ENOMEM;
+ }
- regions[0].data = pkcs7->data;
- regions[0].size = pkcs7->data_len;
+ regions[0].data = pkcs7->data;
+ regions[0].size = pkcs7->data_len;
- /* Digest the message [RFC2315 9.3] */
- hash_calculate(sinfo->sig->hash_algo, regions, 1, sig->digest);
+ /* Digest the message [RFC2315 9.3] */
+ hash_calculate(sinfo->sig->hash_algo, regions, 1, sig->digest);
+ }
/* However, if there are authenticated attributes, there must be a
* message digest attribute amongst them which corresponds to the
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 073d90c802..fdf245dea3 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -77,6 +77,20 @@ config EFI_VAR_SEED_FILE
endif
+config EFI_VAR_BUF_SIZE
+ int "Memory size of the UEFI variable store"
+ default 16384
+ range 4096 2147483647
+ help
+ This defines the size in bytes of the memory area reserved for keeping
+ UEFI variables.
+
+ When using StandAloneMM (CONFIG_EFI_MM_COMM_TEE=y) this value should
+ match the value of PcdFlashNvStorageVariableSize used to compile the
+ StandAloneMM module.
+
+ Minimum 4096, default 16384.
+
config EFI_GET_TIME
bool "GetTime() runtime service"
depends on DM_RTC
@@ -139,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_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 61dc72a23d..d3be2f94c6 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -275,7 +275,7 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
memcpy(*load_options, lo.optional_data, size);
ret = efi_set_load_options(*handle, size, *load_options);
} else {
- load_options = NULL;
+ *load_options = NULL;
}
error:
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 03053e8660..b2cb0160c0 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -247,8 +247,8 @@ static void efi_queue_event(struct efi_event *event)
}
if (event)
list_add_tail(&event->queue_link, &efi_event_queue);
+ efi_process_event_queue();
}
- efi_process_event_queue();
}
/**
@@ -274,8 +274,8 @@ efi_status_t is_valid_tpl(efi_uintn_t tpl)
* efi_signal_event() - signal an EFI event
* @event: event to signal
*
- * This function signals an event. If the event belongs to an event group all
- * events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL
+ * This function signals an event. If the event belongs to an event group, all
+ * events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL,
* their notification function is queued.
*
* For the SignalEvent service see efi_signal_event_ext.
@@ -2161,7 +2161,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
}
if (!efi_st_keep_devices) {
- if IS_ENABLED(CONFIG_USB_DEVICE)
+ if (IS_ENABLED(CONFIG_USB_DEVICE))
udc_disconnect();
board_quiesce_devices();
dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
@@ -2978,6 +2978,8 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
efi_status_t ret;
void *info;
efi_handle_t parent_image = current_image;
+ efi_status_t exit_status;
+ struct jmp_buf_data exit_jmp;
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
@@ -2999,9 +3001,11 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
image_obj->exit_data_size = exit_data_size;
image_obj->exit_data = exit_data;
+ image_obj->exit_status = &exit_status;
+ image_obj->exit_jmp = &exit_jmp;
/* call the image! */
- if (setjmp(&image_obj->exit_jmp)) {
+ if (setjmp(&exit_jmp)) {
/*
* We called the entry point of the child image with EFI_CALL
* in the lines below. The child image called the Exit() boot
@@ -3023,10 +3027,10 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
*/
assert(__efi_entry_check());
EFI_PRINT("%lu returned by started image\n",
- (unsigned long)((uintptr_t)image_obj->exit_status &
+ (unsigned long)((uintptr_t)exit_status &
~EFI_ERROR_MASK));
current_image = parent_image;
- return EFI_EXIT(image_obj->exit_status);
+ return EFI_EXIT(exit_status);
}
current_image = image_handle;
@@ -3209,6 +3213,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
struct efi_loaded_image *loaded_image_protocol;
struct efi_loaded_image_obj *image_obj =
(struct efi_loaded_image_obj *)image_handle;
+ struct jmp_buf_data *exit_jmp;
EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status,
exit_data_size, exit_data);
@@ -3250,6 +3255,9 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
if (ret != EFI_SUCCESS)
EFI_PRINT("%s: out of memory\n", __func__);
}
+ /* efi_delete_image() frees image_obj. Copy before the call. */
+ exit_jmp = image_obj->exit_jmp;
+ *image_obj->exit_status = exit_status;
if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION ||
exit_status != EFI_SUCCESS)
efi_delete_image(image_obj, loaded_image_protocol);
@@ -3263,8 +3271,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
*/
efi_restore_gd();
- image_obj->exit_status = exit_status;
- longjmp(&image_obj->exit_jmp, 1);
+ longjmp(exit_jmp, 1);
panic("EFI application exited");
out:
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index ea22ee7968..dad1b0fcf7 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;
@@ -73,8 +77,8 @@ void set_capsule_result(int index, struct efi_capsule_header *capsule,
struct efi_time time;
efi_status_t ret;
- efi_create_indexed_name(variable_name16, "Capsule", index);
-
+ efi_create_indexed_name(variable_name16, sizeof(variable_name16),
+ "Capsule", index);
result.variable_total_size = sizeof(result);
result.capsule_guid = capsule->capsule_guid;
ret = EFI_CALL((*efi_runtime_services.get_time)(&time, NULL));
@@ -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
@@ -896,7 +1018,8 @@ efi_status_t efi_launch_capsules(void)
free(files);
/* CapsuleLast */
- efi_create_indexed_name(variable_name16, "Capsule", index - 1);
+ efi_create_indexed_name(variable_name16, sizeof(variable_name16),
+ "Capsule", index - 1);
efi_set_variable_int(L"CapsuleLast", &efi_guid_capsule_report,
EFI_VARIABLE_READ_ONLY |
EFI_VARIABLE_NON_VOLATILE |
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 011accab78..705109596e 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -14,6 +14,7 @@
#include <env.h>
#include <stdio_dev.h>
#include <video_console.h>
+#include <linux/delay.h>
#define EFI_COUT_MODE_2 2
#define EFI_MAX_COUT_MODE 3
@@ -689,6 +690,17 @@ static efi_status_t efi_cin_read_key(struct efi_key_data *key)
switch (ch) {
case 0x1b:
/*
+ * If a second key is received within 10 ms, assume that we are
+ * dealing with an escape sequence. Otherwise consider this the
+ * escape key being hit. 10 ms is long enough to work fine at
+ * 1200 baud and above.
+ */
+ udelay(10000);
+ if (!tstc()) {
+ pressed_key.scan_code = 23;
+ break;
+ }
+ /*
* Xterm Control Sequences
* https://www.xfree86.org/4.8.0/ctlseqs.html
*/
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index 72c560dbc2..5e401bbca2 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -11,8 +11,30 @@
#include <dfu.h>
#include <efi_loader.h>
#include <image.h>
+#include <signatures.h>
+
#include <linux/list.h>
+#define FMP_PAYLOAD_HDR_SIGNATURE SIGNATURE_32('M', 'S', 'S', '1')
+
+/**
+ * struct fmp_payload_header - EDK2 header for the FMP payload
+ *
+ * This structure describes the header which is preprended to the
+ * FMP payload by the edk2 capsule generation scripts.
+ *
+ * @signature: Header signature used to identify the header
+ * @header_size: Size of the structure
+ * @fw_version: Firmware versions used
+ * @lowest_supported_version: Lowest supported version
+ */
+struct fmp_payload_header {
+ u32 signature;
+ u32 header_size;
+ u32 fw_version;
+ u32 lowest_supported_version;
+};
+
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_get_image_unsupported(
@@ -162,9 +184,16 @@ static efi_status_t efi_get_dfu_info(
image_info[i].version_name = NULL; /* not supported */
image_info[i].size = 0;
image_info[i].attributes_supported =
- IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+ IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
image_info[i].attributes_setting =
IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+
+ /* Check if the capsule authentication is enabled */
+ if (env_get("capsule_authentication_enabled"))
+ image_info[0].attributes_setting |=
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
+
image_info[i].lowest_supported_image_version = 0;
image_info[i].last_attempt_version = 0;
image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
@@ -379,12 +408,58 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
efi_status_t (*progress)(efi_uintn_t completion),
u16 **abort_reason)
{
+ u32 fmp_hdr_signature;
+ struct fmp_payload_header *header;
+ void *capsule_payload;
+ efi_status_t status;
+ efi_uintn_t capsule_payload_size;
+
EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
image_size, vendor_code, progress, abort_reason);
if (!image)
return EFI_EXIT(EFI_INVALID_PARAMETER);
+ /* Authenticate the capsule if authentication enabled */
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE) &&
+ env_get("capsule_authentication_enabled")) {
+ capsule_payload = NULL;
+ capsule_payload_size = 0;
+ status = efi_capsule_authenticate(image, image_size,
+ &capsule_payload,
+ &capsule_payload_size);
+
+ if (status == EFI_SECURITY_VIOLATION) {
+ printf("Capsule authentication check failed. Aborting update\n");
+ return EFI_EXIT(status);
+ } else if (status != EFI_SUCCESS) {
+ return EFI_EXIT(status);
+ }
+
+ debug("Capsule authentication successfull\n");
+ image = capsule_payload;
+ image_size = capsule_payload_size;
+ } else {
+ debug("Capsule authentication disabled. ");
+ debug("Updating capsule without authenticating.\n");
+ }
+
+ fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
+ header = (void *)image;
+
+ if (!memcmp(&header->signature, &fmp_hdr_signature,
+ sizeof(fmp_hdr_signature))) {
+ /*
+ * When building the capsule with the scripts in
+ * edk2, a FMP header is inserted above the capsule
+ * payload. Compensate for this header to get the
+ * actual payload that is to be updated.
+ */
+ image += header->header_size;
+ image_size -= header->header_size;
+
+ }
+
if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
NULL, NULL))
return EFI_EXIT(EFI_DEVICE_ERROR);
diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c
index 4bf3b5ef68..b9ee883905 100644
--- a/lib/efi_loader/efi_load_initrd.c
+++ b/lib/efi_loader/efi_load_initrd.c
@@ -4,13 +4,11 @@
*/
#include <common.h>
-#include <env.h>
-#include <malloc.h>
-#include <mapmem.h>
-#include <dm.h>
-#include <fs.h>
#include <efi_loader.h>
#include <efi_load_initrd.h>
+#include <fs.h>
+#include <malloc.h>
+#include <mapmem.h>
static efi_status_t EFIAPI
efi_load_file2_initrd(struct efi_load_file_protocol *this,
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index ce6292f559..5800cbf6d4 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -257,11 +257,6 @@ efi_status_t efi_init_obj_list(void)
if (ret != EFI_SUCCESS)
goto out;
#endif
-#ifdef CONFIG_EFI_LOAD_FILE2_INITRD
- ret = efi_initrd_register();
- if (ret != EFI_SUCCESS)
- goto out;
-#endif
#ifdef CONFIG_NET
ret = efi_net_register();
if (ret != EFI_SUCCESS)
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index 79dee27421..c7ec275414 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -26,7 +26,92 @@ 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,
+ /* OID: pkcs7-signedData */
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
+ /* Context Structured? */
+ 0xa0, 0x82, 0x05, 0xb8,
+};
+
+/**
+ * efi_parse_pkcs7_header - parse a signature in payload
+ * @buf: Pointer to payload's value
+ * @buflen: Length of @buf
+ * @tmpbuf: Pointer to temporary buffer
+ *
+ * Parse a signature embedded in payload's value and instantiate
+ * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
+ * pkcs7's signedData, some header needed be prepended for correctly
+ * parsing authentication data
+ * A temporary buffer will be allocated if needed, and it should be
+ * kept valid during the authentication because some data in the buffer
+ * will be referenced by efi_signature_verify().
+ *
+ * Return: Pointer to pkcs7_message structure on success, NULL on error
+ */
+struct pkcs7_message *efi_parse_pkcs7_header(const void *buf,
+ size_t buflen,
+ u8 **tmpbuf)
+{
+ u8 *ebuf;
+ size_t ebuflen, len;
+ struct pkcs7_message *msg;
+
+ /*
+ * This is the best assumption to check if the binary is
+ * already in a form of pkcs7's signedData.
+ */
+ if (buflen > sizeof(pkcs7_hdr) &&
+ !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
+ msg = pkcs7_parse_message(buf, buflen);
+ if (IS_ERR(msg))
+ return NULL;
+ return msg;
+ }
+
+ /*
+ * Otherwise, we should add a dummy prefix sequence for pkcs7
+ * message parser to be able to process.
+ * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
+ * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
+ * TODO:
+ * The header should be composed in a more refined manner.
+ */
+ EFI_PRINT("Makeshift prefix added to authentication data\n");
+ ebuflen = sizeof(pkcs7_hdr) + buflen;
+ if (ebuflen <= 0x7f) {
+ EFI_PRINT("Data is too short\n");
+ return NULL;
+ }
+
+ ebuf = malloc(ebuflen);
+ if (!ebuf) {
+ EFI_PRINT("Out of memory\n");
+ return NULL;
+ }
+
+ memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
+ memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
+ len = ebuflen - 4;
+ ebuf[2] = (len >> 8) & 0xff;
+ ebuf[3] = len & 0xff;
+ len = ebuflen - 0x13;
+ ebuf[0x11] = (len >> 8) & 0xff;
+ ebuf[0x12] = len & 0xff;
+
+ msg = pkcs7_parse_message(ebuf, ebuflen);
+
+ if (IS_ERR(msg)) {
+ free(ebuf);
+ return NULL;
+ }
+
+ *tmpbuf = ebuf;
+ return msg;
+}
/**
* efi_hash_regions - calculate a hash value
@@ -652,6 +737,63 @@ err:
}
/**
+ * efi_sigstore_parse_sigdb - parse the signature list and populate
+ * the signature store
+ *
+ * @sig_list: Pointer to the signature list
+ * @size: Size of the signature list
+ *
+ * Parse the efi signature list and instantiate a signature store
+ * structure.
+ *
+ * Return: Pointer to signature store on success, NULL on error
+ */
+struct efi_signature_store *efi_build_signature_store(void *sig_list,
+ efi_uintn_t size)
+{
+ struct efi_signature_list *esl;
+ struct efi_signature_store *sigstore = NULL, *siglist;
+
+ esl = sig_list;
+ while (size > 0) {
+ /* List must exist if there is remaining data. */
+ if (size < sizeof(*esl)) {
+ EFI_PRINT("Signature list in wrong format\n");
+ goto err;
+ }
+
+ if (size < esl->signature_list_size) {
+ EFI_PRINT("Signature list in wrong format\n");
+ goto err;
+ }
+
+ /* Parse a single siglist. */
+ siglist = efi_sigstore_parse_siglist(esl);
+ if (!siglist) {
+ EFI_PRINT("Parsing of signature list of failed\n");
+ goto err;
+ }
+
+ /* Append siglist */
+ siglist->next = sigstore;
+ sigstore = siglist;
+
+ /* Next */
+ size -= esl->signature_list_size;
+ esl = (void *)esl + esl->signature_list_size;
+ }
+ free(sig_list);
+
+ return sigstore;
+
+err:
+ efi_sigstore_free(sigstore);
+ free(sig_list);
+
+ return NULL;
+}
+
+/**
* efi_sigstore_parse_sigdb - parse a signature database variable
* @name: Variable's name
*
@@ -662,8 +804,7 @@ err:
*/
struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
{
- struct efi_signature_store *sigstore = NULL, *siglist;
- struct efi_signature_list *esl;
+ struct efi_signature_store *sigstore = NULL;
const efi_guid_t *vendor;
void *db;
efi_uintn_t db_size;
@@ -699,47 +840,10 @@ struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, db));
if (ret != EFI_SUCCESS) {
EFI_PRINT("Getting variable, %ls, failed\n", name);
- goto err;
- }
-
- /* Parse siglist list */
- esl = db;
- while (db_size > 0) {
- /* List must exist if there is remaining data. */
- if (db_size < sizeof(*esl)) {
- EFI_PRINT("variable, %ls, in wrong format\n", name);
- goto err;
- }
-
- if (db_size < esl->signature_list_size) {
- EFI_PRINT("variable, %ls, in wrong format\n", name);
- goto err;
- }
-
- /* Parse a single siglist. */
- siglist = efi_sigstore_parse_siglist(esl);
- if (!siglist) {
- EFI_PRINT("Parsing signature list of %ls failed\n",
- name);
- goto err;
- }
-
- /* Append siglist */
- siglist->next = sigstore;
- sigstore = siglist;
-
- /* Next */
- db_size -= esl->signature_list_size;
- esl = (void *)esl + esl->signature_list_size;
+ free(db);
+ return NULL;
}
- free(db);
- return sigstore;
-
-err:
- efi_sigstore_free(sigstore);
- free(db);
-
- return NULL;
+ return efi_build_signature_store(db, db_size);
}
-#endif /* CONFIG_EFI_SECURE_BOOT */
+#endif /* CONFIG_EFI_SECURE_BOOT || CONFIG_EFI_CAPSULE_AUTHENTICATE */
diff --git a/lib/efi_loader/efi_string.c b/lib/efi_loader/efi_string.c
index 3de721f06c..9627242288 100644
--- a/lib/efi_loader/efi_string.c
+++ b/lib/efi_loader/efi_string.c
@@ -23,13 +23,19 @@
* Return: A pointer to the next position after the created string
* in @buffer, or NULL otherwise
*/
-u16 *efi_create_indexed_name(u16 *buffer, const char *name, unsigned int index)
+u16 *efi_create_indexed_name(u16 *buffer, size_t buffer_size, const char *name,
+ unsigned int index)
{
u16 *p = buffer;
char index_buf[5];
+ size_t size;
+ size = (utf8_utf16_strlen(name) * sizeof(u16) +
+ sizeof(index_buf) * sizeof(u16));
+ if (buffer_size < size)
+ return NULL;
utf8_utf16_strcpy(&p, name);
- sprintf(index_buf, "%04X", index);
+ snprintf(index_buf, sizeof(index_buf), "%04X", index);
utf8_utf16_strcpy(&p, index_buf);
return p;
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 0c689cfb47..ba0874e9e7 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -24,91 +24,6 @@
#include <asm/sections.h>
#ifdef CONFIG_EFI_SECURE_BOOT
-static u8 pkcs7_hdr[] = {
- /* SEQUENCE */
- 0x30, 0x82, 0x05, 0xc7,
- /* OID: pkcs7-signedData */
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
- /* Context Structured? */
- 0xa0, 0x82, 0x05, 0xb8,
-};
-
-/**
- * efi_variable_parse_signature - parse a signature in variable
- * @buf: Pointer to variable's value
- * @buflen: Length of @buf
- * @tmpbuf: Pointer to temporary buffer
- *
- * Parse a signature embedded in variable's value and instantiate
- * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
- * pkcs7's signedData, some header needed be prepended for correctly
- * parsing authentication data, particularly for variable's.
- * A temporary buffer will be allocated if needed, and it should be
- * kept valid during the authentication because some data in the buffer
- * will be referenced by efi_signature_verify().
- *
- * Return: Pointer to pkcs7_message structure on success, NULL on error
- */
-static struct pkcs7_message *efi_variable_parse_signature(const void *buf,
- size_t buflen,
- u8 **tmpbuf)
-{
- u8 *ebuf;
- size_t ebuflen, len;
- struct pkcs7_message *msg;
-
- /*
- * This is the best assumption to check if the binary is
- * already in a form of pkcs7's signedData.
- */
- if (buflen > sizeof(pkcs7_hdr) &&
- !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
- msg = pkcs7_parse_message(buf, buflen);
- if (IS_ERR(msg))
- return NULL;
- return msg;
- }
-
- /*
- * Otherwise, we should add a dummy prefix sequence for pkcs7
- * message parser to be able to process.
- * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
- * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
- * TODO:
- * The header should be composed in a more refined manner.
- */
- EFI_PRINT("Makeshift prefix added to authentication data\n");
- ebuflen = sizeof(pkcs7_hdr) + buflen;
- if (ebuflen <= 0x7f) {
- EFI_PRINT("Data is too short\n");
- return NULL;
- }
-
- ebuf = malloc(ebuflen);
- if (!ebuf) {
- EFI_PRINT("Out of memory\n");
- return NULL;
- }
-
- memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
- memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
- len = ebuflen - 4;
- ebuf[2] = (len >> 8) & 0xff;
- ebuf[3] = len & 0xff;
- len = ebuflen - 0x13;
- ebuf[0x11] = (len >> 8) & 0xff;
- ebuf[0x12] = len & 0xff;
-
- msg = pkcs7_parse_message(ebuf, ebuflen);
-
- if (IS_ERR(msg)) {
- free(ebuf);
- return NULL;
- }
-
- *tmpbuf = ebuf;
- return msg;
-}
/**
* efi_variable_authenticate - authenticate a variable
@@ -215,10 +130,10 @@ static efi_status_t efi_variable_authenticate(u16 *variable,
goto err;
/* ebuf should be kept valid during the authentication */
- var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
- auth->auth_info.hdr.dwLength
- - sizeof(auth->auth_info),
- &ebuf);
+ var_sig = efi_parse_pkcs7_header(auth->auth_info.cert_data,
+ auth->auth_info.hdr.dwLength
+ - sizeof(auth->auth_info),
+ &ebuf);
if (!var_sig) {
EFI_PRINT("Parsing variable's signature failed\n");
goto err;
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index be6f3dfad4..b8808fdeca 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -36,20 +36,29 @@ static int get_connection(struct mm_connection *conn)
static const struct tee_optee_ta_uuid uuid = PTA_STMM_UUID;
struct udevice *tee = NULL;
struct tee_open_session_arg arg;
- int rc;
+ int rc = -ENODEV;
tee = tee_find_device(tee, NULL, NULL, NULL);
if (!tee)
- return -ENODEV;
+ goto out;
memset(&arg, 0, sizeof(arg));
tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
rc = tee_open_session(tee, &arg, 0, NULL);
- if (!rc) {
- conn->tee = tee;
- conn->session = arg.session;
+ if (rc)
+ goto out;
+
+ /* Check the internal OP-TEE result */
+ if (arg.ret != TEE_SUCCESS) {
+ rc = -EIO;
+ goto out;
}
+ conn->tee = tee;
+ conn->session = arg.session;
+
+ return 0;
+out:
return rc;
}
@@ -88,6 +97,7 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
if (tee_shm_register(conn.tee, comm_buf, buf_size, 0, &shm)) {
log_err("Unable to register shared memory\n");
+ tee_close_session(conn.tee, conn.session);
return EFI_UNSUPPORTED;
}