Blame SOURCES/0057-Add-support-for-vendor_db-built-in-shim-authorized-l.patch

00e791
From dd3a5d71252a1f94e37f1a4c8841d253630b305a Mon Sep 17 00:00:00 2001
00e791
From: Peter Jones <pjones@redhat.com>
00e791
Date: Thu, 23 Jul 2020 12:36:56 -0400
00e791
Subject: [PATCH 57/62] Add support for vendor_db built-in shim authorized
00e791
 list.
00e791
00e791
Potential new signing strategies ( for example signing grub, fwupdate
00e791
and vmlinuz with separate certificates ) require shim to support a
00e791
vendor provided bundle of trusted certificates and hashes, which allows
00e791
shim to trust EFI binaries matching either certificate by signature or
00e791
hash in the vendor_db.  Functionality is similar to vendor_dbx.
00e791
00e791
This also improves the mirroring quite a bit.
00e791
Upstream: pr#206
00e791
---
00e791
 lib/variables.c     |  55 +++--
00e791
 mok.c               | 502 ++++++++++++++++++++++++++++++--------------
00e791
 shim.c              |  27 +++
00e791
 include/console.h   |   3 +-
00e791
 include/variables.h |   9 +-
00e791
 shim.h              |   7 +-
00e791
 cert.S              |  13 +-
00e791
 Make.defaults       |   3 +
00e791
 README.tpm          |   1 +
00e791
 9 files changed, 437 insertions(+), 183 deletions(-)
00e791
00e791
diff --git a/lib/variables.c b/lib/variables.c
00e791
index 9c2e7d0ac2d..8123ae60fc9 100644
00e791
--- a/lib/variables.c
00e791
+++ b/lib/variables.c
00e791
@@ -25,32 +25,59 @@
00e791
 #include "shim.h"
00e791
 
00e791
 EFI_STATUS
00e791
-variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner,
00e791
-		    void **out, int *outlen)
00e791
+fill_esl(const uint8_t *data, const size_t data_len,
00e791
+	 const EFI_GUID *type, const EFI_GUID *owner,
00e791
+	 uint8_t *out, size_t *outlen)
00e791
 {
00e791
-	*outlen = cert_len + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
00e791
+	EFI_SIGNATURE_LIST *sl;
00e791
+	EFI_SIGNATURE_DATA *sd;
00e791
+	size_t needed = 0;
00e791
 
00e791
-	*out = AllocateZeroPool(*outlen);
00e791
-	if (!*out)
00e791
-		return EFI_OUT_OF_RESOURCES;
00e791
+	if (!data || !data_len || !type || !outlen)
00e791
+		return EFI_INVALID_PARAMETER;
00e791
 
00e791
-	EFI_SIGNATURE_LIST *sl = *out;
00e791
+	needed = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) + data_len;
00e791
+	if (!out || *outlen < needed) {
00e791
+		*outlen = needed;
00e791
+		return EFI_BUFFER_TOO_SMALL;
00e791
+	}
00e791
+
00e791
+	*outlen = needed;
00e791
+	sl = (EFI_SIGNATURE_LIST *)out;
00e791
 
00e791
 	sl->SignatureHeaderSize = 0;
00e791
 	sl->SignatureType = *type;
00e791
-	sl->SignatureSize = cert_len + sizeof(EFI_GUID);
00e791
-	sl->SignatureListSize = *outlen;
00e791
-
00e791
-	EFI_SIGNATURE_DATA *sd = *out + sizeof(EFI_SIGNATURE_LIST);
00e791
+	sl->SignatureSize = sizeof(EFI_GUID) + data_len;
00e791
+	sl->SignatureListSize = needed;
00e791
 
00e791
+	sd = (EFI_SIGNATURE_DATA *)(out + sizeof(EFI_SIGNATURE_LIST));
00e791
 	if (owner)
00e791
 		sd->SignatureOwner = *owner;
00e791
 
00e791
-	CopyMem(sd->SignatureData, cert, cert_len);
00e791
+	CopyMem(sd->SignatureData, data, data_len);
00e791
 
00e791
 	return EFI_SUCCESS;
00e791
 }
00e791
 
00e791
+EFI_STATUS
00e791
+variable_create_esl(const uint8_t *data, const size_t data_len,
00e791
+		    const EFI_GUID *type, const EFI_GUID *owner,
00e791
+		    uint8_t **out, size_t *outlen)
00e791
+{
00e791
+	EFI_STATUS efi_status;
00e791
+
00e791
+	*outlen = 0;
00e791
+	efi_status = fill_esl(data, data_len, type, owner, NULL, outlen);
00e791
+	if (efi_status != EFI_BUFFER_TOO_SMALL)
00e791
+		return efi_status;
00e791
+
00e791
+	*out = AllocateZeroPool(*outlen);
00e791
+	if (!*out)
00e791
+		return EFI_OUT_OF_RESOURCES;
00e791
+
00e791
+	return fill_esl(data, data_len, type, owner, *out, outlen);
00e791
+}
00e791
+
00e791
 EFI_STATUS
00e791
 CreateTimeBasedPayload(IN OUT UINTN * DataSize, IN OUT UINT8 ** Data)
