aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/lib/efi_loader/efi_signature.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/lib/efi_loader/efi_signature.c')
-rw-r--r--roms/u-boot/lib/efi_loader/efi_signature.c784
1 files changed, 784 insertions, 0 deletions
diff --git a/roms/u-boot/lib/efi_loader/efi_signature.c b/roms/u-boot/lib/efi_loader/efi_signature.c
new file mode 100644
index 000000000..bdd09881f
--- /dev/null
+++ b/roms/u-boot/lib/efi_loader/efi_signature.c
@@ -0,0 +1,784 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
+ * Copyright (c) 2019 Linaro Limited, Author: AKASHI Takahiro
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <efi_loader.h>
+#include <image.h>
+#include <hexdump.h>
+#include <malloc.h>
+#include <crypto/pkcs7.h>
+#include <crypto/pkcs7_parser.h>
+#include <crypto/public_key.h>
+#include <linux/compat.h>
+#include <linux/oid_registry.h>
+#include <u-boot/hash-checksum.h>
+#include <u-boot/rsa.h>
+#include <u-boot/sha256.h>
+
+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;
+const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
+
+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
+ * @regs: Array of regions
+ * @count: Number of regions
+ * @hash: Pointer to a pointer to buffer holding a hash value
+ * @size: Size of buffer to be returned
+ *
+ * Calculate a sha256 value of @regs and return a value in @hash.
+ *
+ * Return: true on success, false on error
+ */
+static bool efi_hash_regions(struct image_region *regs, int count,
+ void **hash, size_t *size)
+{
+ if (!*hash) {
+ *hash = calloc(1, SHA256_SUM_LEN);
+ if (!*hash) {
+ EFI_PRINT("Out of memory\n");
+ return false;
+ }
+ }
+ if (size)
+ *size = SHA256_SUM_LEN;
+
+ hash_calculate("sha256", regs, count, *hash);
+#ifdef DEBUG
+ EFI_PRINT("hash calculated:\n");
+ print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
+ *hash, SHA256_SUM_LEN, false);
+#endif
+
+ return true;
+}
+
+/**
+ * efi_signature_lookup_digest - search for an image's digest in sigdb
+ * @regs: List of regions to be authenticated
+ * @db: Signature database for trusted certificates
+ *
+ * A message digest of image pointed to by @regs is calculated and
+ * its hash value is compared to entries in signature database pointed
+ * to by @db.
+ *
+ * Return: true if found, false if not
+ */
+bool efi_signature_lookup_digest(struct efi_image_regions *regs,
+ struct efi_signature_store *db)
+{
+ struct efi_signature_store *siglist;
+ struct efi_sig_data *sig_data;
+ void *hash = NULL;
+ size_t size = 0;
+ bool found = false;
+
+ EFI_PRINT("%s: Enter, %p, %p\n", __func__, regs, db);
+
+ if (!regs || !db || !db->sig_data_list)
+ goto out;
+
+ for (siglist = db; siglist; siglist = siglist->next) {
+ /* TODO: support other hash algorithms */
+ if (guidcmp(&siglist->sig_type, &efi_guid_sha256)) {
+ EFI_PRINT("Digest algorithm is not supported: %pUl\n",
+ &siglist->sig_type);
+ break;
+ }
+
+ if (!efi_hash_regions(regs->reg, regs->num, &hash, &size)) {
+ EFI_PRINT("Digesting an image failed\n");
+ break;
+ }
+
+ for (sig_data = siglist->sig_data_list; sig_data;
+ sig_data = sig_data->next) {
+#ifdef DEBUG
+ EFI_PRINT("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)) {
+ found = true;
+ free(hash);
+ goto out;
+ }
+ }
+
+ free(hash);
+ hash = NULL;
+ }
+
+out:
+ EFI_PRINT("%s: Exit, found: %d\n", __func__, found);
+ return found;
+}
+
+/**
+ * efi_lookup_certificate - find a certificate within db
+ * @msg: Signature
+ * @db: Signature database
+ *
+ * Search signature database pointed to by @db and find a certificate
+ * pointed to by @cert.
+ *
+ * Return: true if found, false otherwise.
+ */
+static bool efi_lookup_certificate(struct x509_certificate *cert,
+ struct efi_signature_store *db)
+{
+ struct efi_signature_store *siglist;
+ struct efi_sig_data *sig_data;
+ struct image_region reg[1];
+ void *hash = NULL, *hash_tmp = NULL;
+ size_t size = 0;
+ bool found = false;
+
+ EFI_PRINT("%s: Enter, %p, %p\n", __func__, cert, db);
+
+ if (!cert || !db || !db->sig_data_list)
+ goto out;
+
+ /*
+ * TODO: identify a certificate using sha256 digest
+ * Is there any better way?
+ */
+ /* calculate hash of TBSCertificate */
+ reg[0].data = cert->tbs;
+ reg[0].size = cert->tbs_size;
+ if (!efi_hash_regions(reg, 1, &hash, &size))
+ goto out;
+
+ EFI_PRINT("%s: searching for %s\n", __func__, cert->subject);
+ for (siglist = db; siglist; siglist = siglist->next) {
+ /* only with x509 certificate */
+ if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509))
+ continue;
+
+ for (sig_data = siglist->sig_data_list; sig_data;
+ sig_data = sig_data->next) {
+ struct x509_certificate *cert_tmp;
+
+ cert_tmp = x509_cert_parse(sig_data->data,
+ sig_data->size);
+ if (IS_ERR_OR_NULL(cert_tmp))
+ continue;
+
+ EFI_PRINT("%s: against %s\n", __func__,
+ cert_tmp->subject);
+ reg[0].data = cert_tmp->tbs;
+ reg[0].size = cert_tmp->tbs_size;
+ if (!efi_hash_regions(reg, 1, &hash_tmp, NULL))
+ goto out;
+
+ x509_free_certificate(cert_tmp);
+
+ if (!memcmp(hash, hash_tmp, size)) {
+ found = true;
+ goto out;
+ }
+ }
+ }
+out:
+ free(hash);
+ free(hash_tmp);
+
+ EFI_PRINT("%s: Exit, found: %d\n", __func__, found);
+ return found;
+}
+
+/**
+ * efi_verify_certificate - verify certificate's signature with database
+ * @signer: Certificate
+ * @db: Signature database
+ * @root: Certificate to verify @signer
+ *
+ * Determine if certificate pointed to by @signer may be verified
+ * by one of certificates in signature database pointed to by @db.
+ *
+ * Return: true if certificate is verified, false otherwise.
+ */
+static bool efi_verify_certificate(struct x509_certificate *signer,
+ struct efi_signature_store *db,
+ struct x509_certificate **root)
+{
+ struct efi_signature_store *siglist;
+ struct efi_sig_data *sig_data;
+ struct x509_certificate *cert;
+ bool verified = false;
+ int ret;
+
+ EFI_PRINT("%s: Enter, %p, %p\n", __func__, signer, db);
+
+ if (!signer || !db || !db->sig_data_list)
+ goto out;
+
+ for (siglist = db; siglist; siglist = siglist->next) {
+ /* only with x509 certificate */
+ if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509))
+ continue;
+
+ for (sig_data = siglist->sig_data_list; sig_data;
+ sig_data = sig_data->next) {
+ cert = x509_cert_parse(sig_data->data, sig_data->size);
+ if (IS_ERR_OR_NULL(cert)) {
+ EFI_PRINT("Cannot parse x509 certificate\n");
+ continue;
+ }
+
+ ret = public_key_verify_signature(cert->pub,
+ signer->sig);
+ if (!ret) {
+ verified = true;
+ if (root)
+ *root = cert;
+ else
+ x509_free_certificate(cert);
+ goto out;
+ }
+ x509_free_certificate(cert);
+ }
+ }
+
+out:
+ EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified);
+ return verified;
+}
+
+/**
+ * efi_signature_check_revocation - check revocation with dbx
+ * @sinfo: Signer's info
+ * @cert: x509 certificate
+ * @dbx: Revocation signature database
+ *
+ * Search revocation signature database pointed to by @dbx and find
+ * an entry matching to certificate pointed to by @cert.
+ *
+ * While this entry contains revocation time, we don't support timestamp
+ * protocol at this time and any image will be unconditionally revoked
+ * when this match occurs.
+ *
+ * Return: true if check passed (not found), false otherwise.
+ */
+static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo,
+ struct x509_certificate *cert,
+ struct efi_signature_store *dbx)
+{
+ struct efi_signature_store *siglist;
+ struct efi_sig_data *sig_data;
+ struct image_region reg[1];
+ void *hash = NULL;
+ size_t size = 0;
+ time64_t revoc_time;
+ bool revoked = false;
+
+ EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, sinfo, cert, dbx);
+
+ if (!sinfo || !cert || !dbx || !dbx->sig_data_list)
+ goto out;
+
+ EFI_PRINT("Checking revocation against %s\n", cert->subject);
+ for (siglist = dbx; siglist; siglist = siglist->next) {
+ if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509_sha256))
+ continue;
+
+ /* calculate hash of TBSCertificate */
+ reg[0].data = cert->tbs;
+ reg[0].size = cert->tbs_size;
+ if (!efi_hash_regions(reg, 1, &hash, &size))
+ goto out;
+
+ for (sig_data = siglist->sig_data_list; sig_data;
+ sig_data = sig_data->next) {
+ /*
+ * struct efi_cert_x509_sha256 {
+ * u8 tbs_hash[256/8];
+ * time64_t revocation_time;
+ * };
+ */
+#ifdef DEBUG
+ if (sig_data->size >= size) {
+ EFI_PRINT("hash in db:\n");
+ print_hex_dump(" ", DUMP_PREFIX_OFFSET,
+ 16, 1,
+ sig_data->data, size, false);
+ }
+#endif
+ if ((sig_data->size < size + sizeof(time64_t)) ||
+ memcmp(sig_data->data, hash, size))
+ continue;
+
+ memcpy(&revoc_time, sig_data->data + size,
+ sizeof(revoc_time));
+ EFI_PRINT("revocation time: 0x%llx\n", revoc_time);
+ /*
+ * TODO: compare signing timestamp in sinfo
+ * with revocation time
+ */
+
+ revoked = true;
+ free(hash);
+ goto out;
+ }
+ free(hash);
+ hash = NULL;
+ }
+out:
+ EFI_PRINT("%s: Exit, revoked: %d\n", __func__, revoked);
+ return !revoked;
+}
+
+/*
+ * efi_signature_verify - verify signatures with db and dbx
+ * @regs: List of regions to be authenticated
+ * @msg: Signature
+ * @db: Signature database for trusted certificates
+ * @dbx: Revocation signature database
+ *
+ * All the signature pointed to by @msg against image pointed to by @regs
+ * will be verified by signature database pointed to by @db and @dbx.
+ *
+ * Return: true if verification for all signatures passed, false otherwise
+ */
+bool efi_signature_verify(struct efi_image_regions *regs,
+ struct pkcs7_message *msg,
+ struct efi_signature_store *db,
+ struct efi_signature_store *dbx)
+{
+ struct pkcs7_signed_info *sinfo;
+ struct x509_certificate *signer, *root;
+ bool verified = false;
+ int ret;
+
+ EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, regs, msg, db, dbx);
+
+ if (!regs || !msg || !db || !db->sig_data_list)
+ goto out;
+
+ for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) {
+ EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n",
+ sinfo->sig->hash_algo, sinfo->sig->pkey_algo);
+
+ /*
+ * only for authenticated variable.
+ *
+ * If this function is called for image,
+ * hash calculation will be done in
+ * pkcs7_verify_one().
+ */
+ if (!msg->data &&
+ !efi_hash_regions(regs->reg, regs->num,
+ (void **)&sinfo->sig->digest, NULL)) {
+ EFI_PRINT("Digesting an image failed\n");
+ goto out;
+ }
+
+ EFI_PRINT("Verifying certificate chain\n");
+ signer = NULL;
+ ret = pkcs7_verify_one(msg, sinfo, &signer);
+ if (ret == -ENOPKG)
+ continue;
+
+ if (ret < 0 || !signer)
+ goto out;
+
+ if (sinfo->blacklisted)
+ goto out;
+
+ EFI_PRINT("Verifying last certificate in chain\n");
+ if (signer->self_signed) {
+ if (efi_lookup_certificate(signer, db))
+ if (efi_signature_check_revocation(sinfo,
+ signer, dbx))
+ break;
+ } else if (efi_verify_certificate(signer, db, &root)) {
+ bool check;
+
+ check = efi_signature_check_revocation(sinfo, root,
+ dbx);
+ x509_free_certificate(root);
+ if (check)
+ break;
+ }
+
+ EFI_PRINT("Certificate chain didn't reach trusted CA\n");
+ }
+ if (sinfo)
+ verified = true;
+out:
+ EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified);
+ return verified;
+}
+
+/**
+ * efi_signature_check_signers - check revocation against all signers with dbx
+ * @msg: Signature
+ * @dbx: Revocation signature database
+ *
+ * Determine if none of signers' certificates in @msg are revoked
+ * by signature database pointed to by @dbx.
+ *
+ * Return: true if all signers passed, false otherwise.
+ */
+bool efi_signature_check_signers(struct pkcs7_message *msg,
+ struct efi_signature_store *dbx)
+{
+ struct pkcs7_signed_info *sinfo;
+ bool revoked = false;
+
+ EFI_PRINT("%s: Enter, %p, %p\n", __func__, msg, dbx);
+
+ if (!msg || !dbx)
+ goto out;
+
+ for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) {
+ if (sinfo->signer &&
+ !efi_signature_check_revocation(sinfo, sinfo->signer,
+ dbx)) {
+ revoked = true;
+ break;
+ }
+ }
+out:
+ EFI_PRINT("%s: Exit, revoked: %d\n", __func__, revoked);
+ return !revoked;
+}
+
+/**
+ * efi_sigstore_free - free signature store
+ * @sigstore: Pointer to signature store structure
+ *
+ * Feee all the memories held in signature store and itself,
+ * which were allocated by efi_sigstore_parse_sigdb().
+ */
+void efi_sigstore_free(struct efi_signature_store *sigstore)
+{
+ struct efi_signature_store *sigstore_next;
+ struct efi_sig_data *sig_data, *sig_data_next;
+
+ while (sigstore) {
+ sigstore_next = sigstore->next;
+
+ sig_data = sigstore->sig_data_list;
+ while (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;
+ }
+}
+
+/**
+ * efi_sigstore_parse_siglist - parse a signature list
+ * @name: Pointer to signature list
+ *
+ * Parse signature list and instantiate a signature store structure.
+ * Signature database is a simple concatenation of one or more
+ * signature list(s).
+ *
+ * Return: Pointer to signature store on success, NULL on error
+ */
+static struct efi_signature_store *
+efi_sigstore_parse_siglist(struct efi_signature_list *esl)
+{
+ struct efi_signature_store *siglist = 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)) {
+ EFI_PRINT("Siglist in wrong format\n");
+ return NULL;
+ }
+
+ /* Create a head */
+ siglist = calloc(sizeof(*siglist), 1);
+ if (!siglist) {
+ EFI_PRINT("Out of memory\n");
+ goto err;
+ }
+ memcpy(&siglist->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) {
+ /* Signature must exist if there is remaining data. */
+ if (left < esl->signature_size) {
+ EFI_PRINT("Certificate is too small\n");
+ goto err;
+ }
+
+ sig_data = calloc(esl->signature_size
+ - sizeof(esd->signature_owner), 1);
+ if (!sig_data) {
+ EFI_PRINT("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) {
+ EFI_PRINT("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;
+ }
+ siglist->sig_data_list = sig_data_next;
+
+ return siglist;
+
+err:
+ efi_sigstore_free(siglist);
+
+ return NULL;
+}
+
+/**
+ * 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
+ *
+ * Read in a value of signature database variable pointed to by
+ * @name, parse it and instantiate a signature store structure.
+ *
+ * Return: Pointer to signature store on success, NULL on error
+ */
+struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
+{
+ struct efi_signature_store *sigstore = NULL;
+ 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 {
+ EFI_PRINT("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) {
+ EFI_PRINT("variable, %ls, not found\n", name);
+ sigstore = calloc(sizeof(*sigstore), 1);
+ return sigstore;
+ } else if (ret != EFI_BUFFER_TOO_SMALL) {
+ EFI_PRINT("Getting variable, %ls, failed\n", name);
+ return NULL;
+ }
+
+ db = malloc(db_size);
+ if (!db) {
+ EFI_PRINT("Out of memory\n");
+ return NULL;
+ }
+
+ ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, db));
+ if (ret != EFI_SUCCESS) {
+ EFI_PRINT("Getting variable, %ls, failed\n", name);
+ free(db);
+ return NULL;
+ }
+
+ return efi_build_signature_store(db, db_size);
+}