Merge tag 'efi-2020-10-rc3-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for efi-2020-10-rc3 (2)

This series includes bug fixes for:

* UEFI secure boot - images with multiple signatures
* UEFI secure boot - support for intermediate certificates
* corrections for UEFI unit tests
* missing loadaddr on MAIX board
diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index d00d424..9874838 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -1126,7 +1126,7 @@
 	efi_uintn_t exit_data_size = 0;
 	u16 *exit_data = NULL;
 	efi_status_t ret;
-	void *load_options;
+	void *load_options = NULL;
 
 	ret = efi_bootmgr_load(&image, &load_options);
 	printf("efi_bootmgr_load() returned: %ld\n", ret & ~EFI_ERROR_MASK);
diff --git a/include/configs/sipeed-maix.h b/include/configs/sipeed-maix.h
index a46473f..36ff522 100644
--- a/include/configs/sipeed-maix.h
+++ b/include/configs/sipeed-maix.h
@@ -21,4 +21,13 @@
 /* For early init */
 #define K210_SYSCTL_BASE 0x50440000
 
+#ifndef CONFIG_EXTRA_ENV_SETTINGS
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	"loadaddr=0x80060000\0" \
+	"fdt_addr_r=0x80028000\0" \
+	"scriptaddr=0x80020000\0" \
+	"kernel_addr_r=0x80060000\0" \
+	"fdtfile=kendryte/" CONFIG_DEFAULT_DEVICE_TREE ".dtb\0"
+#endif
+
 #endif /* CONFIGS_SIPEED_MAIX_H */
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 7f0ab1b..50a17a3 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -773,13 +773,16 @@
 
 bool efi_signature_lookup_digest(struct efi_image_regions *regs,
 				 struct efi_signature_store *db);
-bool efi_signature_verify_one(struct efi_image_regions *regs,
-			      struct pkcs7_message *msg,
-			      struct efi_signature_store *db);
-bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs,
-				     struct pkcs7_message *msg,
-				     struct efi_signature_store *db,
-				     struct efi_signature_store *dbx);
+bool efi_signature_verify(struct efi_image_regions *regs,
+			  struct pkcs7_message *msg,
+			  struct efi_signature_store *db,
+			  struct efi_signature_store *dbx);
+static inline bool efi_signature_verify_one(struct efi_image_regions *regs,
+					    struct pkcs7_message *msg,
+					    struct efi_signature_store *db)
+{
+	return efi_signature_verify(regs, msg, db, NULL);
+}
 bool efi_signature_check_signers(struct pkcs7_message *msg,
 				 struct efi_signature_store *dbx);
 
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 6017ffe..bad1a29 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -205,6 +205,7 @@
 	select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
 	select X509_CERTIFICATE_PARSER
 	select PKCS7_MESSAGE_PARSER
+	select PKCS7_VERIFY
 	default n
 	help
 	  Select this option to enable EFI secure boot support.
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index fef0bb8..eea42cc 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -546,6 +546,11 @@
 		goto err;
 	}
 
+	if (efi_signature_lookup_digest(regs, dbx)) {
+		EFI_PRINT("Image's digest was found in \"dbx\"\n");
+		goto err;
+	}
+
 	/*
 	 * go through WIN_CERTIFICATE list
 	 * NOTE:
@@ -553,10 +558,9 @@
 	 * in PE header, or as pkcs7 SignerInfo's in SignedData.
 	 * So the verification policy here is:
 	 *   - Success if, at least, one of signatures is verified
-	 *   - unless
-	 *       any of signatures is rejected explicitly, or
-	 *       none of digest algorithms are supported
+	 *   - unless signature is rejected explicitly with its digest.
 	 */
+
 	for (wincert = wincerts, wincerts_end = (u8 *)wincerts + wincerts_len;
 	     (u8 *)wincert < wincerts_end;
 	     wincert = (WIN_CERTIFICATE *)
@@ -627,32 +631,29 @@
 		/* try black-list first */
 		if (efi_signature_verify_one(regs, msg, dbx)) {
 			EFI_PRINT("Signature was rejected by \"dbx\"\n");
-			goto err;
+			continue;
 		}
 
 		if (!efi_signature_check_signers(msg, dbx)) {
 			EFI_PRINT("Signer(s) in \"dbx\"\n");
-			goto err;
-		}
-
-		if (efi_signature_lookup_digest(regs, dbx)) {
-			EFI_PRINT("Image's digest was found in \"dbx\"\n");
-			goto err;
+			continue;
 		}
 
 		/* try white-list */
-		if (efi_signature_verify_with_sigdb(regs, msg, db, dbx))
-			continue;
+		if (efi_signature_verify(regs, msg, db, dbx)) {
+			ret = true;
+			break;
+		}
 
 		debug("Signature was not verified by \"db\"\n");
 
-		if (efi_signature_lookup_digest(regs, db))
-			continue;
+		if (efi_signature_lookup_digest(regs, db)) {
+			ret = true;
+			break;
+		}
 
 		debug("Image's digest was not found in \"db\" or \"dbx\"\n");
-		goto err;
 	}
