File shim-mokmanager-support-sha-family.patch of Package shim

From f110c89b169505156741ee4ce4b0952e899ed0d8 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 3 Apr 2014 18:26:37 +0800
Subject: [PATCH 1/5] MokManager: Support SHA1 hash in MOK

Add SHA1 hash support and amend the code to make it easier to support
other SHA digests.
---
 MokManager.c | 121 ++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 75 insertions(+), 46 deletions(-)

Index: shim-0.7/MokManager.c
===================================================================
--- shim-0.7.orig/MokManager.c
+++ shim-0.7/MokManager.c
@@ -25,6 +25,9 @@
 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
 
 EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
+EFI_GUID EFI_CERT_SHA224_GUID = { 0xb6e5233, 0xa65c, 0x44c9, {0x94, 0x7, 0xd9, 0xab, 0x83, 0xbf, 0xc8, 0xbd} };
+EFI_GUID EFI_CERT_SHA384_GUID = { 0xff3e5307, 0x9fd0, 0x48c9, {0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x1} };
+EFI_GUID EFI_CERT_SHA512_GUID = { 0x93e0fae, 0xa6c4, 0x4f50, {0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a} };
 
 #define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
 #define HASH_STRING L"Select a file to trust:\n\n"
@@ -93,31 +96,84 @@ done:
 	return status;
 }
 
+static BOOLEAN is_sha_hash (EFI_GUID Type)
+{
+	EFI_GUID Sha1 = EFI_CERT_SHA1_GUID;
+	EFI_GUID Sha224 = EFI_CERT_SHA224_GUID;
+	EFI_GUID Sha256 = EFI_CERT_SHA256_GUID;
+	EFI_GUID Sha384 = EFI_CERT_SHA384_GUID;
+	EFI_GUID Sha512 = EFI_CERT_SHA512_GUID;
+
+	if (CompareGuid(&Type, &Sha1) == 0)
+		return TRUE;
+	else if (CompareGuid(&Type, &Sha224) == 0)
+		return TRUE;
+	else if (CompareGuid(&Type, &Sha256) == 0)
+		return TRUE;
+	else if (CompareGuid(&Type, &Sha384) == 0)
+		return TRUE;
+	else if (CompareGuid(&Type, &Sha512) == 0)
+		return TRUE;
+
+	return FALSE;
+}
+
+static UINT32 sha_size (EFI_GUID Type)
+{
+	EFI_GUID Sha1 = EFI_CERT_SHA1_GUID;
+	EFI_GUID Sha224 = EFI_CERT_SHA224_GUID;
+	EFI_GUID Sha256 = EFI_CERT_SHA256_GUID;
+	EFI_GUID Sha384 = EFI_CERT_SHA384_GUID;
+	EFI_GUID Sha512 = EFI_CERT_SHA512_GUID;
+
+	if (CompareGuid(&Type, &Sha1) == 0)
+		return SHA1_DIGEST_SIZE;
+	else if (CompareGuid(&Type, &Sha224) == 0)
+		return SHA224_DIGEST_LENGTH;
+	else if (CompareGuid(&Type, &Sha256) == 0)
+		return SHA256_DIGEST_SIZE;
+	else if (CompareGuid(&Type, &Sha384) == 0)
+		return SHA384_DIGEST_LENGTH;
+	else if (CompareGuid(&Type, &Sha512) == 0)
+		return SHA512_DIGEST_LENGTH;
+
+	return 0;
+}
+
+static BOOLEAN is_valid_siglist (EFI_GUID Type, UINT32 SigSize)
+{
+	EFI_GUID CertType = X509_GUID;
+	UINT32 hash_sig_size;
+
+	if (CompareGuid (&Type, &CertType) == 0 && SigSize != 0)
+		return TRUE;
+
+	if (!is_sha_hash (Type))
+		return FALSE;
+
+	hash_sig_size = sha_size (Type) + sizeof(EFI_GUID);
+	if (SigSize != hash_sig_size)
+		return FALSE;
+
+	return TRUE;
+}
+
 static UINT32 count_keys(void *Data, UINTN DataSize)
 {
 	EFI_SIGNATURE_LIST *CertList = Data;
-	EFI_GUID CertType = X509_GUID;
-	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
 	UINTN dbsize = DataSize;
 	UINT32 MokNum = 0;
 
 	while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
-		if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
-		    (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
-			console_notify(L"Doesn't look like a key or hash");
-			dbsize -= CertList->SignatureListSize;
-			CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
-						  CertList->SignatureListSize);
-			continue;
+		if (CertList->SignatureListSize == 0 ||
+		    CertList->SignatureListSize <= CertList->SignatureSize) {
+			console_errorbox(L"Corrupted signature list");
+			return 0;
 		}
 
-		if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
-		    (CertList->SignatureSize != 48)) {
-			console_notify(L"Doesn't look like a valid hash");
-			dbsize -= CertList->SignatureListSize;
-			CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
-						  CertList->SignatureListSize);
-			continue;
+		if (!is_valid_siglist(CertList->SignatureType, CertList->SignatureSize)) {
+			console_errorbox(L"Invalid signature list found");
+			return 0;
 		}
 
 		MokNum++;
