From 49355a83722494099caeb23b46637b2c94a6ab9e Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 18 Feb 2014 17:29:19 +0800
Subject: [PATCH 1/3] Show the build-in certificate prompt

This is an openSUSE-only patch.

Pop up a window to ask if the user is willing to trust the built-in
openSUSE certificate.

If yes, set openSUSE_Verify, a BootService variable, to 1, and shim
won't bother the user afterward.

If no, continue the booting process without using the built-in
certificate to verify the EFI images, and the window will show up
again after reboot.

The state will store in use_openSUSE_cert, a volatile RT variable.
---
 mok.c  |  3 ++-
 shim.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 shim.h |  1 +
 3 files changed, 71 insertions(+), 2 deletions(-)

Index: shim-15.6/mok.c
===================================================================
--- shim-15.6.orig/mok.c
+++ shim-15.6/mok.c
@@ -46,7 +46,8 @@ static EFI_STATUS check_mok_request(EFI_
 	    check_var(L"MokPW") || check_var(L"MokAuth") ||
 	    check_var(L"MokDel") || check_var(L"MokDB") ||
 	    check_var(L"MokXNew") || check_var(L"MokXDel") ||
-	    check_var(L"MokXAuth") || check_var(L"MokListTrustedNew")) {
+	    check_var(L"MokXAuth") || check_var(L"MokListTrustedNew") ||
+	    check_var(L"ClearVerify")) {
 		efi_status = start_image(image_handle, MOK_MANAGER);
 
 		if (EFI_ERROR(efi_status)) {
@@ -62,7 +63,8 @@ static vendor_addend_category_t
 categorize_authorized(struct mok_state_variable *v)
 {
 	if (!(v->addend && v->addend_size &&
-	      *v->addend && *v->addend_size)) {
+	      *v->addend && *v->addend_size &&
+	      use_builtin_cert)) {
 		return VENDOR_ADDEND_NONE;
 	}
 
Index: shim-15.6/shim.c
===================================================================
--- shim-15.6.orig/shim.c
+++ shim-15.6/shim.c
@@ -496,6 +496,8 @@ verify_one_signature(WIN_CERTIFICATE_EFI
 	}
 
 	efi_status = EFI_NOT_FOUND;
+	if (!use_builtin_cert)
+		return efi_status;
 #if defined(ENABLE_SHIM_CERT)
 	/*
 	 * Check against the shim build key
@@ -1568,6 +1570,69 @@ shim_fini(void)
 	console_fini();
 }
 
+#define VENDOR_VERIFY L"openSUSE_Verify"
+
+/* Show the built-in certificate prompt if necessary */
+static int builtin_cert_prompt(void)
+{
+	EFI_STATUS status;
+	UINT32 attributes;
+	UINTN len = sizeof(UINT8);
+	UINT8 data;
+
+	use_builtin_cert = FALSE;
+
+	if (vendor_cert_size == 0)
+		return 0;
+
+	status = gRT->GetVariable(VENDOR_VERIFY, &SHIM_LOCK_GUID,
+				  &attributes, &len, (void *)&data);
+	if (status != EFI_SUCCESS ||
+	    (attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
+		int choice;
+
+		if (status != EFI_NOT_FOUND)
+			LibDeleteVariable(VENDOR_VERIFY, &SHIM_LOCK_GUID);
+
+		CHAR16 *str[] = {L"Trust openSUSE Certificate",
+				 L"",
+				 L"Do you agree to use the built-in openSUSE certificate",
+				 L"to verify boot loaders and kernels?",
+				 NULL};
+		choice = console_yes_no(str);
+		if (choice != 1) {
+			data = 0;
+			goto done;
+		}
+
+		data = 1;
+		status = gRT->SetVariable(VENDOR_VERIFY, &SHIM_LOCK_GUID,
+					  EFI_VARIABLE_NON_VOLATILE |
+					  EFI_VARIABLE_BOOTSERVICE_ACCESS,
+					  sizeof(UINT8), &data);
+		if (status != EFI_SUCCESS) {
+			console_error(L"Failed to set openSUSE_Verify", status);
+			return -1;
+		}
+	}
+
+	use_builtin_cert = TRUE;
+	data = 1;
+
+done:
+	/* Setup a runtime variable to show the current state */
+	status = gRT->SetVariable(L"use_openSUSE_cert", &SHIM_LOCK_GUID,
+				  EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				  EFI_VARIABLE_RUNTIME_ACCESS,
+				  sizeof(UINT8), &data);
+	if (status != EFI_SUCCESS) {
+		console_error(L"Failed to set use_openSUSE_cert", status);
+		return -1;
+	}
+
+	return 0;
+}
+
 extern EFI_STATUS
 efi_main(EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab);
 
@@ -1708,6 +1773,9 @@ efi_main (EFI_HANDLE passed_image_handle
 	 */
 	debug_hook();
 
+	if (secure_mode() && (builtin_cert_prompt() != 0))
+		return EFI_ABORTED;
+
 	efi_status = set_sbat_uefi_variable();
 	if (EFI_ERROR(efi_status) && secure_mode()) {
 		perror(L"%s variable initialization failed\n", SBAT_VAR_NAME);
Index: shim-15.6/MokManager.c
===================================================================
--- shim-15.6.orig/MokManager.c
+++ shim-15.6/MokManager.c
@@ -1864,6 +1864,36 @@ mokpw_done:
 	return EFI_SUCCESS;
 }
 
+static INTN mok_clear_verify_prompt(void *ClearVerify, UINTN ClearVerifySize) {
+	EFI_STATUS status;
+
+        if (console_yes_no((CHAR16 *[]){L"Do you want to revoke openSUSE certificate?", NULL}) != 1)
+                return 0;
+
+	if (ClearVerifySize == PASSWORD_CRYPT_SIZE) {
+		status = match_password((PASSWORD_CRYPT *)ClearVerify, NULL, 0,
+					 NULL, NULL);
+	} else {
+		status = EFI_INVALID_PARAMETER;
+	}
+	if (status != EFI_SUCCESS)
+		return -1;
+
+	status = gRT->SetVariable(L"openSUSE_Verify", &SHIM_LOCK_GUID,
+				  EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				  EFI_VARIABLE_NON_VOLATILE,
+				  0, NULL);
+	if (status != EFI_SUCCESS) {
+		console_error(L"Failed to delete openSUSE_Verify", status);
+		return -1;
+	}
+
+	console_notify(L"The system must now be rebooted");
+	gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
+	console_notify(L"Failed to reboot");
+	return -1;
+}
+
 static BOOLEAN verify_certificate(UINT8 * cert, UINTN size)
 {
 	X509 *X509Cert;
@@ -2195,6 +2225,7 @@ typedef enum {
 	MOK_CHANGE_SB,
 	MOK_SET_PW,
 	MOK_CHANGE_DB,
+	MOK_CLEAR_VERIFY,
 	MOK_KEY_ENROLL,
 	MOK_HASH_ENROLL,
 	MOK_CHANGE_TML
@@ -2217,7 +2248,9 @@ static EFI_STATUS enter_mok_menu(EFI_HAN
 				 void *MokDB, UINTN MokDBSize,
 				 void *MokXNew, UINTN MokXNewSize,
 				 void *MokXDel, UINTN MokXDelSize,
-				 void *MokTML, UINTN MokTMLSize)
+				 void *MokTML, UINTN MokTMLSize,
+				 void *ClearVerify, UINTN ClearVerifySize)
+
 {
 	CHAR16 **menu_strings = NULL;
 	mok_menu_item *menu_item = NULL;
@@ -2296,6 +2329,9 @@ static EFI_STATUS enter_mok_menu(EFI_HAN
 		if (MokTML)
 			menucount++;
 
+		if (ClearVerify)
+			menucount++;
+
 		menu_strings = AllocateZeroPool(sizeof(CHAR16 *) *
 						(menucount + 1));
 		if (!menu_strings)
@@ -2373,6 +2409,12 @@ static EFI_STATUS enter_mok_menu(EFI_HAN
 			i++;
 		}
 
+		if (ClearVerify) {
+			menu_strings[i] = L"Revoke openSUSE certificate";
+			menu_item[i] = MOK_CLEAR_VERIFY;
+			i++;
+		}
+
 		menu_strings[i] = L"Enroll key from disk";
 		menu_item[i] = MOK_KEY_ENROLL;
 		i++;
@@ -2477,6 +2519,9 @@ static EFI_STATUS enter_mok_menu(EFI_HAN
 			if (!EFI_ERROR(efi_status))
 				MokDB = NULL;
 			break;
+		case MOK_CLEAR_VERIFY:
+			mok_clear_verify_prompt(ClearVerify, ClearVerifySize);
+			break;
 		case MOK_KEY_ENROLL:
 			efi_status = mok_key_enroll();
 			break;
@@ -2519,6 +2564,7 @@ static EFI_STATUS check_mok_request(EFI_
 {
 	UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
 	UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0, MokTMLSize = 0;
+	UINTN ClearVerifySize = 0;
 	void *MokNew = NULL;
 	void *MokDel = NULL;
 	void *MokSB = NULL;
@@ -2527,6 +2573,7 @@ static EFI_STATUS check_mok_request(EFI_
 	void *MokXNew = NULL;
 	void *MokXDel = NULL;
 	void *MokTML = NULL;
+	void *ClearVerify = NULL;
 	EFI_STATUS efi_status;
 
 	efi_status = get_variable(L"MokNew", (UINT8 **) & MokNew, &MokNewSize,
@@ -2611,9 +2658,20 @@ static EFI_STATUS check_mok_request(EFI_
 		console_error(L"Could not retrieve MokXDel", efi_status);
 	}
 
+	efi_status = get_variable(L"ClearVerify", (UINT8 **)&ClearVerify,
+				  &ClearVerifySize, SHIM_LOCK_GUID);
+	if (!EFI_ERROR(efi_status)) {
+		efi_status = LibDeleteVariable(L"ClearVerify", &SHIM_LOCK_GUID);
+		if (EFI_ERROR(efi_status))
+			console_notify(L"Failed to delete ClearVerify");
+	} else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
+		console_error(L"Could not retrieve ClearVerify", efi_status);
+	}
+
 	enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
 		       MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize,
-		       MokXNew, MokXNewSize, MokXDel, MokXDelSize, MokTML, MokTMLSize);
+		       MokXNew, MokXNewSize, MokXDel, MokXDelSize, MokTML, MokTMLSize,
+		       ClearVerify, ClearVerifySize);
 
 	if (MokNew)
 		FreePool(MokNew);
@@ -2639,6 +2697,9 @@ static EFI_STATUS check_mok_request(EFI_
 	if (MokTML)
 		FreePool(MokTML);
 
+	if (ClearVerify)
+		FreePool (ClearVerify);
+
 	LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
 	LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID);
 	LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
Index: shim-15.6/globals.c
===================================================================
--- shim-15.6.orig/globals.c
+++ shim-15.6/globals.c
@@ -25,6 +25,7 @@ UINT8 *build_cert;
  */
 verification_method_t verification_method;
 int loader_is_participating;
+BOOLEAN use_builtin_cert;
 
 UINT8 user_insecure_mode;
 UINT8 ignore_db;
Index: shim-15.6/shim.h
===================================================================
--- shim-15.6.orig/shim.h
+++ shim-15.6/shim.h
@@ -270,6 +270,7 @@ extern UINT8 mok_policy;
 extern UINT8 in_protocol;
 extern void *load_options;
 extern UINT32 load_options_size;
+extern BOOLEAN use_builtin_cert;
 
 BOOLEAN secure_mode (void);
 