00e791
 {
00e791
@@ -137,9 +164,9 @@ SetSecureVariable(CHAR16 *var, UINT8 *Data, UINTN len, EFI_GUID owner,
00e791
 		return EFI_SECURITY_VIOLATION;
00e791
 
00e791
 	if (createtimebased) {
00e791
-		int ds;
00e791
+		size_t ds;
00e791
 		efi_status = variable_create_esl(Data, len, &X509_GUID, NULL,
00e791
-						 (void **)&Cert, &ds);
00e791
+						 (uint8_t **)&Cert, &ds);
00e791
 		if (EFI_ERROR(efi_status)) {
00e791
 			console_print(L"Failed to create %s certificate %d\n",
00e791
 				      var, efi_status);
00e791
diff --git a/mok.c b/mok.c
00e791
index 089ea6bfc9a..e69857f3c37 100644
00e791
--- a/mok.c
00e791
+++ b/mok.c
00e791
@@ -5,6 +5,8 @@
00e791
 
00e791
 #include "shim.h"
00e791
 
00e791
+#include <stdint.h>
00e791
+
00e791
 /*
00e791
  * Check if a variable exists
00e791
  */
00e791
@@ -47,6 +49,15 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
00e791
 	return EFI_SUCCESS;
00e791
 }
00e791
 
00e791
+typedef enum {
00e791
+	VENDOR_ADDEND_DB,
00e791
+	VENDOR_ADDEND_X509,
00e791
+	VENDOR_ADDEND_NONE,
00e791
+} vendor_addend_category_t;
00e791
+
00e791
+struct mok_state_variable;
00e791
+typedef vendor_addend_category_t (vendor_addend_categorizer_t)(struct mok_state_variable *);
00e791
+
00e791
 /*
00e791
  * MoK variables that need to have their storage validated.
00e791
  *
00e791
@@ -58,18 +69,20 @@ struct mok_state_variable {
00e791
 	char *name8;
00e791
 	CHAR16 *rtname;
00e791
 	EFI_GUID *guid;
00e791
+
00e791
 	UINT8 *data;
00e791
 	UINTN data_size;
00e791
+
00e791
 	/*
00e791
-	 * These two are indirect pointers just to make initialization
00e791
-	 * saner...
00e791
+	 * These are indirect pointers just to make initialization saner...
00e791
 	 */
00e791
-	UINT8 **addend_source;
00e791
+	vendor_addend_categorizer_t *categorize_addend;
00e791
+	UINT8 **addend;
00e791
 	UINT32 *addend_size;
00e791
-#if defined(ENABLE_SHIM_CERT)
00e791
+
00e791
 	UINT8 **build_cert;
00e791
 	UINT32 *build_cert_size;
00e791
-#endif /* defined(ENABLE_SHIM_CERT) */
00e791
+
00e791
 	UINT32 yes_attr;
00e791
 	UINT32 no_attr;
00e791
 	UINT32 flags;
00e791
@@ -77,6 +90,28 @@ struct mok_state_variable {
00e791
 	UINT8 *state;
00e791
 };
00e791
 
00e791
+static vendor_addend_category_t
00e791
+categorize_authorized(struct mok_state_variable *v)
00e791
+{
00e791
+	if (!(v->addend && v->addend_size &&
00e791
+	      *v->addend && *v->addend_size)) {
00e791
+		return VENDOR_ADDEND_NONE;
00e791
+	}
00e791
+
00e791
+	return vendor_authorized_category;
00e791
+}
00e791
+
00e791
+static vendor_addend_category_t
00e791
+categorize_deauthorized(struct mok_state_variable *v)
00e791
+{
00e791
+	if (!(v->addend && v->addend_size &&
00e791
+	      *v->addend && *v->addend_size)) {
00e791
+		return VENDOR_ADDEND_NONE;
00e791
+	}
00e791
+
00e791
+	return VENDOR_ADDEND_DB;
00e791
+}
00e791
+
00e791
 #define MOK_MIRROR_KEYDB	0x01
00e791
 #define MOK_MIRROR_DELETE_FIRST	0x02
00e791
 #define MOK_VARIABLE_MEASURE	0x04
00e791
@@ -90,8 +125,9 @@ struct mok_state_variable mok_state_variables[] = {
00e791
 	 .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
00e791
 		     EFI_VARIABLE_NON_VOLATILE,
00e791
 	 .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
00e791
-	 .addend_source = &vendor_cert,
00e791
-	 .addend_size = &vendor_cert_size,
00e791
+	 .categorize_addend = categorize_authorized,
00e791
+	 .addend = &vendor_authorized,
00e791
+	 .addend_size = &vendor_authorized_size,
00e791
 #if defined(ENABLE_SHIM_CERT)
00e791
 	 .build_cert = &build_cert,
00e791
 	 .build_cert_size = &build_cert_size,
00e791
@@ -107,6 +143,9 @@ struct mok_state_variable mok_state_variables[] = {
00e791
 	 .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
00e791
 		     EFI_VARIABLE_NON_VOLATILE,
00e791
 	 .no_attr = EFI_VARIABLE_RUNTIME_ACCESS,
00e791
+	 .categorize_addend = categorize_deauthorized,
00e791
+	 .addend = &vendor_deauthorized,
00e791
+	 .addend_size = &vendor_deauthorized_size,
00e791
 	 .flags = MOK_MIRROR_KEYDB |
00e791
 		  MOK_VARIABLE_LOG,
00e791
 	 .pcr = 14,
00e791
@@ -136,123 +175,253 @@ struct mok_state_variable mok_state_variables[] = {
00e791
 	{ NULL, }
00e791
 };
00e791
 
00e791
-static inline BOOLEAN nonnull(1)
00e791
-check_vendor_cert(struct mok_state_variable *v)
00e791
-{
00e791
-	return (v->addend_source && v->addend_size &&
00e791
-		*v->addend_source && *v->addend_size) ? TRUE : FALSE;
00e791
-}
00e791
+#define should_mirror_addend(v) (((v)->categorize_addend) && ((v)->categorize_addend(v) != VENDOR_ADDEND_NONE))
00e791
 
00e791
-#if defined(ENABLE_SHIM_CERT)
00e791
 static inline BOOLEAN nonnull(1)
00e791
-check_build_cert(struct mok_state_variable *v)
00e791
+should_mirror_build_cert(struct mok_state_variable *v)
00e791
 {
00e791
 	return (v->build_cert && v->build_cert_size &&
00e791
 		*v->build_cert && *v->build_cert_size) ? TRUE : FALSE;
00e791
 }
00e791
-#define check_addend(v) (check_vendor_cert(v) || check_build_cert(v))
00e791
-#else
00e791
-#define check_addend(v) check_vendor_cert(v)
00e791
-#endif /* defined(ENABLE_SHIM_CERT) */
00e791
+
00e791
+static const uint8_t null_sha256[32] = { 0, };
00e791
 
00e791
 static EFI_STATUS nonnull(1)
00e791
 mirror_one_mok_variable(struct mok_state_variable *v)
00e791
 {
00e791
 	EFI_STATUS efi_status = EFI_SUCCESS;
00e791
-	void *FullData = NULL;
00e791
-	UINTN FullDataSize = 0;
00e791
+	uint8_t *FullData = NULL;
00e791
+	size_t FullDataSize = 0;
00e791
+	vendor_addend_category_t addend_category = VENDOR_ADDEND_NONE;
00e791
 	uint8_t *p = NULL;
00e791
 
00e791
-	if ((v->flags & MOK_MIRROR_KEYDB) && check_addend(v)) {
00e791
-		EFI_SIGNATURE_LIST *CertList = NULL;
00e791
-		EFI_SIGNATURE_DATA *CertData = NULL;
00e791
-#if defined(ENABLE_SHIM_CERT)
00e791
-		FullDataSize = v->data_size;
00e791
-		if (check_build_cert(v)) {
00e791
-			FullDataSize += sizeof (*CertList)
00e791
-					+ sizeof (EFI_GUID)
00e791
-					+ *v->build_cert_size;
00e791
-		}
00e791
-		if (check_vendor_cert(v)) {
00e791
-			FullDataSize += sizeof (*CertList)
00e791
-					+ sizeof (EFI_GUID)
00e791
-					+ *v->addend_size;
00e791
-		}
00e791
-#else
00e791
-		FullDataSize = v->data_size
00e791
-			     + sizeof (*CertList)
00e791
-			     + sizeof (EFI_GUID)
00e791
-			     + *v->addend_size;
00e791
-#endif /* defined(ENABLE_SHIM_CERT) */
00e791
-		FullData = AllocatePool(FullDataSize);
00e791
-		if (!FullData) {
00e791
-			perror(L"Failed to allocate space for MokListRT\n");
00e791
-			return EFI_OUT_OF_RESOURCES;
00e791
-		}
00e791
-		p = FullData;
00e791
+	size_t build_cert_esl_sz = 0, addend_esl_sz = 0;
00e791
 
00e791
-		if (!EFI_ERROR(efi_status) && v->data_size > 0) {
00e791
-			CopyMem(p, v->data, v->data_size);
00e791
-			p += v->data_size;
00e791
-		}
00e791
+	if (v->categorize_addend)
00e791
+		addend_category = v->categorize_addend(v);
00e791
 
00e791
-#if defined(ENABLE_SHIM_CERT)
00e791
-		if (check_build_cert(v) == FALSE)
00e791
-			goto skip_build_cert;
00e791
+	/*
00e791
+	 * we're always mirroring the original data, whether this is an efi
00e791
+	 * security database or not
00e791
+	 */
00e791
+	dprint(L"v->data_size:%lu v->data:0x%08llx\n", v->data_size, v->data);
00e791
+	dprint(L"FullDataSize:%lu FullData:0x%08llx\n", FullDataSize, FullData);
00e791
+	if (v->data_size) {
00e791
+		FullDataSize = v->data_size;
00e791
+		dprint(L"FullDataSize:%lu FullData:0x%08llx\n",
00e791
+		       FullDataSize, FullData);
00e791
+	}
00e791
 
00e791
-		CertList = (EFI_SIGNATURE_LIST *)p;
00e791
-		p += sizeof (*CertList);
00e791
-		CertData = (EFI_SIGNATURE_DATA *)p;
00e791
-		p += sizeof (EFI_GUID);
00e791
+	/*
00e791
+	 * if it is, there's more data
00e791
+	 */
00e791
+	if (v->flags & MOK_MIRROR_KEYDB) {
00e791
 
00e791
-		CertList->SignatureType = EFI_CERT_TYPE_X509_GUID;
00e791
-		CertList->SignatureListSize = *v->build_cert_size
00e791
-					      + sizeof (*CertList)
00e791
-					      + sizeof (*CertData)
00e791
-					      -1;
00e791
-		CertList->SignatureHeaderSize = 0;
00e791
-		CertList->SignatureSize = *v->build_cert_size +
00e791
-					  sizeof (EFI_GUID);
00e791
+		/*
00e791
+		 * We're mirroring (into) an efi security database, aka an
00e791
+		 * array of efi_signature_list_t.  Its layout goes like:
00e791
+		 *
00e791
+		 *   existing_variable_data
00e791
+		 *   existing_variable_data_size
00e791
+		 *   if flags & MOK_MIRROR_KEYDB
00e791
+		 *     if build_cert
00e791
+		 *       build_cert_esl
00e791
+		 *       build_cert_header (always sz=0)
00e791
+		 *       build_cert_esd[0] { owner, data }
00e791
+		 *     if addend==vendor_db
00e791
+		 *       for n=[1..N]
00e791
+		 *         vendor_db_esl_n
00e791
+		 *           vendor_db_header_n (always sz=0)
00e791
+		 *           vendor_db_esd_n[m] {{ owner, data }, ... }
00e791
+		 *     elif addend==vendor_cert
00e791
+		 *       vendor_cert_esl
00e791
+		 *         vendor_cert_header (always sz=0)
00e791
+		 *         vendor_cert_esd[1] { owner, data }
00e791
+		 *
00e791
+		 * first we determine the size of the variable, then alloc
00e791
+		 * and add the data.
00e791
+		 */
00e791
 
00e791
-		CertData->SignatureOwner = SHIM_LOCK_GUID;
00e791
-		CopyMem(p, *v->build_cert, *v->build_cert_size);
00e791
+		/*
00e791
+		 * first bit is existing data, but we added that above
00e791
+		 */
00e791
 
00e791
-		p += *v->build_cert_size;
00e791
+		/*
00e791
+		 * then the build cert if it's there
00e791
+		 */
00e791
+		if (should_mirror_build_cert(v)) {
00e791
+			efi_status = fill_esl(*v->build_cert,
00e791
+					      *v->build_cert_size,
00e791
+					      &EFI_CERT_TYPE_X509_GUID,
00e791
+					      &SHIM_LOCK_GUID,
00e791
+					      NULL, &build_cert_esl_sz);
00e791
+			if (efi_status != EFI_BUFFER_TOO_SMALL) {
00e791
+				perror(L"Could not add built-in cert to %s: %r\n",
00e791
+				       v->name, efi_status);
00e791
+				return efi_status;
00e791
+			}
00e791
+			FullDataSize += build_cert_esl_sz;
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx\n",
00e791
+			       FullDataSize, FullData);
00e791
+		}
00e791
 
00e791
-		if (check_vendor_cert(v) == FALSE)
00e791
-			goto skip_vendor_cert;
00e791
-skip_build_cert:
00e791
-#endif /* defined(ENABLE_SHIM_CERT) */
00e791
+		/*
00e791
+		 * then the addend data
00e791
+		 */
00e791
+		switch (addend_category) {
00e791
+		case VENDOR_ADDEND_DB:
00e791
+			/*
00e791
+			 * if it's an ESL already, we use it wholesale
00e791
+			 */
00e791
+			FullDataSize += *v->addend_size;
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx\n",
00e791
+			       FullDataSize, FullData);
00e791
+			break;
00e791
+		case VENDOR_ADDEND_X509:
00e791
+			efi_status = fill_esl(*v->addend, *v->addend_size,
00e791
+					      &EFI_CERT_TYPE_X509_GUID,
00e791
+					      &SHIM_LOCK_GUID,
00e791
+					      NULL, &addend_esl_sz);
00e791
+			if (efi_status != EFI_BUFFER_TOO_SMALL) {
00e791
+				perror(L"Could not add built-in cert to %s: %r\n",
00e791
+				       v->name, efi_status);
00e791
+				return efi_status;
00e791
+			}
00e791
+			FullDataSize += addend_esl_sz;
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx\n",
00e791
+				      FullDataSize, FullData);
00e791
+			break;
00e791
+		default:
00e791
+		case VENDOR_ADDEND_NONE:
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx\n",
00e791
+				      FullDataSize, FullData);
00e791
+			break;
00e791
+		}
00e791
+	}
00e791
 
00e791
-		CertList = (EFI_SIGNATURE_LIST *)p;
00e791
-		p += sizeof (*CertList);
00e791
-		CertData = (EFI_SIGNATURE_DATA *)p;
00e791
-		p += sizeof (EFI_GUID);
00e791
+	/*
00e791
+	 * Now we have the full size
00e791
+	 */
00e791
+	if (FullDataSize) {
00e791
+		/*
00e791
+		 * allocate the buffer, or use the old one if it's just the
00e791
+		 * existing data.
00e791
+		 */
00e791
+		if (FullDataSize != v->data_size) {
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx allocating FullData\n",
00e791
+			       FullDataSize, FullData);
00e791
+			FullData = AllocatePool(FullDataSize);
00e791
+			if (!FullData) {
00e791
+				FreePool(v->data);
00e791
+				v->data = NULL;
00e791
+				v->data_size = 0;
00e791
+				perror(L"Failed to allocate %lu bytes for %s\n",
00e791
+				       FullDataSize, v->name);
00e791
+				return EFI_OUT_OF_RESOURCES;
00e791
+			}
00e791
+			p = FullData;
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+			       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
+			if (v->data && v->data_size) {
00e791
+				CopyMem(p, v->data, v->data_size);
00e791
+				p += v->data_size;
00e791
+			}
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+			       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
+		} else {
00e791
+			FullData = v->data;
00e791
+			FullDataSize = v->data_size;
00e791
+			p = FullData + FullDataSize;
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+			       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
+			v->data = NULL;
00e791
+			v->data_size = 0;
00e791
+		}
00e791
+	}
00e791
+	dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+	       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
 
00e791
-		CertList->SignatureType = EFI_CERT_TYPE_X509_GUID;
00e791
-		CertList->SignatureListSize = *v->addend_size
00e791
-					      + sizeof (*CertList)
00e791
-					      + sizeof (*CertData)
00e791
-					      -1;
00e791
-		CertList->SignatureHeaderSize = 0;
00e791
-		CertList->SignatureSize = *v->addend_size + sizeof (EFI_GUID);
00e791
+	/*
00e791
+	 * Now fill it.
00e791
+	 */
00e791
+	if (v->flags & MOK_MIRROR_KEYDB) {
00e791
+		/*
00e791
+		 * first bit is existing data, but again, we added that above
00e791
+		 */
00e791
 
00e791
-		CertData->SignatureOwner = SHIM_LOCK_GUID;
00e791
-		CopyMem(p, *v->addend_source, *v->addend_size);
00e791
+		/*
00e791
+		 * second is the build cert
00e791
+		 */
00e791
+		dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+		       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
+		if (should_mirror_build_cert(v)) {
00e791
+			efi_status = fill_esl(*v->build_cert,
00e791
+					      *v->build_cert_size,
00e791
+					      &EFI_CERT_TYPE_X509_GUID,
00e791
+					      &SHIM_LOCK_GUID,
00e791
+					      p, &build_cert_esl_sz);
00e791
+			if (EFI_ERROR(efi_status)) {
00e791
+				perror(L"Could not add built-in cert to %s: %r\n",
00e791
+				       v->name, efi_status);
00e791
+				return efi_status;
00e791
+			}
00e791
+			p += build_cert_esl_sz;
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+			       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
+		}
00e791
 
00e791
-#if defined(ENABLE_SHIM_CERT)
00e791
-skip_vendor_cert:
00e791
-#endif /* defined(ENABLE_SHIM_CERT) */
00e791
-		if (v->data && v->data_size)
00e791
-			FreePool(v->data);
00e791
-		v->data = FullData;
00e791
-		v->data_size = FullDataSize;
00e791
-	} else {
00e791
-		FullDataSize = v->data_size;
00e791
-		FullData = v->data;
00e791
+		switch (addend_category) {
00e791
+		case VENDOR_ADDEND_DB:
00e791
+			CopyMem(p, *v->addend, *v->addend_size);
00e791
+			p += *v->addend_size;
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+			       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
+			break;
00e791
+		case VENDOR_ADDEND_X509:
00e791
+			efi_status = fill_esl(*v->addend, *v->addend_size,
00e791
+					      &EFI_CERT_TYPE_X509_GUID,
00e791
+					      &SHIM_LOCK_GUID,
00e791
+					      p, &addend_esl_sz);
00e791
+			if (EFI_ERROR(efi_status)) {
00e791
+				perror(L"Could not add built-in cert to %s: %r\n",
00e791
+				       v->name, efi_status);
00e791
+				return efi_status;
00e791
+			}
00e791
+			p += addend_esl_sz;
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+			       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
+			break;
00e791
+		default:
00e791
+		case VENDOR_ADDEND_NONE:
00e791
+			dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+			       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
+			break;
00e791
+		}
00e791
+	}
00e791
+	/*
00e791
+	 * We always want to create our key databases, so in this case we
00e791
+	 * need a dummy entry
00e791
+	 */
00e791
+	if ((v->flags & MOK_MIRROR_KEYDB) && FullDataSize == 0) {
00e791
+		efi_status = variable_create_esl(
00e791
+				null_sha256, sizeof(null_sha256),
00e791
+				&EFI_CERT_SHA256_GUID, &SHIM_LOCK_GUID,
00e791
+				&FullData, &FullDataSize);
00e791
+		if (EFI_ERROR(efi_status)) {
00e791
+			perror(L"Failed to allocate %lu bytes for %s\n",
00e791
+			       FullDataSize, v->name);
00e791
+			return efi_status;
00e791
+		}
00e791
+		p = FullData + FullDataSize;
00e791
+		dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+		       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
 	}
00e791
 
00e791
+	dprint(L"FullDataSize:%lu FullData:0x%08llx p:0x%08llx pos:%lld\n",
00e791
+	       FullDataSize, FullData, p, p-(uintptr_t)FullData);
00e791
 	if (FullDataSize) {
00e791
+		dprint(L"Setting %s with %lu bytes of data\n",
00e791
+		       v->rtname, FullDataSize);
00e791
 		efi_status = gRT->SetVariable(v->rtname, v->guid,
00e791
 					      EFI_VARIABLE_BOOTSERVICE_ACCESS |
00e791
 					      EFI_VARIABLE_RUNTIME_ACCESS,
00e791
@@ -262,7 +431,15 @@ skip_vendor_cert:
00e791
 			       v->rtname, efi_status);
00e791
 		}
00e791
 	}