@@ -134,7 +190,6 @@ static MokListNode *build_mok_list(UINT3
 	EFI_SIGNATURE_LIST *CertList = Data;
 	EFI_SIGNATURE_DATA *Cert;
 	EFI_GUID CertType = X509_GUID;
-	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
 	UINTN dbsize = DataSize;
 	UINTN count = 0;
 
@@ -146,21 +201,8 @@ static MokListNode *build_mok_list(UINT3
 	}
 
 	while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
-		if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
-		    (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
-			dbsize -= CertList->SignatureListSize;
-			CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
-						  CertList->SignatureListSize);
-			continue;
-		}
-
-		if ((CompareGuid (&CertList->SignatureType, &HashType) == 0) &&
-		    (CertList->SignatureSize != 48)) {
-			dbsize -= CertList->SignatureListSize;
-			CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
-						  CertList->SignatureListSize);
-			continue;
-		}
+		/* Omit the signature check here since we already did it
+		   in count_keys() */
 
 		Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
 		  sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
@@ -380,22 +422,46 @@ static void show_x509_info (X509 *X509Ce
 	FreePool(text);
 }
 
-static void show_sha256_digest (UINT8 *hash)
+static void show_sha_digest (EFI_GUID Type, UINT8 *hash)
 {
+	EFI_GUID Sha1 = EFI_CERT_SHA1_GUID;
+	EFI_GUID Sha224 = EFI_CERT_SHA224_GUID;
+	EFI_GUID Sha256 = EFI_CERT_SHA256_GUID;
+	EFI_GUID Sha384 = EFI_CERT_SHA384_GUID;
+	EFI_GUID Sha512 = EFI_CERT_SHA512_GUID;
 	CHAR16 *text[5];
 	POOL_PRINT hash_string1;
 	POOL_PRINT hash_string2;
 	int i;
+	int length;
+
+	if (CompareGuid(&Type, &Sha1) == 0) {
+		length = SHA1_DIGEST_SIZE;
+		text[0] = L"SHA1 hash";
+	} else if (CompareGuid(&Type, &Sha224) == 0) {
+		length = SHA224_DIGEST_LENGTH;
+		text[0] = L"SHA224 hash";
+	} else if (CompareGuid(&Type, &Sha256) == 0) {
+		length = SHA256_DIGEST_SIZE;
+		text[0] = L"SHA256 hash";
+	} else if (CompareGuid(&Type, &Sha384) == 0) {
+		length = SHA384_DIGEST_LENGTH;
+		text[0] = L"SHA384 hash";
+	} else if (CompareGuid(&Type, &Sha512) == 0) {
+		length = SHA512_DIGEST_LENGTH;
+		text[0] = L"SHA512 hash";
+	} else {
+		return;
+	}
 
 	ZeroMem(&hash_string1, sizeof(hash_string1));
 	ZeroMem(&hash_string2, sizeof(hash_string2));
 
-	text[0] = L"SHA256 hash";
 	text[1] = L"";
 
-	for (i=0; i<16; i++)
+	for (i=0; i<length/2; i++)
 		CatPrint(&hash_string1, L"%02x ", hash[i]);
-	for (i=16; i<32; i++)
+	for (i=length/2; i<length; i++)
 		CatPrint(&hash_string2, L"%02x ", hash[i]);
 
 	text[2] = hash_string1.str;
@@ -411,7 +477,7 @@ static void show_sha256_digest (UINT8 *h
 		FreePool(hash_string2.str);
 }
 
-static void show_efi_hash (void *Mok, UINTN MokSize)
+static void show_efi_hash (EFI_GUID Type, void *Mok, UINTN MokSize)
 {
 	UINTN sig_size;
 	UINTN hash_num;
@@ -420,7 +486,7 @@ static void show_efi_hash (void *Mok, UI
 	int key_num = 0;
 	int i;
 
-	sig_size = SHA256_DIGEST_SIZE + sizeof(EFI_GUID);
+	sig_size = sha_size(Type) + sizeof(EFI_GUID);
 	if ((MokSize % sig_size) != 0) {
 		console_errorbox(L"Corrupted Hash List");
 		return;
@@ -429,7 +495,7 @@ static void show_efi_hash (void *Mok, UI
 
 	if (hash_num == 1) {
 		hash = (UINT8 *)Mok + sizeof(EFI_GUID);
-		show_sha256_digest(hash);
+		show_sha_digest(Type, hash);
 		return;
 	}
 
@@ -452,7 +518,7 @@ static void show_efi_hash (void *Mok, UI
 			break;
 
 		hash = (UINT8 *)Mok + sig_size*key_num + sizeof(EFI_GUID);
-		show_sha256_digest(hash);
+		show_sha_digest(Type, hash);
 	}
 
 	for (i=0; menu_strings[i] != NULL; i++)
@@ -467,7 +533,6 @@ static void show_mok_info (EFI_GUID Type
 	UINT8 hash[SHA1_DIGEST_SIZE];
 	X509 *X509Cert;
 	EFI_GUID CertType = X509_GUID;
-	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
 
 	if (!Mok || MokSize == 0)
 		return;
@@ -488,8 +553,8 @@ static void show_mok_info (EFI_GUID Type
 			console_notify(L"Not a valid X509 certificate");
 			return;
 		}
-	} else if (CompareGuid (&Type, &HashType) == 0) {
-		show_efi_hash(Mok, MokSize);
+	} else if (is_sha_hash(Type)) {
+		show_efi_hash(Type, Mok, MokSize);
 	}
 }
 
@@ -504,15 +569,18 @@ static EFI_STATUS list_keys (void *KeyLi
 	if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) +
 			   sizeof(EFI_SIGNATURE_DATA))) {
 		console_notify(L"No MOK keys found");
-		return 0;
+		return EFI_NOT_FOUND;
 	}
 
 	MokNum = count_keys(KeyList, KeyListSize);
+	if (MokNum == 0) {
+		console_errorbox(L"Invalid key list");
+		return EFI_ABORTED;
+	}
 	keys = build_mok_list(MokNum, KeyList, KeyListSize);
-
 	if (!keys) {
-		console_notify(L"Failed to construct key list");
-		return 0;
+		console_errorbox(L"Failed to construct key list");
+		return EFI_ABORTED;
 	}
 
 	menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (MokNum + 2));
@@ -837,7 +905,7 @@ static EFI_STATUS store_keys (void *MokN
 	return EFI_SUCCESS;
 }
 
-static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth,
+static INTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth,
 				    BOOLEAN MokX)
 {
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
@@ -974,7 +1042,7 @@ static EFI_STATUS write_back_mok_list (M
 		} else {
 			CertList->SignatureListSize = list[i].MokSize +
 						      sizeof(EFI_SIGNATURE_LIST);
-			CertList->SignatureSize = SHA256_DIGEST_SIZE + sizeof(EFI_GUID);
+			CertList->SignatureSize = sha_size(list[i].Type) + sizeof(EFI_GUID);
 
 			CopyMem(CertData, list[i].Mok, list[i].MokSize);
 		}
@@ -1043,10 +1111,9 @@ static void mem_move (void *dest, void *
 		d[i] = s[i];
 }
 
-static void delete_hash_in_list (UINT8 *hash, UINT32 hash_size,
+static void delete_hash_in_list (EFI_GUID Type, UINT8 *hash, UINT32 hash_size,
 				 MokListNode *mok, INTN mok_num)
 {
-	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
 	UINT32 sig_size;
 	UINT32 list_num;
 	int i, del_ind;
@@ -1056,7 +1123,7 @@ static void delete_hash_in_list (UINT8 *
 	sig_size = hash_size + sizeof(EFI_GUID);
 
 	for (i = 0; i < mok_num; i++) {
-		if ((CompareGuid(&(mok[i].Type), &HashType) != 0) ||
+		if ((CompareGuid(&(mok[i].Type), &Type) != 0) ||
 		    (mok[i].MokSize < sig_size))
 			continue;
 
@@ -1086,7 +1153,7 @@ static void delete_hash_in_list (UINT8 *
 	}
 }
 
-static void delete_hash_list (void *hash_list, UINT32 list_size,
+static void delete_hash_list (EFI_GUID Type, void *hash_list, UINT32 list_size,
 			      MokListNode *mok, INTN mok_num)
 {
 	UINT32 hash_size;
@@ -1095,7 +1162,7 @@ static void delete_hash_list (void *hash
 	UINT8 *hash;
 	int i;
 
-	hash_size = SHA256_DIGEST_SIZE;
+	hash_size = sha_size (Type);
 	sig_size = hash_size + sizeof(EFI_GUID);
 	if (list_size < sig_size)
 		return;
@@ -1105,7 +1172,7 @@ static void delete_hash_list (void *hash
 	hash = hash_list + sizeof(EFI_GUID);
 
 	for (i = 0; i < hash_num; i++) {
-		delete_hash_in_list (hash, hash_size, mok, mok_num);
+		delete_hash_in_list (Type, hash, hash_size, mok, mok_num);
 		hash += sig_size;
 	}
 }
@@ -1114,7 +1181,6 @@ static EFI_STATUS delete_keys (void *Mok
 {
 	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;
@@ -1161,7 +1227,13 @@ static EFI_STATUS delete_keys (void *Mok
 
 	efi_status = get_variable_attr (db_name, &MokListData, &MokListDataSize,
 				        shim_lock_guid, &attributes);
-	if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
+	if (efi_status != EFI_SUCCESS) {
+		if (MokX)
+			console_errorbox(L"Failed to retrieve MokListX");
+		else
+			console_errorbox(L"Failed to retrieve MokList");
+		return EFI_ABORTED;
+	} else if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
 		if (MokX) {
 			err_str1 = L"MokListX is compromised!";
 			err_str2 = L"Erase all keys in MokListX!";
@@ -1170,7 +1242,11 @@ static EFI_STATUS delete_keys (void *Mok
 			err_str2 = L"Erase all keys in MokList!";
 		}
 		console_alertbox((CHAR16 *[]){err_str1, err_str2, NULL});
-		LibDeleteVariable(db_name, &shim_lock_guid);
+		uefi_call_wrapper(RT->SetVariable, 5, db_name,
+				  &shim_lock_guid,
+				  EFI_VARIABLE_NON_VOLATILE |
+				  EFI_VARIABLE_BOOTSERVICE_ACCESS,
+				  0, NULL);
 		return EFI_ACCESS_DENIED;
 	}
 
@@ -1180,23 +1256,56 @@ static EFI_STATUS delete_keys (void *Mok
 
 	/* Construct lists */
 	mok_num = count_keys(MokListData, MokListDataSize);
+	if (mok_num == 0) {
+		if (MokX) {
+			err_str1 = L"Failed to construct the key list of MokListX";
+			err_str2 = L"Reset MokListX!";
+		} else {
+			err_str1 = L"Failed to construct the key list of MokList";
+			err_str2 = L"Reset MokList!";
+		}
+		console_alertbox((CHAR16 *[]){err_str1, err_str2, NULL});
+		uefi_call_wrapper(RT->SetVariable, 5, db_name,
+				  &shim_lock_guid,
+				  EFI_VARIABLE_NON_VOLATILE |
+				  EFI_VARIABLE_BOOTSERVICE_ACCESS,
+				  0, NULL);
+		efi_status = EFI_ABORTED;
+		goto error;
+	}
 	mok = build_mok_list(mok_num, MokListData, MokListDataSize);
+	if (!mok) {
+		console_errorbox(L"Failed to construct key list");
+		efi_status = EFI_ABORTED;
+		goto error;
+	}
 	del_num = count_keys(MokDel, MokDelSize);
+	if (del_num == 0) {
+		console_errorbox(L"Invalid key delete list");
+		efi_status = EFI_ABORTED;
+		goto error;
+	}
 	del_key = build_mok_list(del_num, MokDel, MokDelSize);
+	if (!del_key) {
+		console_errorbox(L"Failed to construct key list");
+		efi_status = EFI_ABORTED;
+		goto error;
+	}
 
 	/* Search and destroy */
 	for (i = 0; i < del_num; i++) {
 		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);
+		} else if (is_sha_hash(del_key[i].Type)) {
+			delete_hash_list(del_key[i].Type, del_key[i].Mok,
+					 del_key[i].MokSize, mok, mok_num);
 		}
 	}
 
 	efi_status = write_back_mok_list(mok, mok_num, MokX);
 
+error:
 	if (MokListData)
 		FreePool(MokListData);
 	if (mok)
openSUSE Build Service is sponsored by