
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.akashi@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 patrick@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 */