00e791
-
00e791
+	if (v->data && v->data_size) {
00e791
+		FreePool(v->data);
00e791
+		v->data = NULL;
00e791
+		v->data_size = 0;
00e791
+	}
00e791
+	if (FullData && FullDataSize) {
00e791
+		FreePool(FullData);
00e791
+	}
00e791
+	dprint(L"returning %r\n", efi_status);
00e791
 	return efi_status;
00e791
 }
00e791
 
00e791
@@ -274,6 +451,8 @@ static EFI_STATUS nonnull(1)
00e791
 maybe_mirror_one_mok_variable(struct mok_state_variable *v, EFI_STATUS ret)
00e791
 {
00e791
 	EFI_STATUS efi_status;
00e791
+	BOOLEAN present = FALSE;
00e791
+
00e791
 	if (v->rtname) {
00e791
 		if (v->flags & MOK_MIRROR_DELETE_FIRST)
00e791
 			LibDeleteVariable(v->rtname, v->guid);
00e791
@@ -286,6 +465,43 @@ maybe_mirror_one_mok_variable(struct mok_state_variable *v, EFI_STATUS ret)
00e791
 			       efi_status);
00e791
 		}
00e791
 	}
00e791
+
00e791
+	present = (v->data && v->data_size) ? TRUE : FALSE;
00e791
+	if (!present)
00e791
+		return ret;
00e791
+
00e791
+	if (v->data_size == sizeof(UINT8) && v->state) {
00e791
+		*v->state = v->data[0];
00e791
+	}
00e791
+
00e791
+	if (v->flags & MOK_VARIABLE_MEASURE) {
00e791
+		/*
00e791
+		 * Measure this into PCR 7 in the Microsoft format
00e791
+		 */
00e791
+		efi_status = tpm_measure_variable(v->name, *v->guid,
00e791
+						  v->data_size,
00e791
+						  v->data);
00e791
+		if (EFI_ERROR(efi_status)) {
00e791
+			if (ret != EFI_SECURITY_VIOLATION)
00e791
+				ret = efi_status;
00e791
+		}
00e791
+	}
00e791
+
00e791
+	if (v->flags & MOK_VARIABLE_LOG) {
00e791
+		/*
00e791
+		 * Log this variable into whichever PCR the table
00e791
+		 * says.
00e791
+		 */
00e791
+		EFI_PHYSICAL_ADDRESS datap =
00e791
+				(EFI_PHYSICAL_ADDRESS)(UINTN)v->data,
00e791
+		efi_status = tpm_log_event(datap, v->data_size,
00e791
+					   v->pcr, (CHAR8 *)v->name8);
00e791
+		if (EFI_ERROR(efi_status)) {
00e791
+			if (ret != EFI_SECURITY_VIOLATION)
00e791
+				ret = efi_status;
00e791
+		}
00e791
+	}
00e791
+
00e791
 	return ret;
