File shim-mokx-support.patch of Package shim

From 58b8e54ef60d488886a9f0d0877b7187eb200d07 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 24 Oct 2013 17:02:08 +0800
Subject: [PATCH 01/10] Support MOK blacklist

The new blacklist, MokListX, stores the keys and hashes that are
banned.

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 MokManager.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 shim.c       |   3 +-
 2 files changed, 202 insertions(+), 42 deletions(-)

Index: shim-0.7/MokManager.c
===================================================================
--- shim-0.7.orig/MokManager.c
+++ shim-0.7/MokManager.c
@@ -165,9 +165,16 @@ static MokListNode *build_mok_list(UINT3
 		Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
 		  sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
 
-		list[count].MokSize = CertList->SignatureSize - sizeof(EFI_GUID);
-		list[count].Mok = (void *)Cert->SignatureData;
 		list[count].Type = CertList->SignatureType;
+		if (CompareGuid (&CertList->SignatureType, &CertType) == 0) {
+			list[count].MokSize = CertList->SignatureSize -
+					      sizeof(EFI_GUID);
+			list[count].Mok = (void *)Cert->SignatureData;
+		} else {
+			list[count].MokSize = CertList->SignatureListSize -
+					      sizeof(EFI_SIGNATURE_LIST);
+			list[count].Mok = (void *)Cert;
+		}
 
 		count++;
 		dbsize -= CertList->SignatureListSize;
@@ -373,7 +380,7 @@ static void show_x509_info (X509 *X509Ce
 	FreePool(text);
 }
 
-static void show_efi_hash (UINT8 *hash)
+static void show_sha256_digest (UINT8 *hash)
 {
 	CHAR16 *text[5];
 	POOL_PRINT hash_string1;
@@ -404,16 +411,68 @@ static void show_efi_hash (UINT8 *hash)
 		FreePool(hash_string2.str);
 }
 
-static void show_mok_info (void *Mok, UINTN MokSize)
+static void show_efi_hash (void *Mok, UINTN MokSize)
+{
+	UINTN sig_size;
+	UINTN hash_num;
+	UINT8 *hash;
+	CHAR16 **menu_strings;
+	int key_num = 0;
+	int i;
+
+	sig_size = SHA256_DIGEST_SIZE + sizeof(EFI_GUID);
+	if ((MokSize % sig_size) != 0) {
+		console_errorbox(L"Corrupted Hash List");
+		return;
+	}
+	hash_num = MokSize / sig_size;
+
+	if (hash_num == 1) {
+		hash = (UINT8 *)Mok + sizeof(EFI_GUID);
+		show_sha256_digest(hash);
+		return;
+	}
+
+	menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (hash_num + 2));
+	if (!menu_strings) {
+		console_errorbox(L"Out of Resources");
+		return;
+	}
+	for (i=0; i<hash_num; i++) {
+		menu_strings[i] = PoolPrint(L"View hash %d", i);
+	}
+	menu_strings[i] = StrDuplicate(L"Back");
+	menu_strings[i+1] = NULL;
+
+	while (key_num < hash_num) {
+		key_num = console_select((CHAR16 *[]){ L"[Hash List]", NULL },
+					 menu_strings, key_num);
+
+		if (key_num < 0 || key_num >= hash_num)
+			break;
+
+		hash = (UINT8 *)Mok + sig_size*key_num + sizeof(EFI_GUID);
+		show_sha256_digest(hash);
+	}
+
+	for (i=0; menu_strings[i] != NULL; i++)
+		FreePool(menu_strings[i]);
+
+	FreePool(menu_strings);
+}
+
+static void show_mok_info (EFI_GUID Type, void *Mok, UINTN MokSize)
 {
 	EFI_STATUS efi_status;
 	UINT8 hash[SHA1_DIGEST_SIZE];
 	X509 *X509Cert;
+	EFI_GUID CertType = X509_GUID;
+	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
 
 	if (!Mok || MokSize == 0)
 		return;
 
-	if (MokSize != SHA256_DIGEST_SIZE) {
+	if (CompareGuid (&Type, &CertType) == 0) {
 		efi_status = get_sha1sum(Mok, MokSize, hash);
 
 		if (efi_status != EFI_SUCCESS) {
@@ -429,8 +488,8 @@ static void show_mok_info (void *Mok, UI
 			console_notify(L"Not a valid X509 certificate");
 			return;
 		}
-	} else {
-		show_efi_hash(Mok);
+	} else if (CompareGuid (&Type, &HashType) == 0) {
+		show_efi_hash(Mok, MokSize);
 	}
 }
 
@@ -438,7 +497,7 @@ static EFI_STATUS list_keys (void *KeyLi
 {
 	UINT32 MokNum = 0;
 	MokListNode *keys = NULL;
-	INTN key_num = 0;
+	int key_num = 0;
 	CHAR16 **menu_strings;
 	int i;
 
@@ -470,12 +529,13 @@ static EFI_STATUS list_keys (void *KeyLi
 
 	while (key_num < MokNum) {
 		key_num = console_select((CHAR16 *[]){ title, NULL },
-					 menu_strings, 0);
+					 menu_strings, key_num);
 
-		if (key_num < 0)
+		if (key_num < 0 || key_num >= MokNum)
 			break;
-		else if (key_num < MokNum)
-			show_mok_info(keys[key_num].Mok, keys[key_num].MokSize);
+
+		show_mok_info(keys[key_num].Type, keys[key_num].Mok,
+			      keys[key_num].MokSize);
 	}
 
 	for (i=0; menu_strings[i] != NULL; i++)
@@ -701,23 +761,37 @@ static EFI_STATUS match_password (PASSWO
 	return EFI_SUCCESS;
 }
 
-static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
+static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate,
+			      BOOLEAN MokX)
 {
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
 	EFI_STATUS efi_status;
+	CHAR16 *db_name;
+	CHAR16 *auth_name;
 	UINT8 auth[PASSWORD_CRYPT_SIZE];
 	UINTN auth_size = PASSWORD_CRYPT_SIZE;
 	UINT32 attributes;
 
+	if (MokX) {
+		db_name = L"MokListX";
+		auth_name = L"MokXAuth";
+	} else {
+		db_name = L"MokList";
+		auth_name = L"MokAuth";
+	}
+
 	if (authenticate) {
-		efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
+		efi_status = uefi_call_wrapper(RT->GetVariable, 5, auth_name,
 					       &shim_lock_guid,
 					       &attributes, &auth_size, auth);
 
 		if (efi_status != EFI_SUCCESS ||
 		    (auth_size != SHA256_DIGEST_SIZE &&
 		     auth_size != PASSWORD_CRYPT_SIZE)) {
-			console_error(L"Failed to get MokAuth", efi_status);
+			if (MokX)
+				console_error(L"Failed to get MokXAuth", efi_status);
+			else
+				console_error(L"Failed to get MokAuth", efi_status);
 			return efi_status;
 		}
 
@@ -734,14 +808,14 @@ static EFI_STATUS store_keys (void *MokN
 
 	if (!MokNewSize) {
 		/* Delete MOK */
-		efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
+		efi_status = uefi_call_wrapper(RT->SetVariable, 5, db_name,
 					       &shim_lock_guid,
 					       EFI_VARIABLE_NON_VOLATILE
 					       | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 					       0, NULL);
 	} else {
 		/* Write new MOK */
-		efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
+		efi_status = uefi_call_wrapper(RT->SetVariable, 5, db_name,
 					       &shim_lock_guid,
 					       EFI_VARIABLE_NON_VOLATILE
 					       | EFI_VARIABLE_BOOTSERVICE_ACCESS
@@ -757,17 +831,25 @@ static EFI_STATUS store_keys (void *MokN
 	return EFI_SUCCESS;
 }
 
-static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
+static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth,
+				    BOOLEAN MokX)
+{
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
 	EFI_STATUS efi_status;
+	CHAR16 *title;
+
+	if (MokX)
+		title = L"[Enroll MOKX]";
+	else
+		title = L"[Enroll MOK]";
 
-	if (list_keys(MokNew, MokNewSize, L"[Enroll MOK]") != EFI_SUCCESS)
+	if (list_keys(MokNew, MokNewSize, title) != EFI_SUCCESS)
 		return 0;
 
 	if (console_yes_no((CHAR16 *[]){L"Enroll the key(s)?", NULL}) == 0)
 		return 0;
 
-	efi_status = store_keys(MokNew, MokNewSize, auth);
+	efi_status = store_keys(MokNew, MokNewSize, auth, MokX);
 
 	if (efi_status != EFI_SUCCESS) {
 		console_notify(L"Failed to enroll keys\n");
@@ -775,8 +857,13 @@ static UINTN mok_enrollment_prompt (void
 	}
 
 	if (auth) {
-		LibDeleteVariable(L"MokNew", &shim_lock_guid);
-		LibDeleteVariable(L"MokAuth", &shim_lock_guid);
+		if (MokX) {
+			LibDeleteVariable(L"MokXNew", &shim_lock_guid);
+			LibDeleteVariable(L"MokXAuth", &shim_lock_guid);
+		} else {
+			LibDeleteVariable(L"MokNew", &shim_lock_guid);
+			LibDeleteVariable(L"MokAuth", &shim_lock_guid);
+		}
 
 		console_notify(L"The system must now be rebooted");
 		uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
@@ -788,25 +875,35 @@ static UINTN mok_enrollment_prompt (void
 	return 0;
 }
 
-static INTN mok_reset_prompt ()
+static INTN mok_reset_prompt (BOOLEAN MokX)
 {
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
 	EFI_STATUS efi_status;
+	CHAR16 *prompt;
 
 	uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
 
-	if (console_yes_no((CHAR16 *[]){L"Erase all stored keys?", NULL }) == 0)
+	if (MokX)
+		prompt = L"Erase all stored keys in MokListX?";
+	else
+		prompt = L"Erase all stored keys in MokList?";
+	if (console_yes_no((CHAR16 *[]){prompt, NULL }) == 0)
 		return 0;
 
-	efi_status = store_keys(NULL, 0, TRUE);
+	efi_status = store_keys(NULL, 0, TRUE, MokX);
 
 	if (efi_status != EFI_SUCCESS) {
 		console_notify(L"Failed to erase keys\n");
 		return -1;
 	}
 
-	LibDeleteVariable(L"MokNew", &shim_lock_guid);
-	LibDeleteVariable(L"MokAuth", &shim_lock_guid);
+	if (MokX) {
+		LibDeleteVariable(L"MokXNew", &shim_lock_guid);
+		LibDeleteVariable(L"MokXAuth", &shim_lock_guid);
+	} else {
+		LibDeleteVariable(L"MokNew", &shim_lock_guid);
+		LibDeleteVariable(L"MokAuth", &shim_lock_guid);
+	}
 
 	console_notify(L"The system must now be rebooted");
 	uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
@@ -815,15 +912,23 @@ static INTN mok_reset_prompt ()
 	return -1;
 }
 
-static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num)
+static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num,
+				       BOOLEAN MokX)
 {
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+	EFI_GUID CertType = X509_GUID;
 	EFI_STATUS efi_status;
 	EFI_SIGNATURE_LIST *CertList;
 	EFI_SIGNATURE_DATA *CertData;
 	void *Data = NULL, *ptr;
 	INTN DataSize = 0;
 	int i;
+	CHAR16 *db_name;
+
+	if (MokX)
+		db_name = L"MokListX";
+	else
+		db_name = L"MokList";
 
 	for (i = 0; i < key_num; i++) {
 		if (list[i].Mok == NULL)
@@ -848,20 +953,27 @@ static EFI_STATUS write_back_mok_list (M
 			   sizeof(EFI_SIGNATURE_LIST));
 
 		CertList->SignatureType = list[i].Type;
-		CertList->SignatureListSize = list[i].MokSize +
-					      sizeof(EFI_SIGNATURE_LIST) +
-					      sizeof(EFI_SIGNATURE_DATA) - 1;
 		CertList->SignatureHeaderSize = 0;
-		CertList->SignatureSize = list[i].MokSize + sizeof(EFI_GUID);
 
-		CertData->SignatureOwner = shim_lock_guid;
-		CopyMem(CertData->SignatureData, list[i].Mok, list[i].MokSize);
+		if (CompareGuid(&(list[i].Type), &CertType) == 0) {
+			CertList->SignatureListSize = list[i].MokSize +
+						      sizeof(EFI_SIGNATURE_LIST) +
+						      sizeof(EFI_GUID);
+			CertList->SignatureSize = list[i].MokSize + sizeof(EFI_GUID);
 
-		ptr = (uint8_t *)ptr + sizeof(EFI_SIGNATURE_LIST) +
-		      sizeof(EFI_GUID) + list[i].MokSize;
+			CertData->SignatureOwner = shim_lock_guid;
+			CopyMem(CertData->SignatureData, list[i].Mok, list[i].MokSize);
+		} else {
+			CertList->SignatureListSize = list[i].MokSize +
+						      sizeof(EFI_SIGNATURE_LIST);
+			CertList->SignatureSize = SHA256_DIGEST_SIZE + sizeof(EFI_GUID);
+
+			CopyMem(CertData, list[i].Mok, list[i].MokSize);
+		}
+		ptr = (uint8_t *)ptr + CertList->SignatureListSize;
 	}
 
-	efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
+	efi_status = uefi_call_wrapper(RT->SetVariable, 5, db_name,
 				       &shim_lock_guid,
 				       EFI_VARIABLE_NON_VOLATILE
 				       | EFI_VARIABLE_BOOTSERVICE_ACCESS,
@@ -877,10 +989,125 @@ static EFI_STATUS write_back_mok_list (M
 	return EFI_SUCCESS;
 }
 
-static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
+static void delete_cert (void *key, UINT32 key_size,
+			 MokListNode *mok, INTN mok_num)
+{
+	EFI_GUID CertType = X509_GUID;
+	int i;
+
+	for (i = 0; i < mok_num; i++) {
+		if (CompareGuid(&(mok[i].Type), &CertType) != 0)
+			continue;
+
+		if (mok[i].MokSize == key_size &&
+		    CompareMem(key, mok[i].Mok, key_size) == 0) {
+			/* Remove the key */
+			mok[i].Mok = NULL;
+			mok[i].MokSize = 0;
+		}
+	}
+}
+
+static int match_hash (UINT8 *hash, UINT32 hash_size, int start,
+		       void *hash_list, UINT32 list_num)
+{
+	UINT8 *ptr;
+	int i;
+
+	ptr = hash_list + sizeof(EFI_GUID);
+	for (i = start; i < list_num; i++) {
+		if (CompareMem(hash, ptr, hash_size) == 0)
+			return i;
+		ptr += hash_size + sizeof(EFI_GUID);
+	}
+
+	return -1;
+}
+
+static void mem_move (void *dest, void *src, UINTN size)
+{
+	UINT8 *d, *s;
+	int i;
+
+	d = (UINT8 *)dest;
+	s = (UINT8 *)src;
+	for (i = 0; i < size; i++)
+		d[i] = s[i];
+}
+
+static void delete_hash_in_list (UINT8 *hash, UINT32 hash_size,
+				 MokListNode *mok, INTN mok_num)
+{
+	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
+	UINT32 sig_size;
+	int i, del_ind;
+	void *start, *end;
+	UINT32 remain;
+
+	sig_size = hash_size + sizeof(EFI_GUID);
+
+	for (i = 0; i < mok_num; i++) {
+		if ((CompareGuid(&(mok[i].Type), &HashType) != 0) ||
+		    (mok[i].MokSize < sig_size))
+			continue;
+
+		del_ind = match_hash(hash, hash_size, 0, mok[i].Mok,
+				     mok[i].MokSize);
+		while (del_ind >= 0) {
+			/* Remove the hash */
+			if (sig_size == mok[i].MokSize) {
+				mok[i].Mok = NULL;
+				mok[i].MokSize = 0;
+				break;
+			}
+
+			start = mok[i].Mok + del_ind * sig_size;
+			end = start + sig_size;
+			remain = mok[i].MokSize - (del_ind + 1)*sig_size;
+
+			mem_move(start, end, remain);
+			mok[i].MokSize -= sig_size;
+
+			del_ind = match_hash(hash, hash_size, del_ind,
+					     mok[i].Mok, mok[i].MokSize);
+		}
+	}
+}
+
+static void delete_hash_list (void *hash_list, UINT32 list_size,
+			      MokListNode *mok, INTN mok_num)
+{
+	UINT32 hash_size;
+	UINT32 hash_num;
+	UINT32 sig_size;
+	UINT8 *hash;
+	int i;
+
+	hash_size = SHA256_DIGEST_SIZE;
+	sig_size = hash_size + sizeof(EFI_GUID);
+	if (list_size < sig_size)
+		return;
+
+	hash_num = list_size / sig_size;
+
+	hash = hash_list + sizeof(EFI_GUID);
+
+	for (i = 0; i < hash_num; i++) {
+		delete_hash_in_list (hash, hash_size, mok, mok_num);
+		hash += sig_size;
+	}
+}
+
+static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
 {
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+	EFI_GUID CertType = X509_GUID;
+	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
 	EFI_STATUS efi_status;
+	CHAR16 *db_name;
+	CHAR16 *auth_name;
+	CHAR16 *err_str1;
+	CHAR16 *err_str2;
 	UINT8 auth[PASSWORD_CRYPT_SIZE];
 	UINTN auth_size = PASSWORD_CRYPT_SIZE;
 	UINT32 attributes;
@@ -888,15 +1115,26 @@ static EFI_STATUS delete_keys (void *Mok
 	UINTN MokListDataSize = 0;
 	MokListNode *mok, *del_key;
 	INTN mok_num, del_num;
-	int i, j;
+	int i;
 
-	efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
+	if (MokX) {
+		db_name = L"MokListX";
+		auth_name = L"MokXDelAuth";
+	} else {
+		db_name = L"MokList";
+		auth_name = L"MokDelAuth";
+	}
+
+	efi_status = uefi_call_wrapper(RT->GetVariable, 5, auth_name,
 				       &shim_lock_guid,
 				       &attributes, &auth_size, auth);
 
 	if (efi_status != EFI_SUCCESS ||
 	    (auth_size != SHA256_DIGEST_SIZE && auth_size != PASSWORD_CRYPT_SIZE)) {
-		console_error(L"Failed to get MokDelAuth", efi_status);
+		if (MokX)
+			console_error(L"Failed to get MokXDelAuth", efi_status);
+		else
+			console_error(L"Failed to get MokDelAuth", efi_status);
 		return efi_status;
 	}
 
@@ -909,15 +1147,18 @@ static EFI_STATUS delete_keys (void *Mok
 	if (efi_status != EFI_SUCCESS)
 		return EFI_ACCESS_DENIED;
 
-	efi_status = get_variable_attr (L"MokList", &MokListData, &MokListDataSize,
+	efi_status = get_variable_attr (db_name, &MokListData, &MokListDataSize,
 				        shim_lock_guid, &attributes);
 	if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
-		console_alertbox((CHAR16 *[]){L"MokList is compromised!",
-					L"Erase all keys in MokList!",
-					NULL});
-		if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
-			console_notify(L"Failed to erase MokList");
+		if (MokX) {
+			err_str1 = L"MokListX is compromised!";
+			err_str2 = L"Erase all keys in MokListX!";
+		} else {
+			err_str1 = L"MokList is compromised!";
+			err_str2 = L"Erase all keys in MokList!";
 		}
+		console_alertbox((CHAR16 *[]){err_str1, err_str2, NULL});
+		LibDeleteVariable(db_name, &shim_lock_guid);
 		return EFI_ACCESS_DENIED;
 	}
 
@@ -933,19 +1174,16 @@ static EFI_STATUS delete_keys (void *Mok
 
 	/* Search and destroy */
 	for (i = 0; i < del_num; i++) {
-		UINT32 key_size = del_key[i].MokSize;
-		void *key = del_key[i].Mok;
-		for (j = 0; j < mok_num; j++) {
-			if (mok[j].MokSize == key_size &&
-			    CompareMem(key, mok[j].Mok, key_size) == 0) {
-				/* Remove the key */
-				mok[j].Mok = NULL;
-				mok[j].MokSize = 0;
-			}
+		if (CompareGuid(&(del_key[i].Type), &CertType) == 0) {
+			delete_cert(del_key[i].Mok, del_key[i].MokSize,
+				    mok, mok_num);
+		} else if (CompareGuid(&(del_key[i].Type), &HashType) == 0) {
+			delete_hash_list(del_key[i].Mok, del_key[i].MokSize,
+					 mok, mok_num);
 		}
 	}
 
-	efi_status = write_back_mok_list(mok, mok_num);
+	efi_status = write_back_mok_list(mok, mok_num, MokX);
 
 	if (MokListData)
 		FreePool(MokListData);
@@ -957,27 +1195,38 @@ static EFI_STATUS delete_keys (void *Mok
 	return efi_status;
 }
 
-static INTN mok_deletion_prompt (void *MokDel, UINTN MokDelSize)
+static INTN mok_deletion_prompt (void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
 {
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
 	EFI_STATUS efi_status;
+	CHAR16 *title;
+
+	if (MokX)
+		title = L"[Delete MOKX]";
+	else
+		title = L"[Delete MOK]";
 
-	if (list_keys(MokDel, MokDelSize, L"[Delete MOK]") != EFI_SUCCESS) {
+	if (list_keys(MokDel, MokDelSize, title) != EFI_SUCCESS) {
 		return 0;
 	}
 
         if (console_yes_no((CHAR16 *[]){L"Delete the key(s)?", NULL}) == 0)
                 return 0;
 
-	efi_status = delete_keys(MokDel, MokDelSize);
+	efi_status = delete_keys(MokDel, MokDelSize, MokX);
 
 	if (efi_status != EFI_SUCCESS) {
 		console_notify(L"Failed to delete keys");
 		return -1;
 	}
 
-	LibDeleteVariable(L"MokDel", &shim_lock_guid);
-	LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
+	if (MokX) {
+		LibDeleteVariable(L"MokXDel", &shim_lock_guid);
+		LibDeleteVariable(L"MokXDelAuth", &shim_lock_guid);
+	} else {
+		LibDeleteVariable(L"MokDel", &shim_lock_guid);
+		LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
+	}
 
 	console_notify(L"The system must now be rebooted");
 	uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
@@ -1396,7 +1645,7 @@ static EFI_STATUS enroll_file (void *dat
 			goto out;
 	}
 
-	mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE);
+	mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE, FALSE);
 out:
 	if (mokbuffer)
 		FreePool(mokbuffer);
@@ -1631,8 +1880,11 @@ static int draw_countdown()
 typedef enum {
 	MOK_CONTINUE_BOOT,
 	MOK_RESET_MOK,
+	MOK_RESET_MOKX,
 	MOK_ENROLL_MOK,
+	MOK_ENROLL_MOKX,
 	MOK_DELETE_MOK,
+	MOK_DELETE_MOKX,
 	MOK_CHANGE_SB,
 	MOK_SET_PW,
 	MOK_CHANGE_DB,
@@ -1645,13 +1897,17 @@ static EFI_STATUS enter_mok_menu(EFI_HAN
 				 void *MokDel, UINTN MokDelSize,
 				 void *MokSB, UINTN MokSBSize,
 				 void *MokPW, UINTN MokPWSize,
-				 void *MokDB, UINTN MokDBSize)
+				 void *MokDB, UINTN MokDBSize,
+				 void *MokXNew, UINTN MokXNewSize,
+				 void *MokXDel, UINTN MokXDelSize)
 {
 	CHAR16 **menu_strings;
 	mok_menu_item *menu_item;
 	int choice = 0;
 	UINT32 MokAuth = 0;
 	UINT32 MokDelAuth = 0;
+	UINT32 MokXAuth = 0;
+	UINT32 MokXDelAuth = 0;
 	UINTN menucount = 3, i = 0;
 	EFI_STATUS efi_status;
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
@@ -1680,12 +1936,34 @@ static EFI_STATUS enter_mok_menu(EFI_HAN
 	   (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE))
 		MokDelAuth = 1;
 
+	efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokXAuth",
+					       &shim_lock_guid,
+					       &attributes, &auth_size, auth);
+
+	if ((efi_status == EFI_SUCCESS) &&
+	    (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE))
+		MokXAuth = 1;
+
+	efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokXDelAuth",
+					       &shim_lock_guid,
+					       &attributes, &auth_size, auth);
+
+	if ((efi_status == EFI_SUCCESS) &&
+	   (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE))
+		MokXDelAuth = 1;
+
 	if (MokNew || MokAuth)
 		menucount++;
 
 	if (MokDel || MokDelAuth)
 		menucount++;
 
+	if (MokXNew || MokXAuth)
+		menucount++;
+
+	if (MokXDel || MokXDelAuth)
+		menucount++;
+
 	if (MokSB)
 		menucount++;
 
@@ -1723,12 +2001,29 @@ static EFI_STATUS enter_mok_menu(EFI_HAN
 		i++;
 	}
 
-	if (MokDel || MokDelAuth) {		
+	if (MokDel || MokDelAuth) {
 		menu_strings[i] = L"Delete MOK";
 		menu_item[i] = MOK_DELETE_MOK;
 		i++;
 	}
 
+	if (MokXNew || MokXAuth) {
+		if (!MokXNew) {
+			menu_strings[i] = L"Reset MOKX";
+			menu_item[i] = MOK_RESET_MOKX;
+		} else {
+			menu_strings[i] = L"Enroll MOKX";
+			menu_item[i] = MOK_ENROLL_MOKX;
+		}
+		i++;
+	}
+
+	if (MokXDel || MokXDelAuth) {
+		menu_strings[i] = L"Delete MOKX";
+		menu_item[i] = MOK_DELETE_MOKX;
+		i++;
+	}
+
 	if (MokSB) {
 		menu_strings[i] = L"Change Secure Boot state";
 		menu_item[i] = MOK_CHANGE_SB;
@@ -1771,13 +2066,22 @@ static EFI_STATUS enter_mok_menu(EFI_HAN
 		case MOK_CONTINUE_BOOT:
 			goto out;
 		case MOK_RESET_MOK:
-			mok_reset_prompt();
+			mok_reset_prompt(FALSE);
 			break;
 		case MOK_ENROLL_MOK:
-			mok_enrollment_prompt(MokNew, MokNewSize, TRUE);
+			mok_enrollment_prompt(MokNew, MokNewSize, TRUE, FALSE);
 			break;
 		case MOK_DELETE_MOK:
-			mok_deletion_prompt(MokDel, MokDelSize);
+			mok_deletion_prompt(MokDel, MokDelSize, FALSE);
+			break;
+		case MOK_RESET_MOKX:
+			mok_reset_prompt(TRUE);
+			break;
+		case MOK_ENROLL_MOKX:
+			mok_enrollment_prompt(MokXNew, MokXNewSize, TRUE, TRUE);
+			break;
+		case MOK_DELETE_MOKX:
+			mok_deletion_prompt(MokXDel, MokXDelSize, TRUE);
 			break;
 		case MOK_CHANGE_SB:
 			mok_sb_prompt(MokSB, MokSBSize);
@@ -1811,13 +2115,15 @@ out:
 static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
 {
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
-	UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0,
-		  MokDBSize = 0;
+	UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
+	UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0;
 	void *MokNew = NULL;
 	void *MokDel = NULL;
 	void *MokSB = NULL;
 	void *MokPW = NULL;
 	void *MokDB = NULL;
+	void *MokXNew = NULL;
+	void *MokXDel = NULL;
 	EFI_STATUS status;
 
 	status = get_variable(L"MokNew", (UINT8 **)&MokNew, &MokNewSize,
@@ -1870,8 +2176,29 @@ static EFI_STATUS check_mok_request(EFI_
 		console_error(L"Could not retrieve MokDB", status);
 	}
 
+	status = get_variable(L"MokXNew", (UINT8 **)&MokXNew, &MokXNewSize,
+				shim_lock_guid);
+	if (status == EFI_SUCCESS) {
+		if (LibDeleteVariable(L"MokXNew", &shim_lock_guid) != EFI_SUCCESS) {
+			console_notify(L"Failed to delete MokXNew");
+		}
+	} else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
+		console_error(L"Could not retrieve MokXNew", status);
+	}
+
+	status = get_variable(L"MokXDel", (UINT8 **)&MokXDel, &MokXDelSize,
+				shim_lock_guid);
+	if (status == EFI_SUCCESS) {
+		if (LibDeleteVariable(L"MokXDel", &shim_lock_guid) != EFI_SUCCESS) {
+			console_notify(L"Failed to delete MokXDel");
+		}
+	} else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
+		console_error(L"Could not retrieve MokXDel", status);
+	}
+
 	enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
-		       MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize);
+		       MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize,
+		       MokXNew, MokXNewSize, MokXDel, MokXDelSize);
 
 	if (MokNew)
 		FreePool (MokNew);
@@ -1888,8 +2215,16 @@ static EFI_STATUS check_mok_request(EFI_
 	if (MokDB)
 		FreePool (MokDB);
 
+	if (MokXNew)
+		FreePool (MokXNew);
+
+	if (MokXDel)
+		FreePool (MokXDel);
+
 	LibDeleteVariable(L"MokAuth", &shim_lock_guid);
 	LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
+	LibDeleteVariable(L"MokXAuth", &shim_lock_guid);
+	LibDeleteVariable(L"MokXDelAuth", &shim_lock_guid);
 
 	return EFI_SUCCESS;
 }
Index: shim-0.7/shim.c
===================================================================
--- shim-0.7.orig/shim.c
+++ shim-0.7/shim.c
@@ -361,6 +361,7 @@ static EFI_STATUS check_blacklist (WIN_C
 				   UINT8 *sha256hash, UINT8 *sha1hash)
 {
 	EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
+	EFI_GUID shim_var = SHIM_LOCK_GUID;
 	EFI_SIGNATURE_LIST *dbx = (EFI_SIGNATURE_LIST *)vendor_dbx;
 
 	if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha256hash,
@@ -384,6 +385,14 @@ static EFI_STATUS check_blacklist (WIN_C
 	if (cert && check_db_cert(L"dbx", secure_var, cert, sha256hash) ==
 				DATA_FOUND)
 		return EFI_ACCESS_DENIED;
+	if (check_db_hash(L"MokListX", shim_var, sha256hash, SHA256_DIGEST_SIZE,
+			  EFI_CERT_SHA256_GUID) == DATA_FOUND) {
+		return EFI_ACCESS_DENIED;
+	}
+	if (cert && check_db_cert(L"MokListX", shim_var, cert, sha256hash) ==
+				DATA_FOUND) {
+		return EFI_ACCESS_DENIED;
+	}
 
 	return EFI_SUCCESS;
 }
@@ -466,7 +475,7 @@ static BOOLEAN secure_mode (void)
 
 	if (sb != 1) {
 		if (verbose)
-			console_notify(L"Secure boot not enabled\n");
+			console_notify(L"Secure boot not enabled");
 		return FALSE;
 	}
 
@@ -479,7 +488,7 @@ static BOOLEAN secure_mode (void)
 
 	if (setupmode == 1) {
 		if (verbose)
-			console_notify(L"Platform is in setup mode\n");
+			console_notify(L"Platform is in setup mode");
 		return FALSE;
 	}
 
@@ -1454,6 +1463,33 @@ EFI_STATUS mirror_mok_list()
 }
 
 /*
+ * Copy the boot-services only MokListX variable to the runtime-accessible
+ * MokListXRT variable. It's not marked NV, so the OS can't modify it.
+ */
+EFI_STATUS mirror_mok_list_x()
+{
+	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+	EFI_STATUS efi_status;
+	UINT8 *Data = NULL;
+	UINTN DataSize = 0;
+
+	efi_status = get_variable(L"MokListX", &Data, &DataSize, shim_lock_guid);
+	if (efi_status != EFI_SUCCESS)
+		return efi_status;
+
+	efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokListXRT",
+				       &shim_lock_guid,
+				       EFI_VARIABLE_BOOTSERVICE_ACCESS
+				       | EFI_VARIABLE_RUNTIME_ACCESS,
+				       DataSize, Data);
+	if (efi_status != EFI_SUCCESS) {
+		console_error(L"Failed to set MokListRT", efi_status);
+	}
+
+	return efi_status;
+}
+
+/*
  * Check if a variable exists
  */
 static BOOLEAN check_var(CHAR16 *varname)
@@ -1484,7 +1520,9 @@ EFI_STATUS check_mok_request(EFI_HANDLE
 
 	if (check_var(L"MokNew") || check_var(L"MokSB") ||
 	    check_var(L"MokPW") || check_var(L"MokAuth") ||
-	    check_var(L"MokDel") || check_var(L"MokDB")) {
+	    check_var(L"MokDel") || check_var(L"MokDB") ||
+	    check_var(L"MokXNew") || check_var(L"MokXDel") ||
+	    check_var(L"MokXAuth")) {
 		efi_status = start_image(image_handle, MOK_MANAGER);
 
 		if (efi_status != EFI_SUCCESS) {
@@ -1768,6 +1806,8 @@ EFI_STATUS efi_main (EFI_HANDLE image_ha
 	 */
 	efi_status = mirror_mok_list();
 
+	efi_status = mirror_mok_list_x();
+
 	/*
 	 * Create the runtime MokIgnoreDB variable so the kernel can make
 	 * use of it
Index: shim-0.7/Makefile
===================================================================
--- shim-0.7.orig/Makefile
+++ shim-0.7/Makefile
@@ -69,7 +69,6 @@ version.c : version.c.in
 
 certdb/secmod.db: shim.crt
 	-mkdir certdb
-	certutil -A -n 'my CA' -d certdb/ -t CT,CT,CT -i ca.crt
 	pk12util -d certdb/ -i shim.p12 -W "" -K ""
 	certutil -d certdb/ -A -i shim.crt -n shim -t u
 
openSUSE Build Service is sponsored by