-	ret = true;
 
 err:
 	efi_sigstore_free(db);
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index fc0314e..79dee27 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -10,7 +10,9 @@
 #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/rsa.h>
@@ -61,143 +63,6 @@
 }
 
 /**
- * efi_hash_msg_content - calculate a hash value of contentInfo
- * @msg:	Signature
- * @hash:	Pointer to a pointer to buffer holding a hash value
- * @size:	Size of buffer to be returned
- *
- * Calculate a sha256 value of contentInfo in @msg and return a value in @hash.
- *
- * Return:	true on success, false on error
- */
-static bool efi_hash_msg_content(struct pkcs7_message *msg, void **hash,
-				 size_t *size)
-{
-	struct image_region regtmp;
-
-	regtmp.data = msg->data;
-	regtmp.size = msg->data_len;
-
-	return efi_hash_regions(&regtmp, 1, hash, size);
-}
-
-/**
- * efi_signature_verify - verify a signature with a certificate
- * @regs:		List of regions to be authenticated
- * @signed_info:	Pointer to PKCS7's signed_info
- * @cert:		x509 certificate
- *
- * Signature pointed to by @signed_info against image pointed to by @regs
- * is verified by a certificate pointed to by @cert.
- * @signed_info holds a signature, including a message digest which is to be
- * compared with a hash value calculated from @regs.
- *
- * Return:	true if signature is verified, false if not
- */
-static bool efi_signature_verify(struct efi_image_regions *regs,
-				 struct pkcs7_message *msg,
-				 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;
-
-	EFI_PRINT("%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>"
-	 * TODO: support other hash algorithms
-	 */
-	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 {
-		EFI_PRINT("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 */
-	EFI_PRINT("%s: crypto: %s, signature len:%x\n", __func__,
-		  info.name, ps_info->sig->s_size);
-	if (ps_info->aa_set & (1UL << sinfo_has_message_digest)) {
-		EFI_PRINT("%s: RSA verify authentication attribute\n",
-			  __func__);
-		/*
-		 * NOTE: This path will be executed only for
-		 * PE image authentication
-		 */
-
-		/* check if hash matches digest first */
-		EFI_PRINT("checking msg digest first, len:0x%x\n",
-			  ps_info->msgdigest_len);
-
-#ifdef DEBUG
-		EFI_PRINT("hash in database:\n");
-		print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
-			       ps_info->msgdigest, ps_info->msgdigest_len,
-			       false);
-#endif
-		/* against contentInfo first */
-		hash = NULL;
-		if ((msg->data && efi_hash_msg_content(msg, &hash, &size)) ||
-				/* for signed image */
-		    efi_hash_regions(regs->reg, regs->num, &hash, &size)) {
-				/* for authenticated variable */
-			if (ps_info->msgdigest_len != size ||
-			    memcmp(hash, ps_info->msgdigest, size)) {
-				EFI_PRINT("Digest doesn't match\n");
-				free(hash);
-				goto out;
-			}
-
-			free(hash);
-		} else {
-			EFI_PRINT("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 {
-		EFI_PRINT("%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:
-	EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified);
-	return verified;
-}
-
-/**
  * 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
@@ -260,61 +125,129 @@
 }
 
 /**
- * efi_signature_verify_with_list - verify a signature with signature list
- * @regs:		List of regions to be authenticated
- * @msg:		Signature
- * @signed_info:	Pointer to PKCS7's signed_info
- * @siglist:		Signature list for certificates
- * @valid_cert:		x509 certificate that verifies this signature
+ * efi_lookup_certificate - find a certificate within db
+ * @msg:	Signature
+ * @db:		Signature database
  *
- * Signature pointed to by @signed_info against image pointed to by @regs
- * is verified by signature list pointed to by @siglist.
- * Signature database is a simple concatenation of one or more
- * signature list(s).
+ * Search signature database pointed to by @db and find a certificate
+ * pointed to by @cert.
  *
- * Return:	true if signature is verified, false if not
+ * Return:	true if found, false otherwise.
  */
-static
-bool efi_signature_verify_with_list(struct efi_image_regions *regs,
-				    struct pkcs7_message *msg,
-				    struct pkcs7_signed_info *signed_info,
-				    struct efi_signature_store *siglist,
-				    struct x509_certificate **valid_cert)
+static bool efi_lookup_certificate(struct x509_certificate *cert,
+				   struct efi_signature_store *db)
 {
-	struct x509_certificate *cert;
+	struct efi_signature_store *siglist;
 	struct efi_sig_data *sig_data;
-	bool verified = false;
+	struct image_region reg[1];
+	void *hash = NULL, *hash_tmp = NULL;
+	size_t size = 0;
+	bool found = false;
 
-	EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__,
-		  regs, signed_info, siglist, valid_cert);
+	EFI_PRINT("%s: Enter, %p, %p\n", __func__, cert, db);
 
-	if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) {
-		EFI_PRINT("Signature type is not supported: %pUl\n",
-			  &siglist->sig_type);
+	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;
 
-	/* go through the list */
-	for (sig_data = siglist->sig_data_list; sig_data;
-	     sig_data = sig_data->next) {
-		/* TODO: support owner check based on policy */
+	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;
 
-		cert = x509_cert_parse(sig_data->data, sig_data->size);
-		if (IS_ERR(cert)) {
-			EFI_PRINT("Parsing x509 certificate failed\n");
-			goto out;
+		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;
+}
 
-		verified = efi_signature_verify(regs, msg, signed_info, cert);
+/**
+ * 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;
 
-		if (verified) {
-			if (valid_cert)
-				*valid_cert = cert;
-			else
-				x509_free_certificate(cert);
-			break;
+	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);
 		}
-		x509_free_certificate(cert);
 	}
 
 out:
@@ -335,7 +268,7 @@
  * protocol at this time and any image will be unconditionally revoked
  * when this match occurs.
  *
- * Return:	true if check passed, false otherwise.
+ * Return:	true if check passed (not found), false otherwise.
  */
 static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo,
 					   struct x509_certificate *cert,
@@ -405,58 +338,10 @@
 	return !revoked;
 }
 
-/**
- * efi_signature_verify_one - verify signatures with database
+/*
+ * efi_signature_verify - verify signatures with db and dbx
  * @regs:	List of regions to be authenticated
  * @msg:	Signature
- * @db:		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.
- *
- * Return:	true if verification for one of signatures passed, false
- *		otherwise
- */
-bool efi_signature_verify_one(struct efi_image_regions *regs,
-			      struct pkcs7_message *msg,
-			      struct efi_signature_store *db)
-{
-	struct pkcs7_signed_info *sinfo;
-	struct efi_signature_store *siglist;
-	struct x509_certificate *cert;
-	bool verified = false;
-
-	EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, regs, msg, db);
-
-	if (!db)
-		goto out;
-
-	if (!db->sig_data_list)
-		goto out;
-
-	EFI_PRINT("%s: Verify signed image with db\n", __func__);
-	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);
-
-		for (siglist = db; siglist; siglist = siglist->next)
-			if (efi_signature_verify_with_list(regs, msg, sinfo,
-							   siglist, &cert)) {
-				verified = true;
-				goto out;
-			}
-		EFI_PRINT("Valid certificate not in \"db\"\n");
-	}
-
-out:
-	EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified);
-	return verified;
-}
-
-/**
- * efi_signature_verify_with_sigdb - 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
  *
@@ -465,43 +350,71 @@
  *
  * Return:	true if verification for all signatures passed, false otherwise
  */
-bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs,
-				     struct pkcs7_message *msg,
-				     struct efi_signature_store *db,
-				     struct efi_signature_store *dbx)
+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 *info;
-	struct efi_signature_store *siglist;
-	struct x509_certificate *cert;
+	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 (info = msg->signed_infos; info; info = info->next) {
+	for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) {
 		EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n",
-			  info->sig->hash_algo, info->sig->pkey_algo);
+			  sinfo->sig->hash_algo, sinfo->sig->pkey_algo);
 