00e791
 }
00e791
 
00e791
@@ -311,26 +527,20 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
00e791
 	user_insecure_mode = 0;
00e791
 	ignore_db = 0;
00e791
 
00e791
+	dprint(L"importing mok state\n");
00e791
 	for (i = 0; mok_state_variables[i].name != NULL; i++) {
00e791
 		struct mok_state_variable *v = &mok_state_variables[i];
00e791
 		UINT32 attrs = 0;
00e791
-		BOOLEAN delete = FALSE, present, addend;
00e791
-
00e791
-		addend = check_addend(v);
00e791
+		BOOLEAN delete = FALSE;
00e791
 
00e791
 		efi_status = get_variable_attr(v->name,
00e791
 					       &v->data, &v->data_size,
00e791
 					       *v->guid, &attrs);
00e791
+		dprint(L"maybe mirroring %s\n", v->name);
00e791
 		if (efi_status == EFI_NOT_FOUND) {
00e791
-			if (addend)
00e791
-				ret = maybe_mirror_one_mok_variable(v, ret);
00e791
-			/*
00e791
-			 * after possibly adding, we can continue, no
00e791
-			 * further checks to be done.
00e791
-			 */
00e791
-			continue;
00e791
-		}
00e791
-		if (EFI_ERROR(efi_status)) {
00e791
+			v->data = NULL;
00e791
+			v->data_size = 0;
00e791
+		} else if (EFI_ERROR(efi_status)) {
00e791
 			perror(L"Could not verify %s: %r\n", v->name,
00e791
 			       efi_status);
00e791
 			/*
00e791
@@ -339,22 +549,22 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
00e791
 			 */
00e791
 			if (ret != EFI_SECURITY_VIOLATION)
00e791
 				ret = efi_status;
00e791
-			continue;
00e791
-		}
00e791
-
00e791
-		if (!(attrs & v->yes_attr)) {
00e791
-			perror(L"Variable %s is missing attributes:\n",
00e791
-			       v->name);
00e791
-			perror(L"  0x%08x should have 0x%08x set.\n",
00e791
-			       attrs, v->yes_attr);
00e791
-			delete = TRUE;
00e791
-		}
00e791
-		if (attrs & v->no_attr) {
00e791
-			perror(L"Variable %s has incorrect attribute:\n",
00e791
-			       v->name);
00e791
-			perror(L"  0x%08x should not have 0x%08x set.\n",
00e791
-			       attrs, v->no_attr);
00e791
 			delete = TRUE;
00e791
+		} else {
00e791
+			if (!(attrs & v->yes_attr)) {
00e791
+				perror(L"Variable %s is missing attributes:\n",
00e791
+				       v->name);
00e791
+				perror(L"  0x%08x should have 0x%08x set.\n",
00e791
+				       attrs, v->yes_attr);
00e791
+				delete = TRUE;
00e791
+			}
00e791
+			if (attrs & v->no_attr) {
00e791
+				perror(L"Variable %s has incorrect attribute:\n",
00e791
+				       v->name);
00e791
+				perror(L"  0x%08x should not have 0x%08x set.\n",
00e791
+				       attrs, v->no_attr);
00e791
+				delete = TRUE;
00e791
+			}
00e791
 		}
00e791
 		if (delete == TRUE) {
00e791
 			perror(L"Deleting bad variable %s\n", v->name);
00e791
@@ -366,45 +576,9 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
00e791
 			FreePool(v->data);
00e791
 			v->data = NULL;
00e791
 			v->data_size = 0;
00e791
-			continue;
00e791
 		}
00e791
 
00e791
-		if (v->data && v->data_size == sizeof(UINT8) && v->state) {
00e791
-			*v->state = v->data[0];
00e791
-		}
00e791
-
00e791
-		present = (v->data && v->data_size) ? TRUE : FALSE;
00e791
-
00e791
-		if (v->flags & MOK_VARIABLE_MEASURE && present) {
00e791
-			/*
00e791
-			 * Measure this into PCR 7 in the Microsoft format
00e791
-			 */
00e791
-			efi_status = tpm_measure_variable(v->name, *v->guid,
00e791
-							  v->data_size,
00e791
-							  v->data);
00e791
-			if (EFI_ERROR(efi_status)) {
00e791
-				if (ret != EFI_SECURITY_VIOLATION)
00e791
-					ret = efi_status;
00e791
-			}
00e791
-		}
00e791
-
00e791
-		if (v->flags & MOK_VARIABLE_LOG && present) {
00e791
-			/*
00e791
-			 * Log this variable into whichever PCR the table
00e791
-			 * says.
00e791
-			 */
00e791
-			EFI_PHYSICAL_ADDRESS datap =
00e791
-					(EFI_PHYSICAL_ADDRESS)(UINTN)v->data,
00e791
-			efi_status = tpm_log_event(datap, v->data_size,
00e791
-						   v->pcr, (CHAR8 *)v->name8);
00e791
-			if (EFI_ERROR(efi_status)) {
00e791
-				if (ret != EFI_SECURITY_VIOLATION)
00e791
-					ret = efi_status;
00e791
-			}
00e791
-		}
00e791
-
00e791
-		if (present)
00e791
-			ret = maybe_mirror_one_mok_variable(v, ret);
00e791
+		ret = maybe_mirror_one_mok_variable(v, ret);
00e791
 	}
