In this commit, implemented are efi_signature_verify_with_db(),
efi_signature_parse_sigdb() and a couple of helper functions which will be
used for variable authentication as well as image authentication in UEFI
secure boot.

efi_signature_verify_with_db() - authenticate an image with its hash value
for unsigned image, and with its embedded pkcs7 signature with a given
signature store if signed. This function will also be used to validate
authentication data in authenticated variables.

efi_signature_parse_sigdb() - parse signature database variable and
retrieve signature lists, which may consist of x509 certificates or message
digests (SHA256 only for now).

Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org>
---
 include/efi_api.h              |  47 +++
 include/efi_loader.h           |  47 +++
 lib/efi_loader/Makefile        |   1 +
 lib/efi_loader/efi_signature.c | 602 +++++++++++++++++++++++++++++++++
 4 files changed, 697 insertions(+)
 create mode 100644 lib/efi_loader/efi_signature.c

diff --git a/include/efi_api.h b/include/efi_api.h
index 9f49a4575e07..72999f762515 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -18,6 +18,7 @@
 
 #include <efi.h>
 #include <charset.h>
+#include <pe.h>
 
 #ifdef CONFIG_EFI_LOADER
 #include <asm/setjmp.h>
@@ -307,6 +308,10 @@ struct efi_runtime_services {
        EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, \
                 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
 
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
+       EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, \
+                0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
+
 #define EFI_FDT_GUID \
        EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \
                 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
@@ -1597,4 +1602,46 @@ struct efi_unicode_collation_protocol {
 #define LOAD_OPTION_CATEGORY_BOOT      0x00000000
 #define LOAD_OPTION_CATEGORY_APP       0x00000100
 
+/* Secure boot */
+#define EFI_CERT_SHA256_GUID \
+       EFI_GUID(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, \
+                0x41, 0xf9, 0x36, 0x93, 0x43, 0x28)
+#define EFI_CERT_RSA2048_GUID \
+       EFI_GUID(0x3c5766e8, 0x269c, 0x4e34, 0xaa, 0x14, \
+                0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6)
+#define EFI_CERT_X509_GUID \
+       EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, \
+                0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
+#define EFI_CERT_X509_SHA256_GUID \
+       EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, \
+                0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed)
+#define EFI_CERT_TYPE_PKCS7_GUID \
+       EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
+                0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
+
+struct win_certificate_uefi_guid {
+       WIN_CERTIFICATE hdr;
+       efi_guid_t      cert_type;
+       u8              cert_data[];
+} __attribute__((__packed__));
+
+struct efi_variable_authentication_2 {
+       struct efi_time                  time_stamp;
+       struct win_certificate_uefi_guid auth_info;
+} __attribute__((__packed__));
+
+struct efi_signature_data {
+       efi_guid_t      signature_owner;
+       u8              signature_data[];
+} __attribute__((__packed__));
+
+struct efi_signature_list {
+       efi_guid_t      signature_type;
+       u32             signature_list_size;
+       u32             signature_header_size;
+       u32             signature_size;
+/*     u8              signature_header[signature_header_size]; */
+/*     struct efi_signature_data signatures[...][signature_size]; */
+} __attribute__((__packed__));
+
 #endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 5298ea7997f7..c75ee5fcb6ba 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -16,6 +16,7 @@
 #if CONFIG_IS_ENABLED(EFI_LOADER)
 
 #include <linux/list.h>
+#include <linux/oid_registry.h>
 
 /* Maximum number of configuration tables */
 #define EFI_MAX_CONFIGURATION_TABLES 16
@@ -156,6 +157,11 @@ extern const efi_guid_t 
efi_guid_hii_config_routing_protocol;
 extern const efi_guid_t efi_guid_hii_config_access_protocol;
 extern const efi_guid_t efi_guid_hii_database_protocol;
 extern const efi_guid_t efi_guid_hii_string_protocol;
+/* GUID for authentication */
+extern const efi_guid_t efi_guid_image_security_database;
+extern const efi_guid_t efi_guid_sha256;
+extern const efi_guid_t efi_guid_cert_x509;
+extern const efi_guid_t efi_guid_cert_x509_sha256;
 
 extern unsigned int __efi_runtime_start, __efi_runtime_stop;
 extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
@@ -654,6 +660,47 @@ void efi_deserialize_load_option(struct efi_load_option 
*lo, u8 *data);
 unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
 efi_status_t efi_bootmgr_load(efi_handle_t *handle);
 
+#ifdef CONFIG_EFI_SECURE_BOOT
+#include <image.h>
+
+#define EFI_REGS_MAX 16 /* currently good enough */
+
+typedef struct {
+       int                     num;
+       struct image_region     reg[EFI_REGS_MAX];
+} efi_image_regions;
+
+struct efi_sig_data {
+       struct efi_sig_data *next;
+       efi_guid_t owner;
+       void *data;
+       size_t size;
+};
+
+typedef struct efi_signature_store {
+       struct efi_signature_store *next;
+       efi_guid_t sig_type;
+       struct efi_sig_data *sig_data_list;
+} efi_signature_store;
+
+struct pkcs7_message;
+
+bool efi_signature_verify_with_db(efi_image_regions *regs,
+                                 struct pkcs7_message *msg,
+                                 efi_signature_store *trusted);
+bool efi_signature_revoke(efi_image_regions *regs,
+                         struct pkcs7_message *msg,
+                         efi_signature_store *untrusted,
+                         efi_signature_store *tsa);
+
+efi_status_t efi_image_region_add(efi_image_regions *ctx,
+                                 const void *start, const void *end,
+                                 int nocheck);
+
+void efi_sigstore_free(efi_signature_store *ctx);
+efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);
+#endif /* CONFIG_EFI_SECURE_BOOT */
+
 #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
 
 /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 01769ea58ba6..49c996c89052 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_PARTITIONS) += efi_disk.o
 obj-$(CONFIG_NET) += efi_net.o
 obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o
 obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