-		for (siglist = db; siglist; siglist = siglist->next) {
-			if (efi_signature_verify_with_list(regs, msg, info,
-							   siglist, &cert))
-				break;
-		}
-		if (!siglist) {
-			EFI_PRINT("Valid certificate not in \"db\"\n");
+		/*
+		 * 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;
 		}
 
-		if (!dbx || efi_signature_check_revocation(info, cert, dbx))
+		EFI_PRINT("Verifying certificate chain\n");
+		signer = NULL;
+		ret = pkcs7_verify_one(msg, sinfo, &signer);
+		if (ret == -ENOPKG)
 			continue;
 
-		EFI_PRINT("Certificate in \"dbx\"\n");
-		goto out;
-	}
-	verified = true;
+		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;
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index e509d6d..a10b9ca 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -37,16 +37,21 @@
  * 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)
+							  size_t buflen,
+							  u8 **tmpbuf)
 {
 	u8 *ebuf;
 	size_t ebuflen, len;
@@ -59,7 +64,9 @@
 	if (buflen > sizeof(pkcs7_hdr) &&
 	    !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
 		msg = pkcs7_parse_message(buf, buflen);
-		goto out;
+		if (IS_ERR(msg))
+			return NULL;
+		return msg;
 	}
 
 	/*
@@ -94,12 +101,12 @@
 
 	msg = pkcs7_parse_message(ebuf, ebuflen);
 
-	free(ebuf);
-
-out:
-	if (IS_ERR(msg))
+	if (IS_ERR(msg)) {
+		free(ebuf);
 		return NULL;
+	}
 
+	*tmpbuf = ebuf;
 	return msg;
 }
 
@@ -136,6 +143,7 @@
 	struct efi_time timestamp;
 	struct rtc_time tm;
 	u64 new_time;
+	u8 *ebuf;
 	enum efi_auth_var_type var_type;
 	efi_status_t ret;
 
@@ -143,6 +151,7 @@
 	truststore = NULL;
 	truststore2 = NULL;
 	regs = NULL;
+	ebuf = NULL;
 	ret = EFI_SECURITY_VIOLATION;
 
 	if (*data_size < sizeof(struct efi_variable_authentication_2))
@@ -204,9 +213,12 @@
 	/* variable's signature list */
 	if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info))
 		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));