00e791
 
00e791
 	/*
00e791
@@ -412,14 +586,16 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle)
00e791
 	 * cause MokManager to demand a machine reboot, so this is safe to
00e791
 	 * have after the entire loop.
00e791
 	 */
00e791
+	dprint(L"checking mok request\n");
00e791
 	efi_status = check_mok_request(image_handle);
00e791
+	dprint(L"mok returned %r\n", efi_status);
00e791
 	if (EFI_ERROR(efi_status)) {
00e791
 		if (ret != EFI_SECURITY_VIOLATION)
00e791
 			ret = efi_status;
00e791
 		return ret;
00e791
 	}
00e791
 
00e791
-
00e791
+	dprint(L"returning %r\n", ret);
00e791
 	return ret;
00e791
 }
00e791
 
00e791
diff --git a/shim.c b/shim.c
00e791
index 888ee6e8d7b..ee62248ca4e 100644
00e791
--- a/shim.c
00e791
+++ b/shim.c
00e791
@@ -646,6 +646,31 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
00e791
 		}
00e791
 	}
00e791
 
00e791
+#if defined(VENDOR_DB_FILE)
00e791
+	EFI_SIGNATURE_LIST *db = (EFI_SIGNATURE_LIST *)vendor_db;
00e791
+
00e791
+	if (check_db_hash_in_ram(db, vendor_db_size,
00e791
+				 sha256hash, SHA256_DIGEST_SIZE,
00e791
+				 EFI_CERT_SHA256_GUID, L"vendor_db",
00e791
+				 EFI_SECURE_BOOT_DB_GUID) == DATA_FOUND) {
00e791
+		verification_method = VERIFIED_BY_HASH;
00e791
+		update_verification_method(VERIFIED_BY_HASH);
00e791
+		return EFI_SUCCESS;
00e791
+	} else {
00e791
+		LogError(L"check_db_hash(vendor_db, sha256hash) != DATA_FOUND\n");
00e791
+	}
00e791
+	if (cert &&
00e791
+	    check_db_cert_in_ram(db, vendor_db_size,
00e791
+				 cert, sha256hash, L"vendor_db",
00e791
+				 EFI_SECURE_BOOT_DB_GUID) == DATA_FOUND) {
00e791
+		verification_method = VERIFIED_BY_CERT;
00e791
+		update_verification_method(VERIFIED_BY_CERT);
00e791
+		return EFI_SUCCESS;
00e791
+	} else {
00e791
+		LogError(L"check_db_cert(vendor_db, sha256hash) != DATA_FOUND\n");
00e791
+	}
00e791
+#endif
00e791
+
00e791
 	if (check_db_hash(L"MokList", SHIM_LOCK_GUID, sha256hash,
00e791
 			  SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID)
00e791
 				== DATA_FOUND) {
00e791
@@ -1076,6 +1101,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
00e791
 		}