+obj-y += efi_signature.o
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
new file mode 100644
index 000000000000..55a335cc44ae
--- /dev/null
+++ b/lib/efi_loader/efi_signature.c
@@ -0,0 +1,602 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Patrick Wildt <patr...@blueri.se>
+ * Copyright (c) 2019 Linaro Limited, Author: AKASHI Takahiro
+ */
+
+#include <charset.h>
+#include <efi_loader.h>
+#include <image.h>
+#include <hexdump.h>
+#include <malloc.h>
+#include <pe.h>
+#include <linux/compat.h>
+#include <linux/oid_registry.h>
+#include <u-boot/rsa.h>
+#include <u-boot/sha256.h>
+/*
+ * avoid duplicated inclusion:
+ * #include "../lib/crypto/x509_parser.h"
+ */
+#include "../lib/crypto/pkcs7_parser.h"
+
+const efi_guid_t efi_guid_image_security_database =
+               EFI_IMAGE_SECURITY_DATABASE_GUID;
+const efi_guid_t efi_guid_sha256 = EFI_CERT_SHA256_GUID;
+const efi_guid_t efi_guid_cert_rsa2048 = EFI_CERT_RSA2048_GUID;
+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;
+
+#ifdef CONFIG_EFI_SECURE_BOOT
+/* TODO: generalized for other hash algos */
+static const unsigned char WinIndirectSha256[] = {
+       0x30, 0x33, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
+       0x01, 0x0f, 0x30, 0x25, 0x03, 0x01, 0x00, 0xa0, 0x20, 0xa2, 0x1e, 0x80,
+       0x1c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62, 0x00,
+       0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x65, 0x00,
+       0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
+       0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+};
+
+static bool efi_hash_regions(efi_image_regions *regs, void **hash, size_t 
*size)
+{
+       *size = 0;
+       *hash = calloc(1, SHA256_SUM_LEN);
+       if (!*hash) {
+               debug("Out of memory\n");
+               return false;
+       }
+       *size = SHA256_SUM_LEN;
+
+       hash_calculate("sha256", regs->reg, regs->num, *hash);
+#ifdef DEBUG
+       debug("hash calculated:\n");
+       print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
+                      *hash, SHA256_SUM_LEN, false);
+#endif
+
+       return true;
+}
+
+static bool efi_hash_regions_in_der(efi_image_regions *regs, void **hash,
+                                   size_t *size)
+{
+       void *msg;
+       size_t msg_size;
+       struct image_region regtmp[2];
+
+       if (!efi_hash_regions(regs, &msg, &msg_size)) {
+               debug("Hash calculation failed\n");
+               return false;
+               ;
+       }
+
+       *size = 0;
+       *hash = calloc(1, SHA256_SUM_LEN);
+       if (!*hash) {
+               debug("Out of memory\n");
+               free(msg);
+               return false;
+       }
+       *size = SHA256_SUM_LEN;
+
+       /* File image hash is digested with some DER wrapper. */
+       regtmp[0].data = WinIndirectSha256;
+       regtmp[0].size = sizeof(WinIndirectSha256);
+       regtmp[1].data = msg;
+       regtmp[1].size = msg_size;
+
+       hash_calculate("sha256", regtmp, 2, *hash);
+#ifdef DEBUG
+       debug("hash calculated in der:\n");
+       print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
+                      *hash, SHA256_SUM_LEN, false);
+#endif
+
+       free(msg);
+
+       return true;
+}
+
+static bool efi_signature_verify(efi_image_regions *regs,
+                                struct pkcs7_signed_info *ps_info,
+                                struct x509_certificate *cert)
+{
+       struct image_sign_info info;
+       struct image_region regtmp[2];
+       void *hash;
+       size_t size;
+       char c;
+       bool verified;
+
+       debug("%s: Enter, %p, %p, %p(issuer: %s, subject: %s)\n", __func__,
+             regs, ps_info, cert, cert->issuer, cert->subject);
+
+       verified = false;
+
+       memset(&info, '\0', sizeof(info));
+       info.padding = image_get_padding_algo("pkcs-1.5");
+       /*
+        * Note: image_get_[checksum|crypto]_algo takes an string
+        * argument like "<checksum>,<crypto>"
+        */
+       if (!strcmp(ps_info->sig->hash_algo, "sha1")) {
+               info.checksum = image_get_checksum_algo("sha1,rsa2048");
+               info.name = "sha1,rsa2048";
+       } else if (!strcmp(ps_info->sig->hash_algo, "sha256")) {
+               info.checksum = image_get_checksum_algo("sha256,rsa2048");
+               info.name = "sha256,rsa2048";
+       } else {
+               debug("unknown msg digest algo: %s\n", ps_info->sig->hash_algo);
+               goto out;
+       }
+       info.crypto = image_get_crypto_algo(info.name);
+
+       info.key = cert->pub->key;
+       info.keylen = cert->pub->keylen;
+
+       /* verify signature */
+       debug("%s: crypto: %s, signature len:%x\n", __func__,
+             info.name, ps_info->sig->s_size);
+       if (ps_info->authattrs_len) {
+               debug("%s: RSA verify authentication attribute\n", __func__);
+               /*
+                * NOTE: This path will be executed only for
+                * PE image authentication
+                */
+
+               /* check if hash matches digest first */
+               debug("checking msg digest first, len:0x%x\n",
+                     ps_info->msgdigest_len);
+
+               if (efi_hash_regions_in_der(regs, &hash, &size)) {
+                       if (ps_info->msgdigest_len != size ||
+                           memcmp(hash, ps_info->msgdigest, size)) {
+                               debug("Digest doesn't match\n");
+                               free(hash);
+                               goto out;
+                       }
+
+                       free(hash);
+               } else {
+                       debug("Digesting image failed\n");
+                       goto out;
+               }
+
+               /* against digest */
+               c = 0x31;
+               regtmp[0].data = &c;
+               regtmp[0].size = 1;
+               regtmp[1].data = ps_info->authattrs;
+               regtmp[1].size = ps_info->authattrs_len;
+
+               if (!rsa_verify(&info, regtmp, 2,
+                               ps_info->sig->s, ps_info->sig->s_size))
+                       verified = true;
+       } else {
+               debug("%s: RSA verify content data\n", __func__);
+               /* against all data */
+               if (!rsa_verify(&info, regs->reg, regs->num,
+                               ps_info->sig->s, ps_info->sig->s_size))
+                       verified = true;
+       }
+
+out:
+       debug("%s: Exit, verified: %d\n", __func__, verified);
+       return verified;
+}
+
+static
+bool efi_signature_verify_with_list(efi_image_regions *regs,
+                                   struct pkcs7_signed_info *signed_info,
+                                   efi_signature_store *siglist)
+{
+       struct x509_certificate *cert;
+       struct efi_sig_data *sig_data;
+       bool verified = false;
+
+       debug("%s: Enter, %p, %p, %p\n", __func__, regs, signed_info, siglist);
+
+       if (!signed_info) {
+               void *hash;
+               size_t size;
+
+               debug("%s: unsigned image\n", __func__);
+               /* verify based on calculated hash value */
+               if (guidcmp(&siglist->sig_type, &efi_guid_sha256)) {
+                       debug("Digest algorithm is not supported: %pUl\n",
+                             &siglist->sig_type);
+                       goto out;
+               }
+
+               /* TODO: other than CERT_SHA256 */
+               if (!efi_hash_regions(regs, &hash, &size)) {
+                       debug("Digesting unsigned image failed\n");
+                       goto out;
+               }
+
+               /* go through the list */
+               for (sig_data = siglist->sig_data_list; sig_data;
+                    sig_data = sig_data->next) {
+#ifdef DEBUG
+                       debug("Msg digest in database:\n");
+                       print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
+                                      sig_data->data, sig_data->size, false);
+#endif
+                       if ((sig_data->size == size) &&
+                           !memcmp(sig_data->data, hash, size)) {
+                               verified = true;
+                               free(hash);
+                               goto out;
+                       }
+               }
+               free(hash);
+               goto out;
+       }
+
+       debug("%s: signed image\n", __func__);
+       if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) {
+               debug("Signature type is not supported: %pUl\n",
+                     &siglist->sig_type);
+               goto out;
+       }
+
+       /* go through the list */
+       for (sig_data = siglist->sig_data_list; sig_data;
+            sig_data = sig_data->next) {
+               /* TODO: owner check by policy? */
+
+               cert = x509_cert_parse(sig_data->data, sig_data->size);
+               if (IS_ERR(cert)) {
+                       debug("Parsing x509 certificate failed\n");
+                       goto out;
+               }
+
+               verified = efi_signature_verify(regs, signed_info, cert);
+               x509_free_certificate(cert);
+
+               if (verified)
+                       break;
+       }
+
+out:
+       debug("%s: Exit, verified: %d\n", __func__, verified);
+       return verified;
+}
+
+bool efi_signature_verify_with_db(efi_image_regions *regs,
+                                 struct pkcs7_message *msg,
+                                 efi_signature_store *trusted)
+{
+       struct pkcs7_signed_info *info;
+       efi_signature_store *siglist;
+       bool verified = false;
+
+       if (!trusted)
+               goto out;
+
+       if (!trusted->sig_data_list)
+               goto out;
+
+       /* for unsigned image */
+       if (!msg) {
+               for (siglist = trusted; siglist; siglist = siglist->next)
+                       if (efi_signature_verify_with_list(regs, NULL,
+                                                          siglist)) {
+                               verified = true;
+                               goto out;
+                       }
+
+               goto out;
+       }
+
+       /* signed image or variable */
+       for (info = msg->signed_infos; info; info = info->next) {
+               debug("Signed Info: digest algo: %s, pkey algo: %s\n",
+                     info->sig->hash_algo, info->sig->pkey_algo);
+
+               for (siglist = trusted; siglist; siglist = siglist->next) {
+                       if (efi_signature_verify_with_list(regs, info,
+                                                          siglist)) {
+                               verified = true;
+                               goto out;
+                       }
+               }
+       }
+
+out:
+       return verified;
+}
+
+/* TODO: TSA support */
+bool efi_signature_revoke(efi_image_regions *regs,
+                         struct pkcs7_message *msg,
+                         efi_signature_store *untrusted,
+                         efi_signature_store *tsa)
+{
+       struct pkcs7_signed_info *info;
+       efi_signature_store *siglist;
+       bool rejected = false;
+
+       if (!untrusted)
+               goto out;
+
+       if (!untrusted->sig_data_list)
+               goto out;
+
+       for (info = msg->signed_infos; info; info = info->next) {
+               debug("Signed Info: digest algo: %s, pkey algo: %s\n",
+                     info->sig->hash_algo, info->sig->pkey_algo);
+
+               for (siglist = untrusted; siglist; siglist = siglist->next) {
+                       if (efi_signature_verify_with_list(regs, info,
+                                                          siglist)) {
+                               rejected = true;
+                               goto out;
+                       }
+               }
+       }
+
+out:
+       return rejected;
+}
+
+/*
+ * Image region helper.  With this it's easier to record what parts
+ * of an image should be checksummed and then do the checksumming
+ * later depending on the hash.
+ */
+efi_status_t efi_image_region_add(efi_image_regions *ctx,
+                                 const void *start, const void *end,
+                                 int nocheck)
+{
+       struct image_region *reg;
+       int i, j;
+
+       if (ctx->num >= EFI_REGS_MAX) {
+               debug("%s: no more room for regions\n", __func__);
+               return EFI_OUT_OF_RESOURCES;
+       }
+
+       if (end < start)
+               return EFI_INVALID_PARAMETER;
+
+       for (i = 0; i < ctx->num; i++) {
+               reg = &ctx->reg[i];
+               if (nocheck)
+                       continue;
+
+               if (start > reg->data + reg->size)
+                       continue;
+
+               if ((start >= reg->data && start < reg->data + reg->size) ||
+                   (end > reg->data && end < reg->data + reg->size)) {
+                       debug("%s: new region already part of another\n",
+                             __func__);
+                       return EFI_INVALID_PARAMETER;
+               }
+
+               if (start < reg->data && end < reg->data + reg->size) {
+                       for (j = ctx->num - 1; j >= i; j--)
+                               memcpy(&ctx->reg[j], &ctx->reg[j + 1],
+                                      sizeof(*reg));
+                       break;
+               }
+       }
+
+       reg = &ctx->reg[i];
+       reg->data = start;
+       reg->size = end - start;
+       ctx->num++;
+
+       return EFI_SUCCESS;
+}
+
+void efi_sigstore_free(efi_signature_store *sigstore)
+{
+       efi_signature_store *sigstore_next;
+       struct efi_sig_data *sig_data, *sig_data_next;
+
+       while (sigstore) {
+               sigstore_next = sigstore->next;
+
+               /* TODO: more structured data? */
+               sig_data = sigstore->sig_data_list;
+               while (sig_data) {
+                       if (sig_data)
+                               sig_data_next = sig_data->next;
+                       free(sig_data->data);
+                       free(sig_data);
+                       sig_data = sig_data_next;
+               }
+
+               free(sigstore);
+               sigstore = sigstore_next;
+       }
+}
+
+static
+efi_signature_store *efi_sigstore_parse_siglist(struct efi_signature_list *esl)
+{
+       efi_signature_store *sigstore = NULL;
+       struct efi_sig_data *sig_data, *sig_data_next;
+       struct efi_signature_data *esd;
+       size_t left;
+
+       /*
+        * UEFI specification defines certificate types:
+        *   for non-signed images,
+        *      EFI_CERT_SHA256_GUID
+        *      EFI_CERT_RSA2048_GUID
+        *      EFI_CERT_RSA2048_SHA256_GUID
+        *      EFI_CERT_SHA1_GUID
+        *      EFI_CERT_RSA2048_SHA_GUID
+        *      EFI_CERT_SHA224_GUID
+        *      EFI_CERT_SHA384_GUID
+        *      EFI_CERT_SHA512_GUID
+        *
+        *   for signed images,
+        *      EFI_CERT_X509_GUID
+        *      NOTE: Each certificate will normally be in a separate
+        *      EFI_SIGNATURE_LIST as the size may vary depending on
+        *      its algo's.
+        *
+        *   for timestamp revocation of certificate,
+        *      EFI_CERT_X509_SHA512_GUID
+        *      EFI_CERT_X509_SHA256_GUID
+        *      EFI_CERT_X509_SHA384_GUID
+        */
+
+       if (esl->signature_list_size
+                       <= (sizeof(*esl) + esl->signature_header_size)) {
+               debug("Siglist in wrong format\n");
+               return NULL;
+       }
+
+       /* Create a head */
+       sigstore = calloc(sizeof(*sigstore), 1);
+       if (!sigstore) {
+               debug("Out of memory\n");
+               goto err;
+       }
+       memcpy(&sigstore->sig_type, &esl->signature_type, sizeof(efi_guid_t));
+
+       /* Go through the list */
+       sig_data_next = NULL;
+       left = esl->signature_list_size
+                       - (sizeof(*esl) + esl->signature_header_size);
+       esd = (struct efi_signature_data *)
+                       ((u8 *)esl + sizeof(*esl) + esl->signature_header_size);
+
+       while ((left > 0) && left >= esl->signature_size) {
+               /* Signature must exist if there is remaining data. */
+               if (left < esl->signature_size) {
+                       debug("Certificate is too small\n");
+                       goto err;
+               }
+
+               sig_data = calloc(esl->signature_size
+                                       - sizeof(esd->signature_owner), 1);
+               if (!sig_data) {
+                       debug("Out of memory\n");
+                       goto err;
+               }
+
+               /* Append signature data */
+               memcpy(&sig_data->owner, &esd->signature_owner,
+                      sizeof(efi_guid_t));
+               sig_data->size = esl->signature_size
+                                       - sizeof(esd->signature_owner);
+               sig_data->data = malloc(sig_data->size);
+               if (!sig_data->data) {
+                       debug("Out of memory\n");
+                       goto err;
+               }
+               memcpy(sig_data->data, esd->signature_data, sig_data->size);
+
+               sig_data->next = sig_data_next;
+               sig_data_next = sig_data;
+
+               /* Next */
+               esd = (struct efi_signature_data *)
+                               ((u8 *)esd + esl->signature_size);
+               left -= esl->signature_size;
+       }
+       sigstore->sig_data_list = sig_data_next;
+
+       return sigstore;
+
+err:
+       efi_sigstore_free(sigstore);
+
+       return NULL;
+}
+
+efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
+{
+       efi_signature_store *sigstore = NULL, *sigstore_list;
+       struct efi_signature_list *esl;
+       const efi_guid_t *vendor;
+       void *db;
+       efi_uintn_t db_size;
+       efi_status_t ret;
+
+       if (!u16_strcmp(name, L"PK") || !u16_strcmp(name, L"KEK")) {
+               vendor = &efi_global_variable_guid;
+       } else if (!u16_strcmp(name, L"db") || !u16_strcmp(name, L"dbx")) {
+               vendor = &efi_guid_image_security_database;
+       } else {
+               debug("unknown signature database, %ls\n", name);
+               return NULL;
+       }
+
+       /* retrieve variable data */
+       db_size = 0;
+       ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, NULL));
+       if (ret == EFI_NOT_FOUND) {
+               debug("variable, %ls, not found\n", name);
+               /*
+                * TODO:
+                * how should this condition be notified of to caller?
+                * Returning empty sigstore won't harm anything.
+                */
+               sigstore = calloc(sizeof(*sigstore), 1);
+
+               return sigstore;
+       } else if (ret != EFI_BUFFER_TOO_SMALL) {
+               debug("Getting variable, %ls, failed\n", name);
+               return NULL;
+       }
+
+       db = malloc(db_size);
+       if (!db) {
+               debug("Out of memory\n");
+               return NULL;
+       }
+
+       ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, db));
+       if (ret != EFI_SUCCESS) {
+               debug("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)) {
+                       debug("variable, %ls, in wrong format\n", name);
+                       goto err;
+               }
+
+               if (db_size < esl->signature_list_size) {
+                       debug("variable, %ls, in wrong format\n", name);
+                       goto err;
+               }
+
+               /* Parse a single siglist. */
+               sigstore_list = efi_sigstore_parse_siglist(esl);
+               if (!sigstore_list) {
+                       debug("Parsing signature list of %ls failed\n", name);
+                       goto err;
+               }
+
+               /* Append siglist */
+               sigstore_list->next = sigstore;
+               sigstore = sigstore_list;
+
+               /* Next */
+               db_size -= esl->signature_list_size;
+               esl = (void *)esl + esl->signature_list_size;
+       }
+       free(db);
+
+       return sigstore;
+
+err:
+       efi_sigstore_free(sigstore);
+       free(db);
+
+       return NULL;
+}
+#endif /* CONFIG_EFI_SECURE_BOOT */
-- 
2.21.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to