diff options
Diffstat (limited to 'lib/efi_loader/efi_signature.c')
| -rw-r--r-- | lib/efi_loader/efi_signature.c | 823 | 
1 files changed, 823 insertions, 0 deletions
| diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c new file mode 100644 index 00000000000..93a4f257016 --- /dev/null +++ b/lib/efi_loader/efi_signature.c @@ -0,0 +1,823 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se> + * Copyright (c) 2019 Linaro Limited, Author: AKASHI Takahiro + */ + +#define LOG_CATEGORY LOGC_EFI + +#include <charset.h> +#include <efi_loader.h> +#include <efi_variable.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> + +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_x509_sha384 = EFI_CERT_X509_SHA384_GUID; +const efi_guid_t efi_guid_cert_x509_sha512 = EFI_CERT_X509_SHA512_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 + */ +bool efi_hash_regions(struct image_region *regs, int count, +		      void **hash, const char *hash_algo, int *len) +{ +	int ret, hash_len; + +	if (!hash_algo) +		return false; + +	hash_len = algo_to_len(hash_algo); +	if (!hash_len) +		return false; + +	if (!*hash) { +		*hash = calloc(1, hash_len); +		if (!*hash) { +			EFI_PRINT("Out of memory\n"); +			return false; +		} +	} + +	ret = hash_calculate(hash_algo, regs, count, *hash); +	if (ret) +		return false; + +	if (len) +		*len = hash_len; +#ifdef DEBUG +	EFI_PRINT("hash calculated:\n"); +	print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1, +		       *hash, hash_len, false); +#endif + +	return true; +} + +/** + * hash_algo_supported - check if the requested hash algorithm is supported + * @guid: guid of the algorithm + * + * Return: true if supported false otherwise + */ +static bool hash_algo_supported(const efi_guid_t guid) +{ +	int i; +	const efi_guid_t unsupported_hashes[] = { +		 EFI_CERT_SHA1_GUID, +		 EFI_CERT_SHA224_GUID, +		 EFI_CERT_SHA384_GUID, +		 EFI_CERT_SHA512_GUID, +	}; + +	for (i = 0; i < ARRAY_SIZE(unsupported_hashes); i++) { +		if (!guidcmp(&unsupported_hashes[i], &guid)) +			return false; +	} + +	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 + * @dbx		Caller needs to set this to true if he is searching dbx + * + * 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, +				 bool dbx) + +{ +	struct efi_signature_store *siglist; +	struct efi_sig_data *sig_data; +	void *hash = NULL; +	bool found = false; +	bool hash_done = 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) { +		int len = 0; +		const char *hash_algo = NULL; +		/* +		 * if the hash algorithm is unsupported and we get an entry in +		 * dbx reject the image +		 */ +		if (dbx && !hash_algo_supported(siglist->sig_type)) { +			found = true; +			continue; +		}; +		/* +		 * Only support sha256 for now, that's what +		 * hash-to-efi-sig-list produces +		 */ +		if (guidcmp(&siglist->sig_type, &efi_guid_sha256)) +			continue; + +		hash_algo = guid_to_sha_str(&efi_guid_sha256); +		/* +		 * We could check size and hash_algo but efi_hash_regions() +		 * will do that for us +		 */ +		if (!hash_done && +		    !efi_hash_regions(regs->reg, regs->num, &hash, hash_algo, +				      &len)) { +			EFI_PRINT("Digesting an image failed\n"); +			break; +		} +		hash_done = true; + +		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 == len && +			    !memcmp(sig_data->data, hash, len)) { +				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; +	int len = 0; +	bool found = false; +	const char *hash_algo = NULL; + +	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; + +	/* We just need any sha256 algo to start the matching */ +	hash_algo = guid_to_sha_str(&efi_guid_sha256); +	if (!efi_hash_regions(reg, 1, &hash, hash_algo, &len)) +		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, hash_algo, +					      NULL)) +				goto out; + +			x509_free_certificate(cert_tmp); + +			if (!memcmp(hash, hash_tmp, len)) { +				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; +	int len = 0; +	time64_t revoc_time; +	bool revoked = false; +	const char *hash_algo = NULL; + +	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) { +		hash_algo = guid_to_sha_str(&siglist->sig_type); +		if (!hash_algo) +			continue; + +		/* calculate hash of TBSCertificate */ +		reg[0].data = cert->tbs; +		reg[0].size = cert->tbs_size; +		if (!efi_hash_regions(reg, 1, &hash, hash_algo, &len)) +			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 >= len) { +				EFI_PRINT("hash in db:\n"); +				print_hex_dump("    ", DUMP_PREFIX_OFFSET, +					       16, 1, +					       sig_data->data, len, false); +			} +#endif +			if ((sig_data->size < len + sizeof(time64_t)) || +			    memcmp(sig_data->data, hash, len)) +				continue; + +			memcpy(&revoc_time, sig_data->data + len, +			       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, +				      guid_to_sha_str(&efi_guid_sha256), +				      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 (efi_lookup_certificate(signer, db)) +			if (efi_signature_check_revocation(sinfo, signer, dbx)) +				break; +		if (!signer->self_signed && +		    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) +{ +	const efi_guid_t *vendor; +	void *db; +	efi_uintn_t db_size; + +	vendor = efi_auth_var_get_guid(name); +	db = efi_get_var(name, vendor, &db_size); +	if (!db) { +		EFI_PRINT("variable, %ls, not found\n", name); +		return calloc(sizeof(struct efi_signature_store), 1); +	} + +	return efi_build_signature_store(db, db_size); +} | 