00e791
 #endif /* defined(ENABLE_SHIM_CERT) */
00e791
 
00e791
+#if defined(VENDOR_CERT_FILE)
00e791
 		/*
00e791
 		 * And finally, check against shim's built-in key
00e791
 		 */
00e791
@@ -1093,6 +1119,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
00e791
 		} else {
00e791
 			LogError(L"AuthenticodeVerify(vendor_authorized) failed\n");
00e791
 		}
00e791
+#endif /* defined(VENDOR_CERT_FILE) */
00e791
 	}
00e791
 
00e791
 	LogError(L"Binary is not whitelisted\n");
00e791
diff --git a/include/console.h b/include/console.h
00e791
index 9f259c71b72..810bf13a1f1 100644
00e791
--- a/include/console.h
00e791
+++ b/include/console.h
00e791
@@ -78,12 +78,13 @@ struct _EFI_CONSOLE_CONTROL_PROTOCOL {
00e791
 extern VOID console_fini(VOID);
00e791
 extern VOID setup_verbosity(VOID);
00e791
 extern UINT32 verbose;
00e791
-#define dprint(fmt, ...) ({							\
00e791
+#define dprint_(fmt, ...) ({							\
00e791
 		UINTN __dprint_ret = 0;						\
00e791
 		if (verbose)							\
00e791
 			__dprint_ret = console_print((fmt), ##__VA_ARGS__);	\
00e791
 		__dprint_ret;							\
00e791
 	})