+						   - sizeof(auth->auth_info),
+					       &ebuf);
 	if (!var_sig) {
 		EFI_PRINT("Parsing variable's signature failed\n");
 		goto err;
@@ -241,12 +253,11 @@
 	}
 
 	/* verify signature */
-	if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) {
+	if (efi_signature_verify(regs, var_sig, truststore, NULL)) {
 		EFI_PRINT("Verified\n");
 	} else {
 		if (truststore2 &&
-		    efi_signature_verify_with_sigdb(regs, var_sig,
-						    truststore2, NULL)) {
+		    efi_signature_verify(regs, var_sig, truststore2, NULL)) {
 			EFI_PRINT("Verified\n");
 		} else {
 			EFI_PRINT("Verifying variable's signature failed\n");
@@ -262,6 +273,7 @@
 	efi_sigstore_free(truststore);
 	efi_sigstore_free(truststore2);
 	pkcs7_free_message(var_sig);
+	free(ebuf);
 	free(regs);
 
 	return ret;
@@ -496,10 +508,6 @@
 	if (ret != EFI_SUCCESS)
 		return ret;
 
-	ret = efi_init_secure_state();
-	if (ret != EFI_SUCCESS)
-		return ret;
-
 	if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) {
 		ret = efi_var_restore((struct efi_var_file *)
 				      __efi_var_file_begin);
@@ -507,5 +515,9 @@
 			log_err("Invalid EFI variable seed\n");
 	}
 
-	return efi_var_from_file();
+	ret = efi_var_from_file();
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	return efi_init_secure_state();
 }
diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py
index c0943b6..69a498c 100644
--- a/test/py/tests/test_efi_secboot/conftest.py
+++ b/test/py/tests/test_efi_secboot/conftest.py
@@ -25,13 +25,8 @@
     Return:
         A path to disk image to be used for testing
     """
-    global HELLO_PATH
-
     image_path = u_boot_config.persistent_data_dir
-    image_path = image_path + '/' + EFI_SECBOOT_IMAGE_NAME
-
-    if HELLO_PATH == '':
-        HELLO_PATH = u_boot_config.build_dir + '/lib/efi_loader/helloworld.efi'
+    image_path = image_path + '/test_efi_secboot.img'
 
     try:
         mnt_point = u_boot_config.build_dir + '/mnt_efisecure'
@@ -75,9 +70,6 @@
         check_call('cd %s; %scert-to-efi-sig-list -g %s db1.crt db1.esl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key db db1.esl db1.auth'
                    % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
                    shell=True)
-        # db1-update
-        check_call('cd %s; %ssign-efi-sig-list -t "2020-04-06" -a -c KEK.crt -k KEK.key db db1.esl db1-update.auth'
-                   % (mnt_point, EFITOOLS_PATH), shell=True)
         # dbx (TEST_dbx certificate)
         check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_dbx/ -keyout dbx.key -out dbx.crt -nodes -days 365'
                    % mnt_point, shell=True)
@@ -89,7 +81,7 @@
                    % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
                    shell=True)
         # dbx_hash1 (digest of TEST_db1 certificate)
-        check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 256 db1.crt dbx_hash1.crl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx dbx_hash1.crl dbx_hash1.auth'
+        check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 256 db1.crt dbx_hash1.crl; %ssign-efi-sig-list -t "2020-04-06" -c KEK.crt -k KEK.key dbx dbx_hash1.crl dbx_hash1.auth'
                    % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
                    shell=True)
         # dbx_db (with TEST_db certificate)
@@ -98,7 +90,8 @@
                    shell=True)
 
         # Copy image
-        check_call('cp %s %s' % (HELLO_PATH, mnt_point), shell=True)
+        check_call('cp %s/lib/efi_loader/helloworld.efi %s' %
+                   (u_boot_config.build_dir, mnt_point), shell=True)
 
         # Sign image
         check_call('cd %s; sbsign --key db.key --cert db.crt helloworld.efi'
@@ -128,3 +121,119 @@
         yield image_path
     finally:
         call('rm -f %s' % image_path, shell=True)
+
+#
+# Fixture for UEFI secure boot test of intermediate certificates
+#
+
+
+@pytest.fixture(scope='session')
+def efi_boot_env_intca(request, u_boot_config):
+    """Set up a file system to be used in UEFI secure boot test
+    of intermediate certificates.
+
+    Args:
+        request: Pytest request object.
+        u_boot_config: U-boot configuration.
+
+    Return:
+        A path to disk image to be used for testing
+    """
+    image_path = u_boot_config.persistent_data_dir
+    image_path = image_path + '/test_efi_secboot_intca.img'
+
+    try:
+        mnt_point = u_boot_config.persistent_data_dir + '/mnt_efi_secboot_intca'
+        check_call('rm -rf {}'.format(mnt_point), shell=True)
+        check_call('mkdir -p {}'.format(mnt_point), shell=True)
+
+        # Create signature database
+        # PK
+        check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ -keyout PK.key -out PK.crt -nodes -days 365'
+                   % mnt_point, shell=True)
+        check_call('cd %s; %scert-to-efi-sig-list -g %s PK.crt PK.esl; %ssign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth'
+                   % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
+                   shell=True)
+        # KEK
+        check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ -keyout KEK.key -out KEK.crt -nodes -days 365'
+                   % mnt_point, shell=True)
+        check_call('cd %s; %scert-to-efi-sig-list -g %s KEK.crt KEK.esl; %ssign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth'
+                   % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
+                   shell=True)
+
+        # We will have three-tier hierarchy of certificates:
+        #   TestRoot: Root CA (self-signed)
+        #   TestSub: Intermediate CA (signed by Root CA)
+        #   TestCert: User certificate (signed by Intermediate CA, and used
+        #             for signing an image)
+        #
+        # NOTE:
+        # I consulted the following EDK2 document for certificate options:
+        #     BaseTools/Source/Python/Pkcs7Sign/Readme.md
+        # Please not use them as they are in product system. They are
+        # for test purpose only.
+
+        # TestRoot
+        check_call('cp %s/test/py/tests/test_efi_secboot/openssl.cnf %s'
+                   % (u_boot_config.source_dir, mnt_point), shell=True)
+        check_call('cd %s; export OPENSSL_CONF=./openssl.cnf; openssl genrsa -out TestRoot.key 2048; openssl req -extensions v3_ca -new -x509 -days 365 -key TestRoot.key -out TestRoot.crt -subj "/CN=TEST_root/"; touch index.txt; touch index.txt.attr'
+                   % mnt_point, shell=True)
+        # TestSub
+        check_call('cd %s; touch serial.new; export OPENSSL_CONF=./openssl.cnf; openssl genrsa -out TestSub.key 2048; openssl req -new -key TestSub.key -out TestSub.csr -subj "/CN=TEST_sub/"; openssl ca -in TestSub.csr -out TestSub.crt -extensions v3_int_ca -days 365 -batch -rand_serial -cert TestRoot.crt -keyfile TestRoot.key'
+                   % mnt_point, shell=True)
+        # TestCert
+        check_call('cd %s; touch serial.new; export OPENSSL_CONF=./openssl.cnf; openssl genrsa -out TestCert.key 2048; openssl req -new -key TestCert.key -out TestCert.csr -subj "/CN=TEST_cert/"; openssl ca -in TestCert.csr -out TestCert.crt -extensions usr_cert -days 365 -batch -rand_serial -cert TestSub.crt -keyfile TestSub.key'
+                   % mnt_point, shell=True)
+        # db
+        #  for TestCert
+        check_call('cd %s; %scert-to-efi-sig-list -g %s TestCert.crt TestCert.esl; %ssign-efi-sig-list -c KEK.crt -k KEK.key db TestCert.esl db_a.auth'
+                   % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
+                   shell=True)
+        #  for TestSub
+        check_call('cd %s; %scert-to-efi-sig-list -g %s TestSub.crt TestSub.esl; %ssign-efi-sig-list -t "2020-07-16" -c KEK.crt -k KEK.key db TestSub.esl db_b.auth'
+                   % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
+                   shell=True)
+        #  for TestRoot
+        check_call('cd %s; %scert-to-efi-sig-list -g %s TestRoot.crt TestRoot.esl; %ssign-efi-sig-list -t "2020-07-17" -c KEK.crt -k KEK.key db TestRoot.esl db_c.auth'
+                   % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
+                   shell=True)
+        ## dbx (hash of certificate with revocation time)
+        #  for TestCert
+        check_call('cd %s; %scert-to-efi-hash-list -g %s -t "2020-07-20" -s 256 TestCert.crt TestCert.crl; %ssign-efi-sig-list -c KEK.crt -k KEK.key dbx TestCert.crl dbx_a.auth'
+                   % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
+                   shell=True)
+        #  for TestSub
+        check_call('cd %s; %scert-to-efi-hash-list -g %s -t "2020-07-21" -s 256 TestSub.crt TestSub.crl; %ssign-efi-sig-list -t "2020-07-18" -c KEK.crt -k KEK.key dbx TestSub.crl dbx_b.auth'
+                   % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
+                   shell=True)
+        #  for TestRoot
+        check_call('cd %s; %scert-to-efi-hash-list -g %s -t "2020-07-22" -s 256 TestRoot.crt TestRoot.crl; %ssign-efi-sig-list -t "2020-07-19" -c KEK.crt -k KEK.key dbx TestRoot.crl dbx_c.auth'
+                   % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
+                   shell=True)
+
+        # Sign image
+        # additional intermediate certificates may be included
+        # in SignedData
+
+        check_call('cp %s/lib/efi_loader/helloworld.efi %s' %
+                   (u_boot_config.build_dir, mnt_point), shell=True)
+        # signed by TestCert
+        check_call('cd %s; %ssbsign --key TestCert.key --cert TestCert.crt --out helloworld.efi.signed_a helloworld.efi'
+                   % (mnt_point, SBSIGN_PATH), shell=True)
+        # signed by TestCert with TestSub in signature
+        check_call('cd %s; %ssbsign --key TestCert.key --cert TestCert.crt --addcert TestSub.crt --out helloworld.efi.signed_ab helloworld.efi'
+                   % (mnt_point, SBSIGN_PATH), shell=True)
+        # signed by TestCert with TestSub and TestRoot in signature
+        check_call('cd %s; cat TestSub.crt TestRoot.crt > TestSubRoot.crt; %ssbsign --key TestCert.key --cert TestCert.crt --addcert TestSubRoot.crt --out helloworld.efi.signed_abc helloworld.efi'
+                   % (mnt_point, SBSIGN_PATH), shell=True)
+
+        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat {} {}'.format(mnt_point, image_path), shell=True)
+        check_call('rm -rf {}'.format(mnt_point), shell=True)
+
+    except CalledProcessError as e:
+        pytest.skip('Setup failed: %s' % e.cmd)
+        return
+    else:
+        yield image_path
+    finally:
+        call('rm -f %s' % image_path, shell=True)
diff --git a/test/py/tests/test_efi_secboot/defs.py b/test/py/tests/test_efi_secboot/defs.py
index ba6b9f3..b7a2a11 100644
--- a/test/py/tests/test_efi_secboot/defs.py
+++ b/test/py/tests/test_efi_secboot/defs.py
@@ -1,14 +1,14 @@
 # SPDX-License-Identifier:      GPL-2.0+
 
-# Disk image name
-EFI_SECBOOT_IMAGE_NAME = 'test_efi_secboot.img'
-
 # Owner guid
 GUID = '11111111-2222-3333-4444-123456789abc'
 
 # v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
 # you need build a newer version on your own.
+# The path must terminate with '/'.
 EFITOOLS_PATH = ''
 
-# Hello World application for sandbox
-HELLO_PATH = ''
+# "--addcert" option of sbsign must be available, otherwise
+# you need build a newer version on your own.
+# The path must terminate with '/'.
+SBSIGN_PATH = ''
diff --git a/test/py/tests/test_efi_secboot/openssl.cnf b/test/py/tests/test_efi_secboot/openssl.cnf
new file mode 100644
index 0000000..f684f1d
--- /dev/null
+++ b/test/py/tests/test_efi_secboot/openssl.cnf
@@ -0,0 +1,48 @@
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+new_certs_dir = .
+database = ./index.txt
+serial = ./serial
+default_md = sha256
+policy = policy_min
+
+[ req ]
+distinguished_name = def_distinguished_name
+
+[def_distinguished_name]
+
+# Extensions
+#   -addext " ... = ..."
+#
+[ v3_ca ]
+   # Extensions for a typical Root CA.
+   basicConstraints = critical,CA:TRUE
+   keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+   subjectKeyIdentifier = hash
+   authorityKeyIdentifier = keyid:always,issuer
+
+[ v3_int_ca ]
+   # Extensions for a typical intermediate CA.
+   basicConstraints = critical, CA:TRUE
+   keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+   subjectKeyIdentifier = hash
+   authorityKeyIdentifier = keyid:always,issuer
+
+[ usr_cert ]
+   # Extensions for user end certificates.
+   basicConstraints = CA:FALSE
+   keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+   extendedKeyUsage = clientAuth, emailProtection
+   subjectKeyIdentifier = hash
+   authorityKeyIdentifier = keyid,issuer
+
+[ policy_min ]
+   countryName		= optional
+   stateOrProvinceName	= optional
+   localityName		= optional
+   organizationName	= optional
+   organizationalUnitName = optional
+   commonName		= supplied
+   emailAddress		= optional
diff --git a/test/py/tests/test_efi_secboot/test_signed.py b/test/py/tests/test_efi_secboot/test_signed.py
index 7531bba..1443ba7 100644
--- a/test/py/tests/test_efi_secboot/test_signed.py
+++ b/test/py/tests/test_efi_secboot/test_signed.py
@@ -157,7 +157,8 @@
         u_boot_console.restart_uboot()
         disk_img = efi_boot_env
         with u_boot_console.log.section('Test Case 5a'):
-            # Test Case 5a, rejected if any of signatures is not verified
+            # Test Case 5a, authenticated even if only one of signatures
+            # is verified
             output = u_boot_console.run_command_list([
                 'host bind 0 %s' % disk_img,
                 'fatload host 0:1 4000000 db.auth',
@@ -171,8 +172,7 @@
                 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""',
                 'efidebug boot next 1',
                 'efidebug test bootmgr'])
-            assert '\'HELLO\' failed' in ''.join(output)
-            assert 'efi_start_image() returned: 26' in ''.join(output)
+            assert 'Hello, world!' in ''.join(output)
 
         with u_boot_console.log.section('Test Case 5b'):
             # Test Case 5b, authenticated if both signatures are verified
@@ -181,19 +181,29 @@
                 'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize db'])
             assert 'Failed to set EFI variable' not in ''.join(output)
             output = u_boot_console.run_command_list([
-                'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""',
                 'efidebug boot next 1',
-                'bootefi bootmgr'])
+                'efidebug test bootmgr'])
             assert 'Hello, world!' in ''.join(output)
 
         with u_boot_console.log.section('Test Case 5c'):
-            # Test Case 5c, rejected if any of signatures is revoked
+            # Test Case 5c, not rejected if one of signatures (digest of
+            # certificate) is revoked
             output = u_boot_console.run_command_list([
-                'fatload host 0:1 4000000 dbx_hash1.auth',
+                'fatload host 0:1 4000000 dbx_hash.auth',
                 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx'])
             assert 'Failed to set EFI variable' not in ''.join(output)
             output = u_boot_console.run_command_list([
-                'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""',
+                'efidebug boot next 1',
+                'efidebug test bootmgr'])
+            assert 'Hello, world!' in ''.join(output)
+
+        with u_boot_console.log.section('Test Case 5d'):
+            # Test Case 5d, rejected if both of signatures are revoked
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 dbx_hash1.auth',
+                'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize dbx'])
+            assert 'Failed to set EFI variable' not in ''.join(output)
+            output = u_boot_console.run_command_list([
                 'efidebug boot next 1',
                 'efidebug test bootmgr'])
             assert '\'HELLO\' failed' in ''.join(output)
diff --git a/test/py/tests/test_efi_secboot/test_signed_intca.py b/test/py/tests/test_efi_secboot/test_signed_intca.py
new file mode 100644
index 0000000..1e5f4d0
--- /dev/null
+++ b/test/py/tests/test_efi_secboot/test_signed_intca.py
@@ -0,0 +1,135 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2020, Linaro Limited
+# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+#
+# U-Boot UEFI: Image Authentication Test (signature with certificates chain)
+
+"""
+This test verifies image authentication for a signed image which is signed
+by user certificate and contains additional intermediate certificates in its
+signature.
+"""
+
+import pytest
+
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('efi_secure_boot')
+@pytest.mark.buildconfigspec('cmd_efidebug')
+@pytest.mark.buildconfigspec('cmd_fat')
+@pytest.mark.buildconfigspec('cmd_nvedit_efi')
+@pytest.mark.slow
+class TestEfiSignedImageIntca(object):
+    def test_efi_signed_image_intca1(self, u_boot_console, efi_boot_env_intca):
+        """
+        Test Case 1 - authenticated by root CA in db
+        """
+        u_boot_console.restart_uboot()
+        disk_img = efi_boot_env_intca
+        with u_boot_console.log.section('Test Case 1a'):
+            # Test Case 1a, with no Int CA and not authenticated by root CA
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatload host 0:1 4000000 db_c.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize db',
+                'fatload host 0:1 4000000 KEK.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK',
+                'fatload host 0:1 4000000 PK.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK'])
+            assert 'Failed to set EFI variable' not in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'efidebug boot add 1 HELLO_a host 0:1 /helloworld.efi.signed_a ""',
+                'efidebug boot next 1',
+                'efidebug test bootmgr'])
+            assert '\'HELLO_a\' failed' in ''.join(output)
+            assert 'efi_start_image() returned: 26' in ''.join(output)
+
+        with u_boot_console.log.section('Test Case 1b'):
+            # Test Case 1b, signed and authenticated by root CA
+            output = u_boot_console.run_command_list([
+                'efidebug boot add 2 HELLO_ab host 0:1 /helloworld.efi.signed_ab ""',
+                'efidebug boot next 2',
+                'bootefi bootmgr'])
+            assert 'Hello, world!' in ''.join(output)
+
+    def test_efi_signed_image_intca2(self, u_boot_console, efi_boot_env_intca):
+        """
+        Test Case 2 - authenticated by root CA in db
+        """
+        u_boot_console.restart_uboot()
+        disk_img = efi_boot_env_intca
+        with u_boot_console.log.section('Test Case 2a'):
+            # Test Case 2a, unsigned and not authenticated by root CA
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatload host 0:1 4000000 KEK.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK',
+                'fatload host 0:1 4000000 PK.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK'])
+            assert 'Failed to set EFI variable' not in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'efidebug boot add 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc ""',
+                'efidebug boot next 1',
+                'efidebug test bootmgr'])
+            assert '\'HELLO_abc\' failed' in ''.join(output)
+            assert 'efi_start_image() returned: 26' in ''.join(output)
+
+        with u_boot_console.log.section('Test Case 2b'):
+            # Test Case 2b, signed and authenticated by root CA
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 db_b.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize db',
+                'efidebug boot next 1',
+                'efidebug test bootmgr'])
+            assert '\'HELLO_abc\' failed' in ''.join(output)
+            assert 'efi_start_image() returned: 26' in ''.join(output)
+
+        with u_boot_console.log.section('Test Case 2c'):
+            # Test Case 2c, signed and authenticated by root CA
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 db_c.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize db',
+                'efidebug boot next 1',
+                'efidebug test bootmgr'])
+            assert 'Hello, world!' in ''.join(output)
+
+    def test_efi_signed_image_intca3(self, u_boot_console, efi_boot_env_intca):
+        """
+        Test Case 3 - revoked by dbx
+        """
+        u_boot_console.restart_uboot()
+        disk_img = efi_boot_env_intca
+        with u_boot_console.log.section('Test Case 3a'):
+            # Test Case 3a, revoked by int CA in dbx
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatload host 0:1 4000000 dbx_b.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx',
+                'fatload host 0:1 4000000 db_c.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize db',
+                'fatload host 0:1 4000000 KEK.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK',
+                'fatload host 0:1 4000000 PK.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK'])
+            assert 'Failed to set EFI variable' not in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'efidebug boot add 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc ""',
+                'efidebug boot next 1',
+                'efidebug test bootmgr'])
+            assert 'Hello, world!' in ''.join(output)
+            # Or,
+            # assert '\'HELLO_abc\' failed' in ''.join(output)
+            # assert 'efi_start_image() returned: 26' in ''.join(output)
+
+        with u_boot_console.log.section('Test Case 3b'):
+            # Test Case 3b, revoked by root CA in dbx
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 dbx_c.auth',
+                'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx',
+                'efidebug boot next 1',
+                'efidebug test bootmgr'])
+            assert '\'HELLO_abc\' failed' in ''.join(output)
+            assert 'efi_start_image() returned: 26' in ''.join(output)