00e791
+#define dprint(fmt, ...) dprint_(L"%a:%d:%a() " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__)
00e791
 
00e791
 extern EFI_STATUS print_crypto_errors(EFI_STATUS rc, char *file, const char *func, int line);
00e791
 #define crypterr(rc) print_crypto_errors((rc), __FILE__, __func__, __LINE__)
00e791
diff --git a/include/variables.h b/include/variables.h
00e791
index 8566a1a4746..436adb46e16 100644
00e791
--- a/include/variables.h
00e791
+++ b/include/variables.h
00e791
@@ -57,7 +57,12 @@ EFI_STATUS
00e791
 variable_enroll_hash(CHAR16 *var, EFI_GUID owner,
00e791
 		     UINT8 hash[SHA256_DIGEST_SIZE]);
00e791
 EFI_STATUS
00e791
-variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner,
00e791
-		    void **out, int *outlen);
00e791
+variable_create_esl(const uint8_t *cert, const size_t cert_len,
00e791
+		    const EFI_GUID *type, const EFI_GUID *owner,
00e791
+		    uint8_t **out, size_t *outlen);
00e791
+EFI_STATUS
00e791
+fill_esl(const uint8_t *data, const size_t data_len,
00e791
+	 const EFI_GUID *type, const EFI_GUID *owner,
00e791
+	 uint8_t *out, size_t *outlen);
00e791
 
00e791
 #endif /* SHIM_VARIABLES_H */
00e791
diff --git a/shim.h b/shim.h
00e791
index 555498c6673..c1d7e7c7197 100644
00e791
--- a/shim.h
00e791
+++ b/shim.h
00e791
@@ -97,7 +97,11 @@
00e791
 #define FALLBACK L"\\fb" EFI_ARCH L".efi"
00e791
 #define MOK_MANAGER L"\\mm" EFI_ARCH L".efi"
00e791
 
00e791
-#if defined(VENDOR_CERT_FILE)
00e791
+#if defined(VENDOR_DB_FILE)
00e791
+# define vendor_authorized vendor_db
00e791
+# define vendor_authorized_size vendor_db_size
00e791
+# define vendor_authorized_category VENDOR_ADDEND_DB
00e791
+#elif defined(VENDOR_CERT_FILE)
00e791
 # define vendor_authorized vendor_cert
00e791
 # define vendor_authorized_size vendor_cert_size
00e791
 # define vendor_authorized_category VENDOR_ADDEND_X509
00e791
@@ -116,6 +120,7 @@
00e791
 #endif
00e791
 
00e791
 #include "include/asm.h"
00e791
+#include "include/compiler.h"
00e791
 #include "include/configtable.h"
00e791
 #include "include/console.h"
00e791
 #include "include/crypt_blowfish.h"
00e791
diff --git a/cert.S b/cert.S
00e791
index 520caaef3af..e636fcbbf2d 100644
00e791
--- a/cert.S
00e791
+++ b/cert.S
00e791
@@ -1,5 +1,12 @@
00e791
 
00e791
-#if defined(VENDOR_CERT_FILE)
00e791
+#if defined(VENDOR_DB_FILE) && defined(VENDOR_CERT_FILE)
00e791
+# error both VENDOR_DB_FILE and VENDOR_CERT_FILE have been configured
00e791
+#elif defined(VENDOR_DB_FILE)
00e791
+# define vendor_authorized vendor_db
00e791
+# define vendor_authorized_end vendor_db_end
00e791
+# define vendor_authorized_size vendor_db_size
00e791
+# define vendor_authorized_size_end vendor_db_size_end
00e791
+#elif defined(VENDOR_CERT_FILE)
00e791
 # define vendor_authorized vendor_cert
00e791
 # define vendor_authorized_end vendor_cert_end
00e791
 # define vendor_authorized_size vendor_cert_size
00e791
@@ -28,7 +35,9 @@ cert_table:
00e791
 	.size	vendor_authorized, .Lvendor_authorized_end - vendor_authorized
00e791
 	.section .vendor_cert, "a", %progbits
00e791
 vendor_authorized:
00e791
-#if defined(VENDOR_CERT_FILE)
00e791
+#if defined(VENDOR_DB_FILE)
00e791
+.incbin VENDOR_DB_FILE
00e791
+#elif defined(VENDOR_CERT_FILE)
00e791
 .incbin VENDOR_CERT_FILE
00e791
 #endif
00e791
 .Lvendor_authorized_end:
00e791
diff --git a/Make.defaults b/Make.defaults
00e791
index f0bfa9fd573..2e01646a35d 100644
00e791
--- a/Make.defaults
00e791
+++ b/Make.defaults
00e791
@@ -125,6 +125,9 @@ BOOTCSVNAME	?= BOOT$(ARCH_SUFFIX_UPPER).CSV
00e791
 
00e791
 CFLAGS += "-DEFI_ARCH=L\"$(ARCH_SUFFIX)\"" "-DDEBUGDIR=L\"/usr/lib/debug/usr/share/shim/$(ARCH_SUFFIX)-$(VERSION)$(DASHRELEASE)/\""
00e791
 
00e791
+ifneq ($(origin VENDOR_DB_FILE), undefined)
00e791
+	CFLAGS += -DVENDOR_DB_FILE=\"$(VENDOR_DB_FILE)\"
00e791
+endif
00e791
 ifneq ($(origin VENDOR_CERT_FILE), undefined)
00e791
 	CFLAGS += -DVENDOR_CERT_FILE=\"$(VENDOR_CERT_FILE)\"
00e791
 endif
00e791
diff --git a/README.tpm b/README.tpm
00e791
index c060dbe22db..62308d5c71a 100644
00e791
--- a/README.tpm
00e791
+++ b/README.tpm
00e791
@@ -13,6 +13,7 @@ PCR7:
00e791
   - MokListX - the Mok blacklist, logged as "MokListX"
00e791
   - vendor_dbx - shim's built-in vendor blacklist, logged as "dbx"
00e791
   - DB - the system whitelist, logged as "db"
00e791
+  - vendor_db - shim's built-in vendor whitelist, logged as "db"
00e791
   - MokList the Mok whitelist, logged as "MokList"
00e791
   - vendor_cert - shim's built-in vendor whitelist, logged as "Shim"
00e791
   - shim_cert - shim's build-time generated whitelist, logged as "Shim"
00e791
-- 
00e791
2.26.2
00e791