File mokutil-mokx-support.patch of Package mokutil

From 65c8d2eb32beda5e90af891de3e5bda41a8aa6f1 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Mon, 21 Oct 2013 17:49:33 +0800
Subject: [PATCH 01/20] Update TODO

---
 TODO | 16 ++--------------
 1 file changed, 2 insertions(+), 14 deletions(-)

diff --git a/TODO b/TODO
index 373e48d..465835a 100644
--- a/TODO
+++ b/TODO
@@ -1,17 +1,5 @@
-* Validate the DER file [DONE]
 * Show the detail of the DER file when enrolling (?)
 * Add an option to slience the output (?)
-* Show the current value of MokNew and MokListRT [DONE]
-* Request the user to input a password before enrolling [DONE]
-* Read the list from a volatile RT variable [DONE]
-* Export keys in MokListRT [DONE]
 * List hashes in MokListRT
-* Add a new command to probe the state of SecureBoot
-  - SecureBoot, EFI_GLOBAL_VARIABLE
-* Do not to enroll duplicate key
-  - compare the keys in MokListRT before enrolling the new keys
-  - compare the keys in MokNew
-  - add a new command to check duplicate
-* Add a new command to append the new key request to the old one
-  - use the old password to verify the old request
-* Delete a specific key
+* Support MokX
+* Import hash into MokNew, NokDel, MokXNew
-- 
1.8.4


From 012d82be0468e876a10691fbabab2ed11b7a4954 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 22 Oct 2013 14:24:13 +0800
Subject: [PATCH 02/20] Show the hashes in the database

---
 src/efi.h       |   2 +-
 src/mokutil.c   | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/signature.h |  14 ++++++--
 3 files changed, 113 insertions(+), 13 deletions(-)

diff --git a/src/efi.h b/src/efi.h
index a622a2b..33579c5 100644
--- a/src/efi.h
+++ b/src/efi.h
@@ -102,7 +102,7 @@ EFI_GUID( 0x47c7b226, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72,
 EFI_GUID( 0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
 
 static inline int
-efi_guidcmp(efi_guid_t left, efi_guid_t right)
+efi_guidcmp(const efi_guid_t left, const efi_guid_t right)
 {
 	return memcmp(&left, &right, sizeof (efi_guid_t));
 }
diff --git a/src/mokutil.c b/src/mokutil.c
index e4e247c..62690ef 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -157,14 +157,29 @@ test_and_delete_var (const char *var_name)
 	return 0;
 }
 
+static uint32_t
+signature_size (efi_guid_t hash_type)
+{
+	if (efi_guidcmp (hash_type, EfiHashSha1Guid) == 0)
+		return (SHA_DIGEST_LENGTH + sizeof(efi_guid_t));
+	else if (efi_guidcmp (hash_type, EfiHashSha224Guid) == 0)
+		return (SHA224_DIGEST_LENGTH + sizeof(efi_guid_t));
+	else if (efi_guidcmp (hash_type, EfiHashSha256Guid) == 0)
+		return (SHA256_DIGEST_LENGTH + sizeof(efi_guid_t));
+	else if (efi_guidcmp (hash_type, EfiHashSha384Guid) == 0)
+		return (SHA384_DIGEST_LENGTH + sizeof(efi_guid_t));
+	else if (efi_guidcmp (hash_type, EfiHashSha512Guid) == 0)
+		return (SHA512_DIGEST_LENGTH + sizeof(efi_guid_t));
+
+	return 0;
+}
+
 static MokListNode*
 build_mok_list (void *data, unsigned long data_size, uint32_t *mok_num)
 {
 	MokListNode *list;
 	EFI_SIGNATURE_LIST *CertList = data;
 	EFI_SIGNATURE_DATA *Cert;
-	efi_guid_t CertType = EfiCertX509Guid;
-	efi_guid_t HashType = EfiHashSha256Guid;
 	unsigned long dbsize = data_size;
 	unsigned long count = 0;
 
@@ -176,16 +191,20 @@ build_mok_list (void *data, unsigned long data_size, uint32_t *mok_num)
 	}
 
 	while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
-		if ((efi_guidcmp (CertList->SignatureType, CertType) != 0) &&
-		    (efi_guidcmp (CertList->SignatureType, HashType) != 0)) {
+		if ((efi_guidcmp (CertList->SignatureType, EfiCertX509Guid) != 0) &&
+		    (efi_guidcmp (CertList->SignatureType, EfiHashSha1Guid) != 0) &&
+		    (efi_guidcmp (CertList->SignatureType, EfiHashSha224Guid) != 0) &&
+		    (efi_guidcmp (CertList->SignatureType, EfiHashSha256Guid) != 0) &&
+		    (efi_guidcmp (CertList->SignatureType, EfiHashSha384Guid) != 0) &&
+		    (efi_guidcmp (CertList->SignatureType, EfiHashSha512Guid) != 0)) {
 			dbsize -= CertList->SignatureListSize;
 			CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
 						  CertList->SignatureListSize);
 			continue;
 		}
 
-		if ((efi_guidcmp (CertList->SignatureType, HashType) == 0) &&
-		    (CertList->SignatureSize != 48)) {
+		if ((efi_guidcmp (CertList->SignatureType, EfiCertX509Guid) != 0) &&
+		    (CertList->SignatureSize != signature_size (CertList->SignatureType))) {
 			dbsize -= CertList->SignatureListSize;
 			CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
 						  CertList->SignatureListSize);
@@ -203,8 +222,18 @@ build_mok_list (void *data, unsigned long data_size, uint32_t *mok_num)
 		}
 
 		list[count].header = CertList;
-		list[count].mok_size = CertList->SignatureSize - sizeof(efi_guid_t);
-		list[count].mok = (void *)Cert->SignatureData;
+		if (efi_guidcmp (CertList->SignatureType, EfiCertX509Guid) == 0) {
+			/* X509 certificate */
+			list[count].mok_size = CertList->SignatureSize -
+					       sizeof(efi_guid_t);
+			list[count].mok = (void *)Cert->SignatureData;
+		} else {
+			/* hash array */
+			list[count].mok_size = CertList->SignatureListSize -
+					       sizeof(EFI_SIGNATURE_LIST) -
+					       CertList->SignatureHeaderSize;
+			list[count].mok = (void *)Cert;
+		}
 
 		count++;
 		dbsize -= CertList->SignatureListSize;
@@ -258,6 +287,64 @@ print_x509 (char *cert, int cert_size)
 }
 
 static int
+print_hash_array (efi_guid_t hash_type, void *hash_array, uint32_t array_size)
+{
+	uint32_t hash_size, remain;
+	uint32_t sig_size;
+	uint8_t *hash;
+	const char *name;
+	int i;
+
+	if (!hash_array || array_size == 0) {
+		fprintf (stderr, "invalid hash array\n");
+		return -1;
+	}
+
+	if (efi_guidcmp (hash_type, EfiHashSha1Guid) == 0) {
+		name = "SHA1";
+		hash_size = SHA_DIGEST_LENGTH;
+	} else if (efi_guidcmp (hash_type, EfiHashSha224Guid) == 0) {
+		name = "SHA224";
+		hash_size = SHA224_DIGEST_LENGTH;
+	} else if (efi_guidcmp (hash_type, EfiHashSha256Guid) == 0) {
+		name = "SHA256";
+		hash_size = SHA256_DIGEST_LENGTH;
+	} else if (efi_guidcmp (hash_type, EfiHashSha384Guid) == 0) {
+		name = "SHA384";
+		hash_size = SHA384_DIGEST_LENGTH;
+	} else if (efi_guidcmp (hash_type, EfiHashSha512Guid) == 0) {
+		name = "SHA512";
+		hash_size = SHA512_DIGEST_LENGTH;
+	} else {
+		fprintf (stderr, "unknown hash type\n");
+		return -1;
+	}
+	sig_size = hash_size + sizeof(efi_guid_t);
+
+	printf ("  [%s]\n", name);
+
+	remain = array_size;
+	hash = (uint8_t *)hash_array;
+
+	while (remain > 0) {
+		if (remain < sig_size) {
+			fprintf (stderr, "invalid array size\n");
+			return -1;
+		}
+
+		printf ("  ");
+		hash += sizeof(efi_guid_t);
+		for (i = 0; i<hash_size; i++)
+			printf ("%02x", *(hash + i));
+		printf ("\n");
+		hash += hash_size;
+		remain -= sig_size;
+	}
+
+	return 0;
+}
+
+static int
 list_keys (efi_variable_t *var)
 {
 	uint32_t mok_num;
@@ -271,7 +358,12 @@ list_keys (efi_variable_t *var)
 
 	for (i = 0; i < mok_num; i++) {
 		printf ("[key %d]\n", i+1);
-		print_x509 ((char *)list[i].mok, list[i].mok_size);
+		if (efi_guidcmp (list[i].header->SignatureType, EfiCertX509Guid) == 0) {
+			print_x509 ((char *)list[i].mok, list[i].mok_size);
+		} else {
+			print_hash_array (list[i].header->SignatureType,
+					  list[i].mok, list[i].mok_size);
+		}
 		if (i < mok_num - 1)
 			printf ("\n");
 	}
diff --git a/src/signature.h b/src/signature.h
index df88e98..02f0211 100644
--- a/src/signature.h
+++ b/src/signature.h
@@ -28,11 +28,17 @@
  * version.  If you delete this exception statement from all source
  * files in the program, then also delete it here.
  */
-#define SHA256_DIGEST_SIZE  32
+#ifndef SIGNATURE_H
+#define SIGNATURE_H
 
-#define EfiHashSha1Guid EFI_GUID (0x826ca512, 0xcf10, 0x4ac9, 0xb1, 0x87, 0xbe, 0x1, 0x49, 0x66, 0x31, 0xbd)
+#include "efi.h"
+
+#define EfiHashSha1Guid   EFI_GUID (0x826ca512, 0xcf10, 0x4ac9, 0xb1, 0x87, 0xbe, 0x1, 0x49, 0x66, 0x31, 0xbd)
+#define EfiHashSha224Guid EFI_GUID (0xb6e5233, 0xa65c, 0x44c9, 0x94, 0x7, 0xd9, 0xab, 0x83, 0xbf, 0xc8, 0xbd)
 #define EfiHashSha256Guid EFI_GUID (0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28)
-#define EfiCertX509Guid EFI_GUID (0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
+#define EfiHashSha384Guid EFI_GUID (0xff3e5307, 0x9fd0, 0x48c9, 0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x1)
+#define EfiHashSha512Guid EFI_GUID (0x93e0fae, 0xa6c4, 0x4f50, 0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a)
+#define EfiCertX509Guid   EFI_GUID (0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
 
 typedef struct {
 	///
@@ -71,3 +77,5 @@ typedef struct {
 	/// EFI_SIGNATURE_DATA Signatures[][SignatureSize];
 	///
 } __attribute__ ((packed)) EFI_SIGNATURE_LIST;
+
+#endif /* SIGNATURE_H */
-- 
1.8.4


From 77a215f86139b21fd55dca4d032b7269f62b51c1 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 22 Oct 2013 14:34:21 +0800
Subject: [PATCH 03/20] Don't allocate the MOK list until there is a node

---
 src/mokutil.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index 62690ef..ec476dd 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -177,19 +177,12 @@ signature_size (efi_guid_t hash_type)
 static MokListNode*
 build_mok_list (void *data, unsigned long data_size, uint32_t *mok_num)
 {
-	MokListNode *list;
+	MokListNode *list = NULL;
 	EFI_SIGNATURE_LIST *CertList = data;
 	EFI_SIGNATURE_DATA *Cert;
 	unsigned long dbsize = data_size;
 	unsigned long count = 0;
 
-	list = malloc(sizeof(MokListNode));
-
-	if (!list) {
-		fprintf(stderr, "Unable to allocate MOK list\n");
-		return NULL;
-	}
-
 	while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
 		if ((efi_guidcmp (CertList->SignatureType, EfiCertX509Guid) != 0) &&
 		    (efi_guidcmp (CertList->SignatureType, EfiHashSha1Guid) != 0) &&
-- 
1.8.4


From befae0e92ea24e35208b07786857d195ce8aa086 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 22 Oct 2013 14:40:58 +0800
Subject: [PATCH 04/20] Skip hashes while exporting MokListRT

---
 src/mokutil.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/mokutil.c b/src/mokutil.c
index ec476dd..04f7655 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1119,6 +1119,10 @@ export_moks ()
 	/* mode 644 */
 	mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
 	for (i = 0; i < mok_num; i++) {
+		if (efi_guidcmp (list[i].header->SignatureType, EfiCertX509Guid) != 0)
+			continue;
+
+		/* Dump X509 certificate to files */
 		snprintf (filename, PATH_MAX, "MOK-%04d.der", i+1);
 		fd = open (filename, O_CREAT | O_WRONLY, mode);
 		if (fd == -1) {
-- 
1.8.4


From 9cfc5f93e15e05dabf46a86e4f8e899e32443176 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 22 Oct 2013 16:05:33 +0800
Subject: [PATCH 05/20] Match the hashes in the database

---
 src/mokutil.c | 162 +++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 109 insertions(+), 53 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index 04f7655..fa5d668 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -157,19 +157,50 @@ test_and_delete_var (const char *var_name)
 	return 0;
 }
 
+static const char*
+efi_hash_to_string (efi_guid_t hash_type)
+{
+	if (efi_guidcmp (hash_type, EfiHashSha1Guid) == 0) {
+		return "SHA1";
+	} else if (efi_guidcmp (hash_type, EfiHashSha224Guid) == 0) {
+		return "SHA224";
+	} else if (efi_guidcmp (hash_type, EfiHashSha256Guid) == 0) {
+		return "SHA256";
+	} else if (efi_guidcmp (hash_type, EfiHashSha384Guid) == 0) {
+		return "SHA384";
+	} else if (efi_guidcmp (hash_type, EfiHashSha512Guid) == 0) {
+		return "SHA512";
+	}
+
+	return NULL;
+}
+
+static uint32_t
+efi_hash_size (efi_guid_t hash_type)
+{
+	if (efi_guidcmp (hash_type, EfiHashSha1Guid) == 0) {
+		return SHA_DIGEST_LENGTH;
+	} else if (efi_guidcmp (hash_type, EfiHashSha224Guid) == 0) {
+		return SHA224_DIGEST_LENGTH;
+	} else if (efi_guidcmp (hash_type, EfiHashSha256Guid) == 0) {
+		return SHA256_DIGEST_LENGTH;
+	} else if (efi_guidcmp (hash_type, EfiHashSha384Guid) == 0) {
+		return SHA384_DIGEST_LENGTH;
+	} else if (efi_guidcmp (hash_type, EfiHashSha512Guid) == 0) {
+		return SHA512_DIGEST_LENGTH;
+	}
+
+	return 0;
+}
+
 static uint32_t
 signature_size (efi_guid_t hash_type)
 {
-	if (efi_guidcmp (hash_type, EfiHashSha1Guid) == 0)
-		return (SHA_DIGEST_LENGTH + sizeof(efi_guid_t));
-	else if (efi_guidcmp (hash_type, EfiHashSha224Guid) == 0)
-		return (SHA224_DIGEST_LENGTH + sizeof(efi_guid_t));
-	else if (efi_guidcmp (hash_type, EfiHashSha256Guid) == 0)
-		return (SHA256_DIGEST_LENGTH + sizeof(efi_guid_t));
-	else if (efi_guidcmp (hash_type, EfiHashSha384Guid) == 0)
-		return (SHA384_DIGEST_LENGTH + sizeof(efi_guid_t));
-	else if (efi_guidcmp (hash_type, EfiHashSha512Guid) == 0)
-		return (SHA512_DIGEST_LENGTH + sizeof(efi_guid_t));
+	uint32_t hash_size;
+
+	hash_size = efi_hash_size (hash_type);
+	if (hash_size)
+		return (hash_size + sizeof(efi_guid_t));
 
 	return 0;
 }
@@ -293,29 +324,16 @@ print_hash_array (efi_guid_t hash_type, void *hash_array, uint32_t array_size)
 		return -1;
 	}
 
-	if (efi_guidcmp (hash_type, EfiHashSha1Guid) == 0) {
-		name = "SHA1";
-		hash_size = SHA_DIGEST_LENGTH;
-	} else if (efi_guidcmp (hash_type, EfiHashSha224Guid) == 0) {
-		name = "SHA224";
-		hash_size = SHA224_DIGEST_LENGTH;
-	} else if (efi_guidcmp (hash_type, EfiHashSha256Guid) == 0) {
-		name = "SHA256";
-		hash_size = SHA256_DIGEST_LENGTH;
-	} else if (efi_guidcmp (hash_type, EfiHashSha384Guid) == 0) {
-		name = "SHA384";
-		hash_size = SHA384_DIGEST_LENGTH;
-	} else if (efi_guidcmp (hash_type, EfiHashSha512Guid) == 0) {
-		name = "SHA512";
-		hash_size = SHA512_DIGEST_LENGTH;
-	} else {
+	name = efi_hash_to_string (hash_type);
+	hash_size = efi_hash_size (hash_type);
+	sig_size = hash_size + sizeof(efi_guid_t);
+
+	if (!name) {
 		fprintf (stderr, "unknown hash type\n");
 		return -1;
 	}
-	sig_size = hash_size + sizeof(efi_guid_t);
 
 	printf ("  [%s]\n", name);
-
 	remain = array_size;
 	hash = (uint8_t *)hash_array;
 
@@ -829,36 +847,78 @@ is_valid_cert (void *cert, uint32_t cert_size)
 }
 
 static int
-is_duplicate (const void *cert, const uint32_t cert_size, const char *db_name,
-	      efi_guid_t guid)
+match_hash_array (efi_guid_t hash_type, const void *hash,
+		  const void *hash_array, const uint32_t array_size)
+{
+	uint32_t hash_size, hash_count;
+	uint32_t sig_size;
+	int i;
+	void *ptr;
+
+	hash_size = efi_hash_size (hash_type);
+	if (!hash_size)
+		return 0;
+
+	sig_size = hash_size + sizeof(efi_guid_t);
+	if ((array_size % sig_size) != 0) {
+		fprintf (stderr, "invalid hash array size\n");
+		return 0;
+	}
+
+	ptr = (void *)hash_array;
+	hash_count = array_size / sig_size;
+	for (i = 0; i < hash_count; i++) {
+		ptr += sizeof(efi_guid_t);
+		if (memcmp (ptr, hash, hash_size) == 0)
+			return 1;
+		ptr += hash_size;
+	}
+
+	return 0;
+}
+
+static int
+is_duplicate (efi_guid_t type, const void *data, const uint32_t data_size,
+	      efi_guid_t vendor, const char *db_name)
 {
 	efi_variable_t var;
-	uint32_t mok_num;
+	uint32_t node_num;
 	MokListNode *list;
 	int i, ret = 0;
 
-	if (!cert || cert_size == 0 || !db_name)
+	if (!data || data_size == 0 || !db_name)
 		return 0;
 
 	memset (&var, 0, sizeof(var));
 	var.VariableName = db_name;
-	var.VendorGuid = guid;
+	var.VendorGuid = vendor;
 
 	if (read_variable (&var) != EFI_SUCCESS)
 		return 0;
 
-	list = build_mok_list (var.Data, var.DataSize, &mok_num);
+	list = build_mok_list (var.Data, var.DataSize, &node_num);
 	if (list == NULL) {
 		goto done;
 	}
 
-	for (i = 0; i < mok_num; i++) {
-		if (list[i].mok_size != cert_size)
+	for (i = 0; i < node_num; i++) {
+		if (efi_guidcmp (list[i].header->SignatureType, type) != 0)
 			continue;
 
-		if (memcmp (list[i].mok, cert, cert_size) == 0) {
-			ret = 1;
-			break;
+		if (efi_guidcmp (type, EfiCertX509Guid) == 0) {
+			if (list[i].mok_size != data_size)
+				continue;
+
+			if (memcmp (list[i].mok, data, data_size) == 0) {
+				ret = 1;
+				break;
+			}
+		} else {
+			if (match_hash_array (type, data, list[i].mok,
+					      list[i].mok_size)) {
+				ret = 1;
+				break;
+			}
 		}
 	}
 
@@ -870,19 +930,19 @@ done:
 }
 
 static int
-is_valid_request (void *mok, uint32_t mok_size, uint8_t import)
+is_valid_request (efi_guid_t type, void *mok, uint32_t mok_size, uint8_t import)
 {
 	if (import) {
-		if (is_duplicate (mok, mok_size, "PK", EFI_GLOBAL_VARIABLE) ||
-		    is_duplicate (mok, mok_size, "KEK", EFI_GLOBAL_VARIABLE) ||
-		    is_duplicate (mok, mok_size, "db", EFI_IMAGE_SECURITY_DATABASE_GUID) ||
-		    is_duplicate (mok, mok_size, "MokListRT", SHIM_LOCK_GUID) ||
-		    is_duplicate (mok, mok_size, "MokNew", SHIM_LOCK_GUID)) {
+		if (is_duplicate (type, mok, mok_size, EFI_GLOBAL_VARIABLE, "PK") ||
+		    is_duplicate (type, mok, mok_size, EFI_GLOBAL_VARIABLE, "KEK") ||
+		    is_duplicate (type, mok, mok_size, EFI_IMAGE_SECURITY_DATABASE_GUID, "db") ||
+		    is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokListRT") ||
+		    is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokNew")) {
 			return 0;
 		}
 	} else {
-		if (!is_duplicate (mok, mok_size, "MokListRT", SHIM_LOCK_GUID) ||
-		    is_duplicate (mok, mok_size, "MokDel", SHIM_LOCK_GUID)) {
+		if (!is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokListRT") ||
+		    is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokDel")) {
 			return 0;
 		}
 	}
@@ -1008,7 +1068,7 @@ issue_mok_request (char **files, uint32_t total, uint8_t import,
 			         files[i]);
 		}
 
-		if (is_valid_request (ptr, sizes[i], import)) {
+		if (is_valid_request (EfiCertX509Guid, ptr, sizes[i], import)) {
 			ptr += sizes[i];
 			real_size += sizes[i] + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
 		} else if (in_pending_request (ptr, sizes[i], import)) {
@@ -1359,11 +1419,7 @@ test_key (const char *key_file)
 		goto error;
 	}
 
-	if (!is_duplicate (key, read_size, "PK", EFI_GLOBAL_VARIABLE) &&
-	    !is_duplicate (key, read_size, "KEK", EFI_GLOBAL_VARIABLE) &&
-	    !is_duplicate (key, read_size, "db", EFI_GLOBAL_VARIABLE) &&
-	    !is_duplicate (key, read_size, "MokListRT", SHIM_LOCK_GUID) &&
-	    !is_duplicate (key, read_size, "MokNew", SHIM_LOCK_GUID)) {
+	if (!is_valid_request (EfiCertX509Guid, key, read_size, 1)) {
 		printf ("%s is not enrolled\n", key_file);
 		ret = 0;
 	} else {
-- 
1.8.4


From 9ec6f6836a386d527cf62d6583c3ea5e394f62a5 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 22 Oct 2013 18:01:11 +0800
Subject: [PATCH 06/20] Support MOK blacklist

---
 src/mokutil.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 195 insertions(+), 28 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index fa5d668..f10e6e8 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -79,6 +79,7 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b,
 #define SIMPLE_HASH        (1 << 17)
 #define IGNORE_DB          (1 << 18)
 #define USE_DB             (1 << 19)
+#define MOKX               (1 << 20)
 
 #define DEFAULT_CRYPT_METHOD SHA512_BASED
 #define DEFAULT_SALT_SIZE    SHA512_SALT_MAX
@@ -86,6 +87,13 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b,
 
 static int use_simple_hash;
 
+typedef enum {
+	DELETE_MOK = 0,
+	ENROLL_MOK,
+	DELETE_BLACKLIST,
+	ENROLL_BLACKLIST
+} MokRequest;
+
 typedef struct {
 	EFI_SIGNATURE_LIST *header;
 	uint32_t            mok_size;
@@ -135,6 +143,10 @@ print_help ()
 	printf ("  --simple-hash\t\t\t\tUse the old password hash method\n");
 	printf ("               \t\t\t\t(For --import, --delete, --password,\n");
 	printf ("               \t\t\t\t --clear-password and --reset)\n");
+	printf ("  --mokx\t\t\t\tManipulate the MOK blacklist\n");
+	printf ("        \t\t\t\t(For --list-enrolled, --list-new,\n");
+	printf ("        \t\t\t\t --list-delete, --import, --delete,\n");
+	printf ("        \t\t\t\t --revoke-import, and --revoke-delete)\n");
 }
 
 static int
@@ -724,7 +736,7 @@ get_password_from_shadow (pw_crypt_t *pw_crypt)
 }
 
 static int
-update_request (void *new_list, int list_len, uint8_t import,
+update_request (void *new_list, int list_len, MokRequest req,
 		const char *hash_file, const int root_pw)
 {
 	efi_variable_t var;
@@ -739,12 +751,25 @@ update_request (void *new_list, int list_len, uint8_t import,
 	bzero (&pw_crypt, sizeof(pw_crypt_t));
 	pw_crypt.method = DEFAULT_CRYPT_METHOD;
 
-	if (import) {
+	switch (req) {
+	case ENROLL_MOK:
 		req_name = "MokNew";
 		auth_name = "MokAuth";
-	} else {
+		break;
+	case DELETE_MOK:
 		req_name = "MokDel";
 		auth_name = "MokDelAuth";
+		break;
+	case ENROLL_BLACKLIST:
+		req_name = "MokXNew";
+		auth_name = "MokXAuth";
+		break;
+	case DELETE_BLACKLIST:
+		req_name = "MokXDel";
+		auth_name = "MokXDelAuth";
+		break;
+	default:
+		return -1;
 	}
 
 	if (hash_file) {
@@ -776,7 +801,7 @@ update_request (void *new_list, int list_len, uint8_t import,
 	}
 
 	if (new_list) {
-		/* Write MokNew*/
+		/* Write MokNew, MokDel, MokXNew, or MokXDel*/
 		var.Data = new_list;
 		var.DataSize = list_len;
 		var.VariableName = req_name;
@@ -787,15 +812,27 @@ update_request (void *new_list, int list_len, uint8_t import,
 			| EFI_VARIABLE_RUNTIME_ACCESS;
 
 		if (edit_variable (&var) != EFI_SUCCESS) {
-			fprintf (stderr, "Failed to %s keys\n",
-				 import ? "enroll new" : "delete");
+			switch (req) {
+			case ENROLL_MOK:
+				fprintf (stderr, "Failed to enroll new keys\n");
+				break;
+			case ENROLL_BLACKLIST:
+				fprintf (stderr, "Failed to enroll blacklist\n");
+				break;
+			case DELETE_MOK:
+				fprintf (stderr, "Failed to delete keys\n");
+				break;
+			case DELETE_BLACKLIST:
+				fprintf (stderr, "Failed to delete blacklist\n");
+				break;
+			}
 			goto error;
 		}
 	} else {
 		test_and_delete_var (req_name);
 	}
 
-	/* Write MokAuth or MokDelAuth */
+	/* Write MokAuth, MokDelAuth, MokXAuth, or MokXDelAuth */
 	if (!use_simple_hash) {
 		var.Data = (void *)&pw_crypt;
 		var.DataSize = PASSWORD_CRYPT_SIZE;
@@ -930,9 +967,10 @@ done:
 }
 
 static int
-is_valid_request (efi_guid_t type, void *mok, uint32_t mok_size, uint8_t import)
+is_valid_request (efi_guid_t type, void *mok, uint32_t mok_size, MokRequest req)
 {
-	if (import) {
+	switch (req) {
+	case ENROLL_MOK:
 		if (is_duplicate (type, mok, mok_size, EFI_GLOBAL_VARIABLE, "PK") ||
 		    is_duplicate (type, mok, mok_size, EFI_GLOBAL_VARIABLE, "KEK") ||
 		    is_duplicate (type, mok, mok_size, EFI_IMAGE_SECURITY_DATABASE_GUID, "db") ||
@@ -940,29 +978,63 @@ is_valid_request (efi_guid_t type, void *mok, uint32_t mok_size, uint8_t import)
 		    is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokNew")) {
 			return 0;
 		}
-	} else {
+		break;
+	case DELETE_MOK:
 		if (!is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokListRT") ||
 		    is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokDel")) {
 			return 0;
 		}
+		break;
+	case ENROLL_BLACKLIST:
+		if (is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokListXRT") ||
+		    is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokXNew")) {
+			return 0;
+		}
+		break;
+	case DELETE_BLACKLIST:
+		if (!is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokListXRT") ||
+		    is_duplicate (type, mok, mok_size, SHIM_LOCK_GUID, "MokXDel")) {
+			return 0;
+		}
+		break;
 	}
 
 	return 1;
 }
 
 static int
-in_pending_request (void *mok, uint32_t mok_size, uint8_t import)
+in_pending_request (void *mok, uint32_t mok_size, MokRequest req)
 {
 	efi_variable_t authvar;
-	const char *var_name = import ? "MokDel" : "MokNew";
+	const char *var_name;
 
 	if (!mok || mok_size == 0)
 		return 0;
 
 	memset (&authvar, 0, sizeof(authvar));
-	authvar.VariableName = import ? "MokDelAuth" : "MokAuth";
 	authvar.VendorGuid = SHIM_LOCK_GUID;
 
+	switch (req) {
+	case ENROLL_MOK:
+		var_name = "MokDel";
+		authvar.VariableName = "MokDelAuth";
+		break;
+	case DELETE_MOK:
+		var_name = "MokNew";
+		authvar.VariableName = "MokAuth";
+		break;
+	case ENROLL_BLACKLIST:
+		var_name = "MokXDel";
+		authvar.VariableName = "MokXDelAuth";
+		break;
+	case DELETE_BLACKLIST:
+		var_name = "MokXNew";
+		authvar.VariableName = "MokXAuth";
+		break;
+	default:
+		return 0;
+	}
+
 	if (read_variable (&authvar) != EFI_SUCCESS) {
 		return 0;
 	}
@@ -979,7 +1051,7 @@ in_pending_request (void *mok, uint32_t mok_size, uint8_t import)
 }
 
 static int
-issue_mok_request (char **files, uint32_t total, uint8_t import,
+issue_mok_request (char **files, uint32_t total, MokRequest req,
 		   const char *hash_file, const int root_pw)
 {
 	efi_variable_t old_req;
@@ -999,7 +1071,22 @@ issue_mok_request (char **files, uint32_t total, uint8_t import,
 	if (!files)
 		return -1;
 
-	req_name = import ? "MokNew" : "MokDel";
+	switch (req) {
+	case ENROLL_MOK:
+		req_name = "MokNew";
+		break;
+	case DELETE_MOK:
+		req_name = "MokDel";
+		break;
+	case ENROLL_BLACKLIST:
+		req_name = "MokXNew";
+		break;
+	case DELETE_BLACKLIST:
+		req_name = "MokXDel";
+		break;
+	default:
+		return -1;
+	}
 
 	sizes = malloc (total * sizeof(uint32_t));
 
@@ -1068,11 +1155,29 @@ issue_mok_request (char **files, uint32_t total, uint8_t import,
 			         files[i]);
 		}
 
-		if (is_valid_request (EfiCertX509Guid, ptr, sizes[i], import)) {
+		if (is_valid_request (EfiCertX509Guid, ptr, sizes[i], req)) {
 			ptr += sizes[i];
 			real_size += sizes[i] + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
-		} else if (in_pending_request (ptr, sizes[i], import)) {
-			printf ("Removed %s from %s\n", files[i], import ? "MokDel" : "MokNew");
+		} else if (in_pending_request (ptr, sizes[i], req)) {
+			const char *pending;
+			switch (req) {
+			case ENROLL_MOK:
+				pending = "MokDel";
+				break;
+			case DELETE_MOK:
+				pending = "MokNew";
+				break;
+			case ENROLL_BLACKLIST:
+				pending = "MokXDel";
+				break;
+			case DELETE_BLACKLIST:
+				pending = "MokXNew";
+				break;
+			default:
+				pending = "";
+				break;
+			}
+			printf ("Removed %s from %s\n", files[i], pending);
 
 			ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
 		} else {
@@ -1095,7 +1200,7 @@ issue_mok_request (char **files, uint32_t total, uint8_t import,
 		real_size += old_req.DataSize;
 	}
 
-	if (update_request (new_list, real_size, import, hash_file, root_pw) < 0) {
+	if (update_request (new_list, real_size, req, hash_file, root_pw) < 0) {
 		goto error;
 	}
 
@@ -1115,29 +1220,58 @@ static int
 import_moks (char **files, uint32_t total, const char *hash_file,
 	     const int root_pw)
 {
-	return issue_mok_request (files, total, 1, hash_file, root_pw);
+	return issue_mok_request (files, total, ENROLL_MOK, hash_file, root_pw);
 }
 
 static int
 delete_moks (char **files, uint32_t total, const char *hash_file,
 	     const int root_pw)
 {
-	return issue_mok_request (files, total, 0, hash_file, root_pw);
+	return issue_mok_request (files, total, DELETE_MOK, hash_file, root_pw);
 }
 
 static int
-revoke_request (uint8_t import)
+import_blacklist (char **files, uint32_t total, const char *hash_file,
+		  const int root_pw)
 {
-	if (import == 1) {
+	return issue_mok_request (files, total, ENROLL_BLACKLIST, hash_file, root_pw);
+}
+
+static int
+delete_blacklist (char **files, uint32_t total, const char *hash_file,
+		  const int root_pw)
+{
+	return issue_mok_request (files, total, DELETE_BLACKLIST, hash_file, root_pw);
+}
+
+static int
+revoke_request (MokRequest req)
+{
+	switch (req) {
+	case ENROLL_MOK:
 		if (test_and_delete_var ("MokNew") < 0)
 			return -1;
 		if (test_and_delete_var ("MokAuth") < 0)
 			return -1;
-	} else {
+		break;
+	case DELETE_MOK:
 		if (test_and_delete_var ("MokDel") < 0)
 			return -1;
 		if (test_and_delete_var ("MokDelAuth") < 0)
 			return -1;
+		break;
+	case ENROLL_BLACKLIST:
+		if (test_and_delete_var ("MokXNew") < 0)
+			return -1;
+		if (test_and_delete_var ("MokXAuth") < 0)
+			return -1;
+		break;
+	case DELETE_BLACKLIST:
+		if (test_and_delete_var ("MokXDel") < 0)
+			return -1;
+		if (test_and_delete_var ("MokXDelAuth") < 0)
+			return -1;
+		break;
 	}
 
 	return 0;
@@ -1419,7 +1553,7 @@ test_key (const char *key_file)
 		goto error;
 	}
 
-	if (!is_valid_request (EfiCertX509Guid, key, read_size, 1)) {
+	if (!is_valid_request (EfiCertX509Guid, key, read_size, ENROLL_MOK)) {
 		printf ("%s is not enrolled\n", key_file);
 		ret = 0;
 	} else {
@@ -1440,7 +1574,7 @@ error:
 static int
 reset_moks (const char *hash_file, const int root_pw)
 {
-	if (update_request (NULL, 0, 1, hash_file, root_pw)) {
+	if (update_request (NULL, 0, ENROLL_MOK, hash_file, root_pw)) {
 		fprintf (stderr, "Failed to issue a reset request\n");
 		return -1;
 	}
@@ -1539,6 +1673,7 @@ main (int argc, char *argv[])
 			{"simple-hash",        no_argument,       0, 's'},
 			{"ignore-db",          no_argument,       0, 0  },
 			{"use-db",             no_argument,       0, 0  },
+			{"mokx",               no_argument,       0, 0  },
 			{0, 0, 0, 0}
 		};
 
@@ -1574,6 +1709,8 @@ main (int argc, char *argv[])
 				command |= IGNORE_DB;
 			} else if (strcmp (option, "use-db") == 0) {
 				command |= USE_DB;
+			} else if (strcmp (option, "mokx") == 0) {
+				command |= MOKX;
 			}
 			break;
 		case 'd':
@@ -1683,10 +1820,10 @@ main (int argc, char *argv[])
 				ret = delete_moks (files, total, hash_file, 0);
 			break;
 		case REVOKE_IMPORT:
-			ret = revoke_request (1);
+			ret = revoke_request (ENROLL_MOK);
 			break;
 		case REVOKE_DELETE:
-			ret = revoke_request (0);
+			ret = revoke_request (DELETE_MOK);
 			break;
 		case EXPORT:
 			ret = export_moks ();
@@ -1730,6 +1867,36 @@ main (int argc, char *argv[])
 		case USE_DB:
 			ret = enable_db ();
 			break;
+		case LIST_ENROLLED | MOKX:
+			ret = list_keys_in_var ("MokListXRT");
+			break;
+		case LIST_NEW | MOKX:
+			ret = list_keys_in_var ("MokXNew");
+			break;
+		case LIST_DELETE | MOKX:
+			ret = list_keys_in_var ("MokXDel");
+			break;
+		case IMPORT | MOKX:
+		case IMPORT | SIMPLE_HASH | MOKX:
+			if (use_root_pw)
+				ret = import_blacklist (files, total, NULL, 1);
+			else
+				ret = import_blacklist (files, total, hash_file, 0);
+			break;
+		case DELETE | MOKX:
+		case DELETE | SIMPLE_HASH | MOKX:
+			if (use_root_pw)
+				ret = delete_blacklist (files, total, NULL, 1);
+			else
+				ret = delete_blacklist (files, total, hash_file, 0);
+			break;
+		case REVOKE_IMPORT | MOKX:
+			ret = revoke_request (ENROLL_BLACKLIST);
+			break;
+		case REVOKE_DELETE | MOKX:
+			ret = revoke_request (DELETE_BLACKLIST);
+			break;
+
 		default:
 			print_help ();
 			break;
-- 
1.8.4


From 73c2a558b6fa9fb42526d4d2ac5c7db40d402c8f Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 23 Oct 2013 10:41:58 +0800
Subject: [PATCH 07/20] Fix the memory leakage

---
 src/mokutil.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/mokutil.c b/src/mokutil.c
index f10e6e8..bcc12ca 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1746,10 +1746,18 @@ main (int argc, char *argv[])
 
 			break;
 		case 'f':
+			if (hash_file) {
+				command |= HELP;
+				break;
+			}
 			hash_file = strdup (optarg);
 
 			break;
 		case 'g':
+			if (input_pw) {
+				command |= HELP;
+				break;
+			}
 			if (optarg)
 				input_pw = strdup (optarg);
 
@@ -1765,6 +1773,10 @@ main (int argc, char *argv[])
 			use_root_pw = 1;
 			break;
 		case 't':
+			if (key_file) {
+				command |= HELP;
+				break;
+			}
 			key_file = strdup (optarg);
 			if (key_file == NULL) {
 				fprintf (stderr, "Could not allocate space: %m\n");
-- 
1.8.4


From 62162fc5a5c33c987e4b8106a9e98c3abf8288ae Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 23 Oct 2013 17:29:53 +0800
Subject: [PATCH 08/20] Support import and delete a hash

---
 src/mokutil.c | 424 ++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 322 insertions(+), 102 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index bcc12ca..b8edf74 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -80,6 +80,8 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b,
 #define IGNORE_DB          (1 << 18)
 #define USE_DB             (1 << 19)
 #define MOKX               (1 << 20)
+#define IMPORT_HASH        (1 << 21)
+#define DELETE_HASH        (1 << 22)
 
 #define DEFAULT_CRYPT_METHOD SHA512_BASED
 #define DEFAULT_SALT_SIZE    SHA512_SALT_MAX
@@ -132,21 +134,27 @@ print_help ()
 	printf ("  --generate-hash[=password]\t\tGenerate the password hash\n");
 	printf ("  --ignore-db\t\t\t\tIgnore DB for validation\n");
 	printf ("  --use-db\t\t\t\tUse DB for validation\n");
+	printf ("  --import-hash <hash>\t\t\tImport a hash\n");
+	printf ("  --delete-hash <hash>\t\t\tDelete a specific hash\n");
 	printf ("\n");
 	printf ("Supplimentary Options:\n");
 	printf ("  --hash-file <hash file>\t\tUse the specific password hash\n");
 	printf ("                         \t\t(For --import, --delete, --password,\n");
-	printf ("                         \t\t and --reset)\n");
+	printf ("                         \t\t --reset, --import-hash,\n");
+	printf ("                         \t\t and --delete-hash)\n");
 	printf ("  --root-pw\t\t\t\tUse the root password\n");
 	printf ("           \t\t\t\t(For --import, --delete, --password,\n");
-	printf ("           \t\t\t\t and --reset)\n");
+	printf ("           \t\t\t\t --reset, --import-hash,\n");
+	printf ("           \t\t\t\t and --delete-hash)\n");
 	printf ("  --simple-hash\t\t\t\tUse the old password hash method\n");
 	printf ("               \t\t\t\t(For --import, --delete, --password,\n");
-	printf ("               \t\t\t\t --clear-password and --reset)\n");
+	printf ("               \t\t\t\t --clear-password, --reset,\n");
+	printf ("               \t\t\t\t --import-hash, and --delete-hash)\n");
 	printf ("  --mokx\t\t\t\tManipulate the MOK blacklist\n");
 	printf ("        \t\t\t\t(For --list-enrolled, --list-new,\n");
 	printf ("        \t\t\t\t --list-delete, --import, --delete,\n");
-	printf ("        \t\t\t\t --revoke-import, and --revoke-delete)\n");
+	printf ("        \t\t\t\t --revoke-import, --revoke-delete,\n");
+	printf ("        \t\t\t\t --import-hash, and --delete-hash)\n");
 }
 
 static int
@@ -396,17 +404,50 @@ list_keys (efi_variable_t *var)
 	return 0;
 }
 
+/* match the hash in the hash array and return the index if matched */
 static int
-delete_key_from_list (void *mok, uint32_t mok_size,
-		      const char *var_name, efi_guid_t guid)
+match_hash_array (efi_guid_t hash_type, const void *hash,
+		  const void *hash_array, const uint32_t array_size)
+{
+	uint32_t hash_size, hash_count;
+	uint32_t sig_size;
+	int i;
+	void *ptr;
+
+	hash_size = efi_hash_size (hash_type);
+	if (!hash_size)
+		return -1;
+
+	sig_size = hash_size + sizeof(efi_guid_t);
+	if ((array_size % sig_size) != 0) {
+		fprintf (stderr, "invalid hash array size\n");
+		return -1;
+	}
+
+	ptr = (void *)hash_array;
+	hash_count = array_size / sig_size;
+	for (i = 0; i < hash_count; i++) {
+		ptr += sizeof(efi_guid_t);
+		if (memcmp (ptr, hash, hash_size) == 0)
+			return i;
+		ptr += hash_size;
+	}
+
+	return -1;
+}
+
+static int
+delete_data_from_list (efi_guid_t type, void *data, uint32_t data_size,
+		       const char *var_name, efi_guid_t guid)
 {
 	efi_variable_t var;
 	MokListNode *list;
 	uint32_t mok_num, total, remain;
-	void *ptr, *data = NULL;
+	void *end, *start = NULL;
 	int i, del_ind, ret = 0;
+	uint32_t sig_list_size, sig_size;
 
-	if (!var_name || !mok || mok_size == 0)
+	if (!var_name || !data || data_size == 0)
 		return 0;
 
 	memset (&var, 0, sizeof(var));
@@ -422,30 +463,56 @@ delete_key_from_list (void *mok, uint32_t mok_size,
 	if (list == NULL)
 		goto done;
 
+	remain = total;
 	for (i = 0; i < mok_num; i++) {
-		if (list[i].mok_size != mok_size)
+		remain -= list[i].header->SignatureListSize;
+		if (efi_guidcmp (list[i].header->SignatureType, type) != 0)
 			continue;
 
-		if (memcmp (list[i].mok, mok, mok_size) == 0) {
-			/* Remove this key */
-			del_ind = i;
-			data = (void *)list[i].header;
-			ptr = data + list[i].header->SignatureListSize;
-			total -= list[i].header->SignatureListSize;
+		sig_list_size = list[i].header->SignatureListSize;
+
+		if (efi_guidcmp (type, EfiCertX509Guid) == 0) {
+			if (list[i].mok_size != data_size)
+				continue;
+
+			if (memcmp (list[i].mok, data, data_size) == 0) {
+				/* Remove this key */
+				start = (void *)list[i].header;
+				end = start + sig_list_size;
+				total -= sig_list_size;
+				break;
+			}
+		} else {
+			del_ind = match_hash_array (type, data, list[i].mok,
+						    list[i].mok_size);
+			if (del_ind < 0)
+				continue;
+
+			start = (void *)list[i].header;
+			sig_size = signature_size (type);
+			if (sig_list_size == (sizeof(EFI_SIGNATURE_LIST) + sig_size)) {
+				/* Only one hash in the list */
+				end = start + sig_list_size;
+				total -= sig_list_size;
+			} else {
+				/* More than one hash in the list */
+				start += sizeof(EFI_SIGNATURE_LIST) + sig_size * del_ind;
+				end = start + sig_size;
+				total -= sig_size;
+				remain += sig_list_size - sizeof(EFI_SIGNATURE_LIST) -
+					  (del_ind + 1) * sig_size;
+			}
 			break;
 		}
 	}
 
-	/* the key is not in this list */
-	if (data == NULL)
+	/* the key or hash is not in this list */
+	if (start == NULL)
 		return 0;
 
-	/* Move the rest of the keys */
-	remain = 0;
-	for (i = del_ind + 1; i < mok_num; i++)
-		remain += list[i].header->SignatureListSize;
+	/* remove the key or hash  */
 	if (remain > 0)
-		memmove (data, ptr, remain);
+		memmove (start, end, remain);
 
 	var.DataSize = total;
 	var.Attributes = EFI_VARIABLE_NON_VOLATILE
@@ -459,7 +526,8 @@ delete_key_from_list (void *mok, uint32_t mok_size,
 
 	ret = 1;
 done:
-	free (list);
+	if (list)
+		free (list);
 	free (var.Data);
 
 	return ret;
@@ -884,37 +952,6 @@ is_valid_cert (void *cert, uint32_t cert_size)
 }
 
 static int
-match_hash_array (efi_guid_t hash_type, const void *hash,
-		  const void *hash_array, const uint32_t array_size)
-{
-	uint32_t hash_size, hash_count;
-	uint32_t sig_size;
-	int i;
-	void *ptr;
-
-	hash_size = efi_hash_size (hash_type);
-	if (!hash_size)
-		return 0;
-
-	sig_size = hash_size + sizeof(efi_guid_t);
-	if ((array_size % sig_size) != 0) {
-		fprintf (stderr, "invalid hash array size\n");
-		return 0;
-	}
-
-	ptr = (void *)hash_array;
-	hash_count = array_size / sig_size;
-	for (i = 0; i < hash_count; i++) {
-		ptr += sizeof(efi_guid_t);
-		if (memcmp (ptr, hash, hash_size) == 0)
-			return 1;
-		ptr += hash_size;
-	}
-
-	return 0;
-}
-
-static int
 is_duplicate (efi_guid_t type, const void *data, const uint32_t data_size,
 	      efi_guid_t vendor, const char *db_name)
 {
@@ -952,7 +989,7 @@ is_duplicate (efi_guid_t type, const void *data, const uint32_t data_size,
 			}
 		} else {
 			if (match_hash_array (type, data, list[i].mok,
-					      list[i].mok_size)) {
+					      list[i].mok_size) >= 0) {
 				ret = 1;
 				break;
 			}
@@ -960,7 +997,8 @@ is_duplicate (efi_guid_t type, const void *data, const uint32_t data_size,
 	}
 
 done:
-	free (list);
+	if (list)
+		free (list);
 	free (var.Data);
 
 	return ret;
@@ -1003,12 +1041,13 @@ is_valid_request (efi_guid_t type, void *mok, uint32_t mok_size, MokRequest req)
 }
 
 static int
-in_pending_request (void *mok, uint32_t mok_size, MokRequest req)
+in_pending_request (efi_guid_t type, void *data, uint32_t data_size,
+		    MokRequest req)
 {
 	efi_variable_t authvar;
 	const char *var_name;
 
-	if (!mok || mok_size == 0)
+	if (!data || data_size == 0)
 		return 0;
 
 	memset (&authvar, 0, sizeof(authvar));
@@ -1044,8 +1083,9 @@ in_pending_request (void *mok, uint32_t mok_size, MokRequest req)
 	if (authvar.DataSize == SHA256_DIGEST_LENGTH)
 		return 0;
 
-	if (delete_key_from_list (mok, mok_size, var_name, SHIM_LOCK_GUID))
-		return 1;
+	if (delete_data_from_list (type, data, data_size, var_name,
+				   SHIM_LOCK_GUID))
+			return 1;
 
 	return 0;
 }
@@ -1158,7 +1198,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
 		if (is_valid_request (EfiCertX509Guid, ptr, sizes[i], req)) {
 			ptr += sizes[i];
 			real_size += sizes[i] + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
-		} else if (in_pending_request (ptr, sizes[i], req)) {
+		} else if (in_pending_request (EfiCertX509Guid, ptr, sizes[i], req)) {
 			const char *pending;
 			switch (req) {
 			case ENROLL_MOK:
@@ -1217,31 +1257,186 @@ error:
 }
 
 static int
-import_moks (char **files, uint32_t total, const char *hash_file,
-	     const int root_pw)
+identify_hash_type (const char *hash_str, efi_guid_t *type)
 {
-	return issue_mok_request (files, total, ENROLL_MOK, hash_file, root_pw);
-}
+	int len = strlen (hash_str);
+	int hash_size;
+	int i;
 
-static int
-delete_moks (char **files, uint32_t total, const char *hash_file,
-	     const int root_pw)
-{
-	return issue_mok_request (files, total, DELETE_MOK, hash_file, root_pw);
+	for (i = 0; i < len; i++) {
+		if ((hash_str[i] > '9' || hash_str[i] < '0') &&
+		    (hash_str[i] > 'f' || hash_str[i] < 'a') &&
+		    (hash_str[i] > 'F' || hash_str[i] < 'A'))
+		return -1;
+	}
+
+	switch (len) {
+	case SHA_DIGEST_LENGTH*2:
+		*type = EfiHashSha1Guid;
+		hash_size = SHA_DIGEST_LENGTH;
+		break;
+	case SHA224_DIGEST_LENGTH*2:
+		*type = EfiHashSha224Guid;
+		hash_size = SHA224_DIGEST_LENGTH;
+		break;
+	case SHA256_DIGEST_LENGTH*2:
+		*type = EfiHashSha256Guid;
+		hash_size = SHA256_DIGEST_LENGTH;
+		break;
+	case SHA384_DIGEST_LENGTH*2:
+		*type = EfiHashSha384Guid;
+		hash_size = SHA384_DIGEST_LENGTH;
+		break;
+	case SHA512_DIGEST_LENGTH*2:
+		*type = EfiHashSha512Guid;
+		hash_size = SHA512_DIGEST_LENGTH;
+		break;
+	default:
+		return -1;
+	}
+
+	return hash_size;
 }
 
 static int
-import_blacklist (char **files, uint32_t total, const char *hash_file,
-		  const int root_pw)
+hex_str_to_binary (const char *hex_str, uint8_t *array, int len)
 {
-	return issue_mok_request (files, total, ENROLL_BLACKLIST, hash_file, root_pw);
+	char *pos;
+	int i;
+
+	if (!hex_str || !array)
+		return -1;
+
+	pos = (char *)hex_str;
+	for (i = 0; i < len; i++) {
+		sscanf (pos, "%2hhx", &array[i]);
+		pos += 2;
+	}
+
+	return 0;
 }
 
 static int
-delete_blacklist (char **files, uint32_t total, const char *hash_file,
-		  const int root_pw)
+issue_hash_request (const char *hash_str, MokRequest req,
+		    const char *hash_file, const int root_pw)
 {
-	return issue_mok_request (files, total, DELETE_BLACKLIST, hash_file, root_pw);
+	efi_variable_t old_req;
+	const char *req_name;
+	void *new_list = NULL;
+	void *ptr;
+	unsigned long list_size = 0;
+	uint32_t sig_list_size;
+	int ret = -1;
+	EFI_SIGNATURE_LIST *CertList;
+	EFI_SIGNATURE_DATA *CertData;
+	efi_guid_t hash_type;
+	uint8_t db_hash[SHA512_DIGEST_LENGTH];
+	int hash_size;
+	uint8_t valid = 0;
+
+	if (!hash_str)
+		return -1;
+
+	hash_size = identify_hash_type (hash_str, &hash_type);
+	if (hash_size < 0)
+		return -1;
+
+	if (hex_str_to_binary (hash_str, db_hash, hash_size) < 0)
+		return -1;
+
+	switch (req) {
+	case ENROLL_MOK:
+		req_name = "MokNew";
+		break;
+	case DELETE_MOK:
+		req_name = "MokDel";
+		break;
+	case ENROLL_BLACKLIST:
+		req_name = "MokXNew";
+		break;
+	case DELETE_BLACKLIST:
+		req_name = "MokXDel";
+		break;
+	default:
+		return -1;
+	}
+
+	sig_list_size = sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size;
+	list_size += sig_list_size;
+
+	memset (&old_req, 0, sizeof(old_req));
+
+	old_req.VariableName = req_name;
+	old_req.VendorGuid = SHIM_LOCK_GUID;
+	if (read_variable (&old_req) == EFI_SUCCESS)
+		list_size += old_req.DataSize;
+
+	new_list = malloc (list_size);
+	if (!new_list) {
+		fprintf (stderr, "Failed to allocate space for %s\n", req_name);
+		goto error;
+	}
+	ptr = new_list;
+
+	CertList = ptr;
+	CertList->SignatureType = hash_type;
+	CertList->SignatureListSize = sig_list_size;
+	CertList->SignatureHeaderSize = 0;
+	CertList->SignatureSize = hash_size + sizeof(efi_guid_t);
+
+	CertData = (EFI_SIGNATURE_DATA *)(((uint8_t *)ptr) +
+					  sizeof(EFI_SIGNATURE_LIST));
+	CertData->SignatureOwner = SHIM_LOCK_GUID;
+	memcpy (CertData->SignatureData, db_hash, hash_size);
+
+	if (is_valid_request (hash_type, db_hash, hash_size, req)) {
+		valid = 1;
+	} else if (in_pending_request (hash_type, db_hash, hash_size, req)) {
+		const char *pending;
+		switch (req) {
+		case ENROLL_MOK:
+			pending = "MokDel";
+			break;
+		case DELETE_MOK:
+			pending = "MokNew";
+			break;
+		case ENROLL_BLACKLIST:
+			pending = "MokXDel";
+			break;
+		case DELETE_BLACKLIST:
+			pending = "MokXNew";
+			break;
+		default:
+			pending = "";
+			break;
+		}
+		printf ("Removed hash from %s\n", pending);
+	} else {
+		printf ("Skip hash\n");
+	}
+
+	if (!valid) {
+		ret = 0;
+		goto error;
+	}
+
+	/* append the keys to the previous request */
+	if (old_req.Data) {
+		memcpy (new_list + sig_list_size, old_req.Data, old_req.DataSize);
+	}
+
+	if (update_request (new_list, list_size, req, hash_file, root_pw) < 0) {
+		goto error;
+	}
+
+	ret = 0;
+error:
+	if (old_req.Data)
+		free (old_req.Data);
+	if (new_list)
+		free (new_list);
+
+	return ret;
 }
 
 static int
@@ -1641,6 +1836,7 @@ main (int argc, char *argv[])
 	char *key_file = NULL;
 	char *hash_file = NULL;
 	char *input_pw = NULL;
+	char *hash_str = NULL;
 	const char *option;
 	int c, i, f_ind, total = 0;
 	unsigned int command = 0;
@@ -1674,6 +1870,8 @@ main (int argc, char *argv[])
 			{"ignore-db",          no_argument,       0, 0  },
 			{"use-db",             no_argument,       0, 0  },
 			{"mokx",               no_argument,       0, 0  },
+			{"import-hash",        required_argument, 0, 0  },
+			{"delete-hash",        required_argument, 0, 0  },
 			{0, 0, 0, 0}
 		};
 
@@ -1711,6 +1909,20 @@ main (int argc, char *argv[])
 				command |= USE_DB;
 			} else if (strcmp (option, "mokx") == 0) {
 				command |= MOKX;
+			} else if (strcmp (option, "import-hash") == 0) {
+				command |= IMPORT_HASH;
+				if (hash_str) {
+					command |= HELP;
+					break;
+				}
+				hash_str = strdup (optarg);
+			} else if (strcmp (option, "delete-hash") == 0) {
+				command |= DELETE_HASH;
+				if (hash_str) {
+					command |= HELP;
+					break;
+				}
+				hash_str = strdup (optarg);
 			}
 			break;
 		case 'd':
@@ -1802,7 +2014,7 @@ main (int argc, char *argv[])
 	}
 
 	if (use_root_pw == 1 && use_simple_hash == 1)
-		use_simple_hash = 0;;
+		use_simple_hash = 0;
 
 	if (hash_file && use_root_pw)
 		command |= HELP;
@@ -1819,17 +2031,23 @@ main (int argc, char *argv[])
 			break;
 		case IMPORT:
 		case IMPORT | SIMPLE_HASH:
-			if (use_root_pw)
-				ret = import_moks (files, total, NULL, 1);
-			else
-				ret = import_moks (files, total, hash_file, 0);
+			ret = issue_mok_request (files, total, ENROLL_MOK,
+						 hash_file, use_root_pw);
 			break;
 		case DELETE:
 		case DELETE | SIMPLE_HASH:
-			if (use_root_pw)
-				ret = delete_moks (files, total, NULL, 1);
-			else
-				ret = delete_moks (files, total, hash_file, 0);
+			ret = issue_mok_request (files, total, DELETE_MOK,
+						 hash_file, use_root_pw);
+			break;
+		case IMPORT_HASH:
+		case IMPORT_HASH | SIMPLE_HASH:
+			ret = issue_hash_request (hash_str, ENROLL_MOK,
+						  hash_file, use_root_pw);
+			break;
+		case DELETE_HASH:
+		case DELETE_HASH | SIMPLE_HASH:
+			ret = issue_hash_request (hash_str, DELETE_MOK,
+						  hash_file, use_root_pw);
 			break;
 		case REVOKE_IMPORT:
 			ret = revoke_request (ENROLL_MOK);
@@ -1842,10 +2060,7 @@ main (int argc, char *argv[])
 			break;
 		case PASSWORD:
 		case PASSWORD | SIMPLE_HASH:
-			if (use_root_pw)
-				ret = set_password (NULL, 1, 0);
-			else
-				ret = set_password (hash_file, 0, 0);
+			ret = set_password (hash_file, use_root_pw, 0);
 			break;
 		case CLEAR_PASSWORD:
 		case CLEAR_PASSWORD | SIMPLE_HASH:
@@ -1865,10 +2080,7 @@ main (int argc, char *argv[])
 			break;
 		case RESET:
 		case RESET | SIMPLE_HASH:
-			if (use_root_pw)
-				ret = reset_moks (NULL, 1);
-			else
-				ret = reset_moks (hash_file, 0);
+			ret = reset_moks (hash_file, use_root_pw);
 			break;
 		case GENERATE_PW_HASH:
 			ret = generate_pw_hash (input_pw);
@@ -1890,17 +2102,23 @@ main (int argc, char *argv[])
 			break;
 		case IMPORT | MOKX:
 		case IMPORT | SIMPLE_HASH | MOKX:
-			if (use_root_pw)
-				ret = import_blacklist (files, total, NULL, 1);
-			else
-				ret = import_blacklist (files, total, hash_file, 0);
+			ret = issue_mok_request (files, total, ENROLL_BLACKLIST,
+						 hash_file, use_root_pw);
 			break;
 		case DELETE | MOKX:
 		case DELETE | SIMPLE_HASH | MOKX:
-			if (use_root_pw)
-				ret = delete_blacklist (files, total, NULL, 1);
-			else
-				ret = delete_blacklist (files, total, hash_file, 0);
+			ret = issue_mok_request (files, total, DELETE_BLACKLIST,
+						 hash_file, use_root_pw);
+			break;
+		case IMPORT_HASH | MOKX:
+		case IMPORT_HASH | SIMPLE_HASH | MOKX:
+			ret = issue_hash_request (hash_str, ENROLL_BLACKLIST,
+						  hash_file, use_root_pw);
+			break;
+		case DELETE_HASH | MOKX:
+		case DELETE_HASH | SIMPLE_HASH | MOKX:
+			ret = issue_hash_request (hash_str, DELETE_BLACKLIST,
+						  hash_file, use_root_pw);
 			break;
 		case REVOKE_IMPORT | MOKX:
 			ret = revoke_request (ENROLL_BLACKLIST);
@@ -1908,7 +2126,6 @@ main (int argc, char *argv[])
 		case REVOKE_DELETE | MOKX:
 			ret = revoke_request (DELETE_BLACKLIST);
 			break;
-
 		default:
 			print_help ();
 			break;
@@ -1929,5 +2146,8 @@ main (int argc, char *argv[])
 	if (input_pw)
 		free (input_pw);
 
+	if (hash_str)
+		free (hash_str);
+
 	return ret;
 }
-- 
1.8.4


From e852519aad00c669716c76db8908b89c6b5583e1 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 23 Oct 2013 17:42:05 +0800
Subject: [PATCH 09/20] Reorganize issue_*_request

---
 src/mokutil.c | 75 +++++++++++++++++++----------------------------------------
 1 file changed, 24 insertions(+), 51 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index b8edf74..862cfbf 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1096,6 +1096,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
 {
 	efi_variable_t old_req;
 	const char *req_name;
+	const char *reverse_req;
 	void *new_list = NULL;
 	void *ptr;
 	struct stat buf;
@@ -1114,15 +1115,19 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
 	switch (req) {
 	case ENROLL_MOK:
 		req_name = "MokNew";
+		reverse_req = "MokDel";
 		break;
 	case DELETE_MOK:
 		req_name = "MokDel";
+		reverse_req = "MokNew";
 		break;
 	case ENROLL_BLACKLIST:
 		req_name = "MokXNew";
+		reverse_req = "MokXDel";
 		break;
 	case DELETE_BLACKLIST:
 		req_name = "MokXDel";
+		reverse_req = "MokXNew";
 		break;
 	default:
 		return -1;
@@ -1199,26 +1204,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
 			ptr += sizes[i];
 			real_size += sizes[i] + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
 		} else if (in_pending_request (EfiCertX509Guid, ptr, sizes[i], req)) {
-			const char *pending;
-			switch (req) {
-			case ENROLL_MOK:
-				pending = "MokDel";
-				break;
-			case DELETE_MOK:
-				pending = "MokNew";
-				break;
-			case ENROLL_BLACKLIST:
-				pending = "MokXDel";
-				break;
-			case DELETE_BLACKLIST:
-				pending = "MokXNew";
-				break;
-			default:
-				pending = "";
-				break;
-			}
-			printf ("Removed %s from %s\n", files[i], pending);
-
+			printf ("Removed %s from %s\n", files[i], reverse_req);
 			ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
 		} else {
 			printf ("Skip %s\n", files[i]);
@@ -1322,6 +1308,7 @@ issue_hash_request (const char *hash_str, MokRequest req,
 {
 	efi_variable_t old_req;
 	const char *req_name;
+	const char *reverse_req;
 	void *new_list = NULL;
 	void *ptr;
 	unsigned long list_size = 0;
@@ -1347,20 +1334,37 @@ issue_hash_request (const char *hash_str, MokRequest req,
 	switch (req) {
 	case ENROLL_MOK:
 		req_name = "MokNew";
+		reverse_req = "MokDel";
 		break;
 	case DELETE_MOK:
 		req_name = "MokDel";
+		reverse_req = "MokNew";
 		break;
 	case ENROLL_BLACKLIST:
 		req_name = "MokXNew";
+		reverse_req = "MokXDel";
 		break;
 	case DELETE_BLACKLIST:
 		req_name = "MokXDel";
+		reverse_req = "MokXNew";
 		break;
 	default:
 		return -1;
 	}
 
+	if (is_valid_request (hash_type, db_hash, hash_size, req)) {
+		valid = 1;
+	} else if (in_pending_request (hash_type, db_hash, hash_size, req)) {
+		printf ("Removed hash from %s\n", reverse_req);
+	} else {
+		printf ("Skip hash\n");
+	}
+
+	if (!valid) {
+		ret = 0;
+		goto error;
+	}
+
 	sig_list_size = sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size;
 	list_size += sig_list_size;
 
@@ -1389,37 +1393,6 @@ issue_hash_request (const char *hash_str, MokRequest req,
 	CertData->SignatureOwner = SHIM_LOCK_GUID;
 	memcpy (CertData->SignatureData, db_hash, hash_size);
 
-	if (is_valid_request (hash_type, db_hash, hash_size, req)) {
-		valid = 1;
-	} else if (in_pending_request (hash_type, db_hash, hash_size, req)) {
-		const char *pending;
-		switch (req) {
-		case ENROLL_MOK:
-			pending = "MokDel";
-			break;
-		case DELETE_MOK:
-			pending = "MokNew";
-			break;
-		case ENROLL_BLACKLIST:
-			pending = "MokXDel";
-			break;
-		case DELETE_BLACKLIST:
-			pending = "MokXNew";
-			break;
-		default:
-			pending = "";
-			break;
-		}
-		printf ("Removed hash from %s\n", pending);
-	} else {
-		printf ("Skip hash\n");
-	}
-
-	if (!valid) {
-		ret = 0;
-		goto error;
-	}
-
 	/* append the keys to the previous request */
 	if (old_req.Data) {
 		memcpy (new_list + sig_list_size, old_req.Data, old_req.DataSize);
-- 
1.8.4


From 8603b648095d847fbed56b956b0b5aeaa62f091a Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 23 Oct 2013 18:29:09 +0800
Subject: [PATCH 10/20] Merge the hash into an existed signature list

---
 src/mokutil.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 70 insertions(+), 17 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index 862cfbf..f87ae7a 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1312,14 +1312,17 @@ issue_hash_request (const char *hash_str, MokRequest req,
 	void *new_list = NULL;
 	void *ptr;
 	unsigned long list_size = 0;
-	uint32_t sig_list_size;
+	uint32_t sig_size, sig_list_size;
 	int ret = -1;
 	EFI_SIGNATURE_LIST *CertList;
 	EFI_SIGNATURE_DATA *CertData;
 	efi_guid_t hash_type;
 	uint8_t db_hash[SHA512_DIGEST_LENGTH];
 	int hash_size;
+	int merge_ind = -1;
 	uint8_t valid = 0;
+	MokListNode *mok_list = NULL;
+	uint32_t mok_num;
 
 	if (!hash_str)
 		return -1;
@@ -1365,16 +1368,31 @@ issue_hash_request (const char *hash_str, MokRequest req,
 		goto error;
 	}
 
-	sig_list_size = sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size;
-	list_size += sig_list_size;
-
 	memset (&old_req, 0, sizeof(old_req));
 
 	old_req.VariableName = req_name;
 	old_req.VendorGuid = SHIM_LOCK_GUID;
-	if (read_variable (&old_req) == EFI_SUCCESS)
+	if (read_variable (&old_req) == EFI_SUCCESS) {
+		int i;
 		list_size += old_req.DataSize;
 
+		mok_list = build_mok_list (old_req.Data, old_req.DataSize,
+					   &mok_num);
+		if (mok_list == NULL)
+			goto error;
+
+		/* Check if there is a signature list with the same type */
+		for (i = 0; i < mok_num; i++) {
+			if (efi_guidcmp (mok_list[i].header->SignatureType,
+					 hash_type) == 0) {
+				merge_ind = i;
+				break;
+			}
+		}
+	}
+
+	list_size += sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size;
+
 	new_list = malloc (list_size);
 	if (!new_list) {
 		fprintf (stderr, "Failed to allocate space for %s\n", req_name);
@@ -1382,20 +1400,53 @@ issue_hash_request (const char *hash_str, MokRequest req,
 	}
 	ptr = new_list;
 
-	CertList = ptr;
-	CertList->SignatureType = hash_type;
-	CertList->SignatureListSize = sig_list_size;
-	CertList->SignatureHeaderSize = 0;
-	CertList->SignatureSize = hash_size + sizeof(efi_guid_t);
+	if (merge_ind < 0) {
+		/* Create a new signature list for the hash */
+		sig_list_size = sizeof(EFI_SIGNATURE_LIST) +
+				sizeof(efi_guid_t) + hash_size;
+		CertList = ptr;
+		CertList->SignatureType = hash_type;
+		CertList->SignatureListSize = sig_list_size;
+		CertList->SignatureHeaderSize = 0;
+		CertList->SignatureSize = hash_size + sizeof(efi_guid_t);
 
-	CertData = (EFI_SIGNATURE_DATA *)(((uint8_t *)ptr) +
-					  sizeof(EFI_SIGNATURE_LIST));
-	CertData->SignatureOwner = SHIM_LOCK_GUID;
-	memcpy (CertData->SignatureData, db_hash, hash_size);
+		CertData = (EFI_SIGNATURE_DATA *)(((uint8_t *)ptr) +
+						  sizeof(EFI_SIGNATURE_LIST));
+		CertData->SignatureOwner = SHIM_LOCK_GUID;
+		memcpy (CertData->SignatureData, db_hash, hash_size);
 
-	/* append the keys to the previous request */
-	if (old_req.Data) {
-		memcpy (new_list + sig_list_size, old_req.Data, old_req.DataSize);
+		/* prepend the hash to the previous request */
+		ptr += sig_list_size;
+		if (old_req.Data) {
+			memcpy (ptr, old_req.Data, old_req.DataSize);
+		}
+	} else {
+		/* Merge the hash into an existed signature list */
+		int i;
+
+		for (i = 0; i < merge_ind; i++) {
+			sig_list_size = mok_list[i].header->SignatureListSize;
+			memcpy (ptr, (void *)mok_list[i].header, sig_list_size);
+			ptr += sig_list_size;
+		}
+
+		/* Append the hash to the list */
+		i = merge_ind;
+		sig_list_size = mok_list[i].header->SignatureListSize;
+		sig_size = hash_size + sizeof(efi_guid_t);
+		mok_list[i].header->SignatureListSize += sig_size;
+		memcpy (ptr, (void *)mok_list[i].header, sig_list_size);
+		ptr += sig_list_size;
+		memcpy (ptr, (void *)&hash_type, sizeof(efi_guid_t));
+		ptr += sizeof(efi_guid_t);
+		memcpy (ptr, db_hash, hash_size);
+		ptr += hash_size;
+
+		for (i = merge_ind + 1; i < mok_num; i++) {
+			sig_list_size = mok_list[i].header->SignatureListSize;
+			memcpy (ptr, (void *)mok_list[i].header, sig_list_size);
+			ptr += sig_list_size;
+		}
 	}
 
 	if (update_request (new_list, list_size, req, hash_file, root_pw) < 0) {
@@ -1406,6 +1457,8 @@ issue_hash_request (const char *hash_str, MokRequest req,
 error:
 	if (old_req.Data)
 		free (old_req.Data);
+	if (mok_list)
+		free (mok_list);
 	if (new_list)
 		free (new_list);
 
-- 
1.8.4


From d933eba21ebad708d85ff23a715a14a7d67f51a9 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 24 Oct 2013 17:54:18 +0800
Subject: [PATCH 11/20] Initialize the request variable to avoid the potential
 crash

---
 src/mokutil.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index f87ae7a..880c38f 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1334,6 +1334,8 @@ issue_hash_request (const char *hash_str, MokRequest req,
 	if (hex_str_to_binary (hash_str, db_hash, hash_size) < 0)
 		return -1;
 
+	memset (&old_req, 0, sizeof(old_req));
+
 	switch (req) {
 	case ENROLL_MOK:
 		req_name = "MokNew";
@@ -1368,8 +1370,6 @@ issue_hash_request (const char *hash_str, MokRequest req,
 		goto error;
 	}
 
-	memset (&old_req, 0, sizeof(old_req));
-
 	old_req.VariableName = req_name;
 	old_req.VendorGuid = SHIM_LOCK_GUID;
 	if (read_variable (&old_req) == EFI_SUCCESS) {
-- 
1.8.4


From 6c9d5519172ca5f87a08d1a46105c2a68b9f4db7 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Fri, 25 Oct 2013 18:29:07 +0800
Subject: [PATCH 12/20] Make test-key and reset support MOK blacklist

---
 src/mokutil.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index 880c38f..8ff4b41 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -154,7 +154,8 @@ print_help ()
 	printf ("        \t\t\t\t(For --list-enrolled, --list-new,\n");
 	printf ("        \t\t\t\t --list-delete, --import, --delete,\n");
 	printf ("        \t\t\t\t --revoke-import, --revoke-delete,\n");
-	printf ("        \t\t\t\t --import-hash, and --delete-hash)\n");
+	printf ("        \t\t\t\t --import-hash, --delete-hash,\n");
+	printf ("        \t\t\t\t --reset, and --test-key)\n");
 }
 
 static int
@@ -1756,7 +1757,7 @@ read_file(int fd, void **bufp, size_t *lenptr) {
 }
 
 static int
-test_key (const char *key_file)
+test_key (MokRequest req, const char *key_file)
 {
 	void *key = NULL;
 	size_t read_size;
@@ -1774,7 +1775,7 @@ test_key (const char *key_file)
 		goto error;
 	}
 
-	if (!is_valid_request (EfiCertX509Guid, key, read_size, ENROLL_MOK)) {
+	if (!is_valid_request (EfiCertX509Guid, key, read_size, req)) {
 		printf ("%s is not enrolled\n", key_file);
 		ret = 0;
 	} else {
@@ -1793,9 +1794,9 @@ error:
 }
 
 static int
-reset_moks (const char *hash_file, const int root_pw)
+reset_moks (MokRequest req, const char *hash_file, const int root_pw)
 {
-	if (update_request (NULL, 0, ENROLL_MOK, hash_file, root_pw)) {
+	if (update_request (NULL, 0, req, hash_file, root_pw)) {
 		fprintf (stderr, "Failed to issue a reset request\n");
 		return -1;
 	}
@@ -2102,11 +2103,11 @@ main (int argc, char *argv[])
 			ret = sb_state ();
 			break;
 		case TEST_KEY:
-			ret = test_key (key_file);
+			ret = test_key (ENROLL_MOK, key_file);
 			break;
 		case RESET:
 		case RESET | SIMPLE_HASH:
-			ret = reset_moks (hash_file, use_root_pw);
+			ret = reset_moks (ENROLL_MOK, hash_file, use_root_pw);
 			break;
 		case GENERATE_PW_HASH:
 			ret = generate_pw_hash (input_pw);
@@ -2152,6 +2153,13 @@ main (int argc, char *argv[])
 		case REVOKE_DELETE | MOKX:
 			ret = revoke_request (DELETE_BLACKLIST);
 			break;
+		case RESET | MOKX:
+		case RESET | SIMPLE_HASH | MOKX:
+			ret = reset_moks (ENROLL_BLACKLIST, hash_file, use_root_pw);
+			break;
+		case TEST_KEY | MOKX:
+			ret = test_key (ENROLL_BLACKLIST, key_file);
+			break;
 		default:
 			print_help ();
 			break;
-- 
1.8.4


From 0fdc023cf98addb23ae511b91c963619ec1e8e2d Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 30 Oct 2013 10:29:25 +0800
Subject: [PATCH 13/20] Set the verbosity for shim and MokManager

---
 src/mokutil.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/src/mokutil.c b/src/mokutil.c
index 8ff4b41..cd3b622 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -82,6 +82,7 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b,
 #define MOKX               (1 << 20)
 #define IMPORT_HASH        (1 << 21)
 #define DELETE_HASH        (1 << 22)
+#define VERBOSITY          (1 << 23)
 
 #define DEFAULT_CRYPT_METHOD SHA512_BASED
 #define DEFAULT_SALT_SIZE    SHA512_SALT_MAX
@@ -136,6 +137,7 @@ print_help ()
 	printf ("  --use-db\t\t\t\tUse DB for validation\n");
 	printf ("  --import-hash <hash>\t\t\tImport a hash\n");
 	printf ("  --delete-hash <hash>\t\t\tDelete a specific hash\n");
+	printf ("  --set-verbosity <true/false>\t\tSet the verbosity bit for shim\n");
 	printf ("\n");
 	printf ("Supplimentary Options:\n");
 	printf ("  --hash-file <hash file>\t\tUse the specific password hash\n");
@@ -1856,6 +1858,31 @@ generate_pw_hash (const char *input_pw)
 	return 0;
 }
 
+static int
+set_verbosity (uint8_t verbosity)
+{
+	efi_variable_t var;
+
+	if (verbosity) {
+		var.VariableName = "SHIM_VERBOSE";
+		var.VendorGuid = SHIM_LOCK_GUID;
+		var.Data = (void *)&verbosity;
+		var.DataSize = sizeof(uint8_t);
+		var.Attributes = EFI_VARIABLE_NON_VOLATILE
+			| EFI_VARIABLE_BOOTSERVICE_ACCESS
+			| EFI_VARIABLE_RUNTIME_ACCESS;
+
+		if (edit_protected_variable (&var) != EFI_SUCCESS) {
+			fprintf (stderr, "Failed to set SHIM_VERBOSE\n");
+			return -1;
+		}
+	} else {
+		return test_and_delete_var ("SHIM_VERBOSE");
+	}
+
+	return 0;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1868,6 +1895,7 @@ main (int argc, char *argv[])
 	int c, i, f_ind, total = 0;
 	unsigned int command = 0;
 	int use_root_pw = 0;
+	uint8_t verbosity = 0;
 	int ret = -1;
 
 	use_simple_hash = 0;
@@ -1899,6 +1927,7 @@ main (int argc, char *argv[])
 			{"mokx",               no_argument,       0, 0  },
 			{"import-hash",        required_argument, 0, 0  },
 			{"delete-hash",        required_argument, 0, 0  },
+			{"set-verbosity",      required_argument, 0, 0  },
 			{0, 0, 0, 0}
 		};
 
@@ -1950,6 +1979,14 @@ main (int argc, char *argv[])
 					break;
 				}
 				hash_str = strdup (optarg);
+			} else if (strcmp (option, "set-verbosity") == 0) {
+				command |= VERBOSITY;
+				if (strcmp (optarg, "true") == 0)
+					verbosity = 1;
+				else if (strcmp (optarg, "false") == 0)
+					verbosity = 0;
+				else
+					command |= HELP;
 			}
 			break;
 		case 'd':
@@ -2160,6 +2197,9 @@ main (int argc, char *argv[])
 		case TEST_KEY | MOKX:
 			ret = test_key (ENROLL_BLACKLIST, key_file);
 			break;
+		case VERBOSITY:
+			ret = set_verbosity (verbosity);
+			break;
 		default:
 			print_help ();
 			break;
-- 
1.8.4


From 96dfa331c2067c3a44d6086ec86e6abb87f3c30f Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 26 Nov 2013 12:36:12 +0800
Subject: [PATCH 14/20] Update the help and manpage

---
 man/mokutil.1 | 30 +++++++++++++++++++++++++++---
 src/mokutil.c |  4 ++--
 2 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/man/mokutil.1 b/man/mokutil.1
index abfdebb..fa990e5 100644
--- a/man/mokutil.1
+++ b/man/mokutil.1
@@ -5,22 +5,27 @@ mokutil \- utility to manipulate machine owner keys
 
 .SH SYNOPSIS
 \fBmokutil\fR [--list-enrolled]
+        ([--mokx])
 .br
 \fBmokutil\fR [--list-new]
+        ([--mokx])
 .br
 \fBmokutil\fR [--list-delete]
+        ([--mokx])
 .br
 \fBmokutil\fR [--import \fIkeylist\fR| -i \fIkeylist\fR]
         ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
-         [--simple-hash | -s])
+         [--simple-hash | -s] | [--mokx])
 .br
 \fBmokutil\fR [--delete \fIkeylist\fR | -d \fIkeylist\fR]
         ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
-         [--simple-hash | -s])
+         [--simple-hash | -s] | [--mokx])
 .br
 \fBmokutil\fR [--revoke-import]
+        ([--mokx])
 .br
 \fBmokutil\fR [--revoke-delete]
+        ([--mokx])
 .br
 \fBmokutil\fR [--export | -x]
 .br
@@ -41,10 +46,16 @@ mokutil \- utility to manipulate machine owner keys
 .br
 \fBmokutil\fR [--reset]
         ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
-         [--simple-hash | -s])
+         [--simple-hash | -s] | [--mok])
 .br
 \fBmokutil\fR [--generate-hash=\fIpassword\fR | -g\fIpassword\fR]
 .br
+\fBmokutil\fR [--ignore-db]
+.br
+\fBmokutil\fR [--use-db]
+.br
+\fBmokutil\fR [--set-verbosity (\fItrue\fR | \fIfalse\fR)]
+.br
 
 .SH DESCRIPTION
 \fBmokutil\fR is a tool to import or delete the machines owner keys
@@ -108,3 +119,16 @@ Use the root password hash from /etc/shadow
 Use the old SHA256 password hash method to hash the password
 .br
 Note: --root-pw invalidates --simple-hash
+.TP
+\fB--ignore-db\fR
+Tell shim to not use the keys in db to verify EFI images
+.TP
+\fB--use-db\fR
+Tell shim to use the keys in db to verify EFI images (default)
+.TP
+\fB--mokx\fR
+Manipulate the MOK blacklist (MOKX) instead of the MOK list
+.TP
+\fB--set-verbosity\fR
+Set the SHIM_VERBOSE to make shim more or less verbose
+.TP
diff --git a/src/mokutil.c b/src/mokutil.c
index cd3b622..a1f1213 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -135,8 +135,8 @@ print_help ()
 	printf ("  --generate-hash[=password]\t\tGenerate the password hash\n");
 	printf ("  --ignore-db\t\t\t\tIgnore DB for validation\n");
 	printf ("  --use-db\t\t\t\tUse DB for validation\n");
-	printf ("  --import-hash <hash>\t\t\tImport a hash\n");
-	printf ("  --delete-hash <hash>\t\t\tDelete a specific hash\n");
+	printf ("  --import-hash <hash>\t\t\tImport a hash into MOK or MOKX\n");
+	printf ("  --delete-hash <hash>\t\t\tDelete a hash in MOK or MOKX\n");
 	printf ("  --set-verbosity <true/false>\t\tSet the verbosity bit for shim\n");
 	printf ("\n");
 	printf ("Supplimentary Options:\n");
-- 
1.8.4


From e2ea0acb875247d70626545d5f3837f2a422af2f Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 26 Nov 2013 12:40:57 +0800
Subject: [PATCH 15/20] Make the help less verbose

It's all in the manpage anyway.
---
 src/mokutil.c | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index a1f1213..628df7d 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -141,23 +141,9 @@ print_help ()
 	printf ("\n");
 	printf ("Supplimentary Options:\n");
 	printf ("  --hash-file <hash file>\t\tUse the specific password hash\n");
-	printf ("                         \t\t(For --import, --delete, --password,\n");
-	printf ("                         \t\t --reset, --import-hash,\n");
-	printf ("                         \t\t and --delete-hash)\n");
 	printf ("  --root-pw\t\t\t\tUse the root password\n");
-	printf ("           \t\t\t\t(For --import, --delete, --password,\n");
-	printf ("           \t\t\t\t --reset, --import-hash,\n");
-	printf ("           \t\t\t\t and --delete-hash)\n");
 	printf ("  --simple-hash\t\t\t\tUse the old password hash method\n");
-	printf ("               \t\t\t\t(For --import, --delete, --password,\n");
-	printf ("               \t\t\t\t --clear-password, --reset,\n");
-	printf ("               \t\t\t\t --import-hash, and --delete-hash)\n");
 	printf ("  --mokx\t\t\t\tManipulate the MOK blacklist\n");
-	printf ("        \t\t\t\t(For --list-enrolled, --list-new,\n");
-	printf ("        \t\t\t\t --list-delete, --import, --delete,\n");
-	printf ("        \t\t\t\t --revoke-import, --revoke-delete,\n");
-	printf ("        \t\t\t\t --import-hash, --delete-hash,\n");
-	printf ("        \t\t\t\t --reset, and --test-key)\n");
 }
 
 static int
-- 
1.8.4


From 72dd17981660747bc84b7ce643451110529ece38 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 26 Nov 2013 16:26:16 +0800
Subject: [PATCH 16/20] New options to list the firmware keys

---
 man/mokutil.1 | 20 +++++++++++++
 src/mokutil.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 102 insertions(+), 11 deletions(-)

diff --git a/man/mokutil.1 b/man/mokutil.1
index fa990e5..86846b4 100644
--- a/man/mokutil.1
+++ b/man/mokutil.1
@@ -56,6 +56,14 @@ mokutil \- utility to manipulate machine owner keys
 .br
 \fBmokutil\fR [--set-verbosity (\fItrue\fR | \fIfalse\fR)]
 .br
+\fBmokutil\fR [--pk]
+.br
+\fBmokutil\fR [--kek]
+.br
+\fBmokutil\fR [--db]
+.br
+\fBmokutil\fR [--dbx]
+.br
 
 .SH DESCRIPTION
 \fBmokutil\fR is a tool to import or delete the machines owner keys
@@ -132,3 +140,15 @@ Manipulate the MOK blacklist (MOKX) instead of the MOK list
 \fB--set-verbosity\fR
 Set the SHIM_VERBOSE to make shim more or less verbose
 .TP
+\fB--pk\fR
+List the keys in the public Platform Key (PK)
+.TP
+\fB--kek\fR
+List the keys in the Key Exchange Key Signature database (KEK)
+.TP
+\fB--db\fR
+List the keys in the secure boot signature store (db)
+.TP
+\fB--dbx\fR
+List the keys in the secure boot blacklist signature store (dbx)
+.TP
diff --git a/src/mokutil.c b/src/mokutil.c
index 628df7d..6f5aec4 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -97,6 +97,15 @@ typedef enum {
 	ENROLL_BLACKLIST
 } MokRequest;
 
+typedef enum {
+	MOK_LIST_RT = 0,
+	MOK_LIST_X_RT,
+	PK,
+	KEK,
+	DB,
+	DBX,
+} DBName;
+
 typedef struct {
 	EFI_SIGNATURE_LIST *header;
 	uint32_t            mok_size;
@@ -138,6 +147,10 @@ print_help ()
 	printf ("  --import-hash <hash>\t\t\tImport a hash into MOK or MOKX\n");
 	printf ("  --delete-hash <hash>\t\t\tDelete a hash in MOK or MOKX\n");
 	printf ("  --set-verbosity <true/false>\t\tSet the verbosity bit for shim\n");
+	printf ("  --pk\t\t\t\t\tList the keys in PK\n");
+	printf ("  --kek\t\t\t\t\tList the keys in KEK\n");
+	printf ("  --db\t\t\t\t\tList the keys in db\n");
+	printf ("  --dbx\t\t\t\t\tList the keys in dbx\n");
 	printf ("\n");
 	printf ("Supplimentary Options:\n");
 	printf ("  --hash-file <hash file>\t\tUse the specific password hash\n");
@@ -523,7 +536,7 @@ done:
 }
 
 static int
-list_keys_in_var (const char *var_name)
+list_keys_in_var (const char *var_name, const efi_guid_t guid)
 {
 	efi_variable_t var;
 	efi_status_t status;
@@ -531,7 +544,7 @@ list_keys_in_var (const char *var_name)
 
 	memset (&var, 0, sizeof(var));
 	var.VariableName = var_name;
-	var.VendorGuid = SHIM_LOCK_GUID;
+	var.VendorGuid = guid;
 
 	status = read_variable (&var);
 	if (status != EFI_SUCCESS) {
@@ -1869,6 +1882,27 @@ set_verbosity (uint8_t verbosity)
 	return 0;
 }
 
+static inline int
+list_db (DBName db_name)
+{
+	switch (db_name) {
+		case MOK_LIST_RT:
+			return list_keys_in_var ("MokListRT", SHIM_LOCK_GUID);
+		case MOK_LIST_X_RT:
+			return list_keys_in_var ("MokListXRT", SHIM_LOCK_GUID);
+		case PK:
+			return list_keys_in_var ("PK", EFI_GLOBAL_VARIABLE);
+		case KEK:
+			return list_keys_in_var ("KEK", EFI_GLOBAL_VARIABLE);
+		case DB:
+			return list_keys_in_var ("db", EFI_IMAGE_SECURITY_DATABASE_GUID);
+		case DBX:
+			return list_keys_in_var ("dbx", EFI_IMAGE_SECURITY_DATABASE_GUID);
+	}
+
+	return -1;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1882,6 +1916,7 @@ main (int argc, char *argv[])
 	unsigned int command = 0;
 	int use_root_pw = 0;
 	uint8_t verbosity = 0;
+	DBName db_name = MOK_LIST_RT;
 	int ret = -1;
 
 	use_simple_hash = 0;
@@ -1914,6 +1949,10 @@ main (int argc, char *argv[])
 			{"import-hash",        required_argument, 0, 0  },
 			{"delete-hash",        required_argument, 0, 0  },
 			{"set-verbosity",      required_argument, 0, 0  },
+			{"pk",                 no_argument,       0, 0  },
+			{"kek",                no_argument,       0, 0  },
+			{"db",                 no_argument,       0, 0  },
+			{"dbx",                no_argument,       0, 0  },
 			{0, 0, 0, 0}
 		};
 
@@ -1950,7 +1989,12 @@ main (int argc, char *argv[])
 			} else if (strcmp (option, "use-db") == 0) {
 				command |= USE_DB;
 			} else if (strcmp (option, "mokx") == 0) {
-				command |= MOKX;
+				if (db_name != MOK_LIST_RT) {
+					command |= HELP;
+				} else {
+					command |= MOKX;
+					db_name = MOK_LIST_X_RT;
+				}
 			} else if (strcmp (option, "import-hash") == 0) {
 				command |= IMPORT_HASH;
 				if (hash_str) {
@@ -1973,7 +2017,36 @@ main (int argc, char *argv[])
 					verbosity = 0;
 				else
 					command |= HELP;
+			} else if (strcmp (option, "pk") == 0) {
+				if (db_name != MOK_LIST_RT) {
+					command |= HELP;
+				} else {
+					command |= LIST_ENROLLED;
+					db_name = PK;
+				}
+			} else if (strcmp (option, "kek") == 0) {
+				if (db_name != MOK_LIST_RT) {
+					command |= HELP;
+				} else {
+					command |= LIST_ENROLLED;
+					db_name = KEK;
+				}
+			} else if (strcmp (option, "db") == 0) {
+				if (db_name != MOK_LIST_RT) {
+					command |= HELP;
+				} else {
+					command |= LIST_ENROLLED;
+					db_name = DB;
+				}
+			} else if (strcmp (option, "dbx") == 0) {
+				if (db_name != MOK_LIST_RT) {
+					command |= HELP;
+				} else {
+					command |= LIST_ENROLLED;
+					db_name = DBX;
+				}
 			}
+
 			break;
 		case 'd':
 		case 'i':
@@ -2071,13 +2144,14 @@ main (int argc, char *argv[])
 
 	switch (command) {
 		case LIST_ENROLLED:
-			ret = list_keys_in_var ("MokListRT");
+		case LIST_ENROLLED | MOKX:
+			ret = list_db (db_name);
 			break;
 		case LIST_NEW:
-			ret = list_keys_in_var ("MokNew");
+			ret = list_keys_in_var ("MokNew", SHIM_LOCK_GUID);
 			break;
 		case LIST_DELETE:
-			ret = list_keys_in_var ("MokDel");
+			ret = list_keys_in_var ("MokDel", SHIM_LOCK_GUID);
 			break;
 		case IMPORT:
 		case IMPORT | SIMPLE_HASH:
@@ -2141,14 +2215,11 @@ main (int argc, char *argv[])
 		case USE_DB:
 			ret = enable_db ();
 			break;
-		case LIST_ENROLLED | MOKX:
-			ret = list_keys_in_var ("MokListXRT");
-			break;
 		case LIST_NEW | MOKX:
-			ret = list_keys_in_var ("MokXNew");
+			ret = list_keys_in_var ("MokXNew", SHIM_LOCK_GUID);
 			break;
 		case LIST_DELETE | MOKX:
-			ret = list_keys_in_var ("MokXDel");
+			ret = list_keys_in_var ("MokXDel", SHIM_LOCK_GUID);
 			break;
 		case IMPORT | MOKX:
 		case IMPORT | SIMPLE_HASH | MOKX:
-- 
1.8.4


From 9820c083e2a9b605a59aae7bdf56992f63abf7b8 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 26 Nov 2013 16:49:14 +0800
Subject: [PATCH 17/20] Add more short options

---
 man/mokutil.1 | 54 +++++++++++++++++++++++++++++-------------------------
 src/mokutil.c | 42 +++++++++++++++++++++++-------------------
 2 files changed, 52 insertions(+), 44 deletions(-)

diff --git a/man/mokutil.1 b/man/mokutil.1
index 86846b4..02b346f 100644
--- a/man/mokutil.1
+++ b/man/mokutil.1
@@ -4,28 +4,28 @@
 mokutil \- utility to manipulate machine owner keys
 
 .SH SYNOPSIS
-\fBmokutil\fR [--list-enrolled]
-        ([--mokx])
+\fBmokutil\fR [--list-enrolled | -l]
+        ([--mokx | -X])
 .br
-\fBmokutil\fR [--list-new]
-        ([--mokx])
+\fBmokutil\fR [--list-new | -N]
+        ([--mokx | -X])
 .br
-\fBmokutil\fR [--list-delete]
-        ([--mokx])
+\fBmokutil\fR [--list-delete | -D]
+        ([--mokx | -X])
 .br
 \fBmokutil\fR [--import \fIkeylist\fR| -i \fIkeylist\fR]
         ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
-         [--simple-hash | -s] | [--mokx])
+         [--simple-hash | -s] | [--mokx | -X])
 .br
 \fBmokutil\fR [--delete \fIkeylist\fR | -d \fIkeylist\fR]
         ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
-         [--simple-hash | -s] | [--mokx])
+         [--simple-hash | -s] | [--mokx |- X])
 .br
 \fBmokutil\fR [--revoke-import]
-        ([--mokx])
+        ([--mokx | -X])
 .br
 \fBmokutil\fR [--revoke-delete]
-        ([--mokx])
+        ([--mokx | -X])
 .br
 \fBmokutil\fR [--export | -x]
 .br
@@ -42,11 +42,11 @@ mokutil \- utility to manipulate machine owner keys
 .br
 \fBmokutil\fR [--sb-state]
 .br
-\fBmokutil\fR [--test-key | -t] ...
+\fBmokutil\fR [--test-key \fIkeyfile\fR | -t \fIkeyfile\fR]
 .br
 \fBmokutil\fR [--reset]
         ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
-         [--simple-hash | -s] | [--mok])
+         [--simple-hash | -s] | [--mok | -X])
 .br
 \fBmokutil\fR [--generate-hash=\fIpassword\fR | -g\fIpassword\fR]
 .br
@@ -71,18 +71,22 @@ mokutil \- utility to manipulate machine owner keys
 
 .SH OPTIONS
 .TP
-\fB--list-enrolled\fR
+\fB-l, --list-enrolled\fR
 List the keys the already stored in the database
 .TP
-\fB--list-new\fR
+\fB-N, --list-new\fR
 List the keys to be enrolled
 .TP
-\fB--list-delete\fR
+\fB-D, --list-delete\fR
 List the keys to be deleted
 .TP
-\fB--import\fR
-Collect the followed files and form a request to shim. The files must be in DER
-format.
+\fB-i, --import\fR
+Collect the followed files and form a enrolling request to shim. The files must
+be in DER format.
+.TP
+\fB-d, --delete\fR
+Collect the followed files and form a deleting request to shim. The files must be
+in DER format.
 .TP
 \fB--revoke-import\fR
 Revoke the current import request (MokNew)
@@ -90,13 +94,13 @@ Revoke the current import request (MokNew)
 \fB--revoke-delete\fR
 Revoke the current delete request (MokDel)
 .TP
-\fB--export\fR
+\fB-x, --export\fR
 Export the keys stored in MokListRT
 .TP
-\fB--password\fR
+\fB-p, --password\fR
 Setup the password for MokManager (MokPW)
 .TP
-\fB--clear-password\fR
+\fB-c, --clear-password\fR
 Clear the password for MokManager (MokPW)
 .TP
 \fB--disable-validation\fR
@@ -108,7 +112,7 @@ Enable the validation process in shim
 \fB--sb-state\fR
 Show SecureBoot State
 .TP
-\fB--test-key\fR
+\fB-t, --test-key\fR
 Test if the key is enrolled or not
 .TP
 \fB--reset\fR
@@ -120,10 +124,10 @@ Generate the password hash
 \fB--hash-file\fR
 Use the password hash from a specific file
 .TP
-\fB--root-pw\fR
+\fB-P, --root-pw\fR
 Use the root password hash from /etc/shadow
 .TP
-\fB--simple-hash\fR
+\fB-s, --simple-hash\fR
 Use the old SHA256 password hash method to hash the password
 .br
 Note: --root-pw invalidates --simple-hash
@@ -134,7 +138,7 @@ Tell shim to not use the keys in db to verify EFI images
 \fB--use-db\fR
 Tell shim to use the keys in db to verify EFI images (default)
 .TP
-\fB--mokx\fR
+\fB-X, --mokx\fR
 Manipulate the MOK blacklist (MOKX) instead of the MOK list
 .TP
 \fB--set-verbosity\fR
diff --git a/src/mokutil.c b/src/mokutil.c
index 6f5aec4..6fe8ae2 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1924,9 +1924,9 @@ main (int argc, char *argv[])
 	while (1) {
 		static struct option long_options[] = {
 			{"help",               no_argument,       0, 'h'},
-			{"list-enrolled",      no_argument,       0, 0  },
-			{"list-new",	       no_argument,       0, 0  },
-			{"list-delete",	       no_argument,       0, 0  },
+			{"list-enrolled",      no_argument,       0, 'l'},
+			{"list-new",	       no_argument,       0, 'N'},
+			{"list-delete",	       no_argument,       0, 'D'},
 			{"import",             required_argument, 0, 'i'},
 			{"delete",             required_argument, 0, 'd'},
 			{"revoke-import",      no_argument,       0, 0  },
@@ -1945,7 +1945,7 @@ main (int argc, char *argv[])
 			{"simple-hash",        no_argument,       0, 's'},
 			{"ignore-db",          no_argument,       0, 0  },
 			{"use-db",             no_argument,       0, 0  },
-			{"mokx",               no_argument,       0, 0  },
+			{"mokx",               no_argument,       0, 'X'},
 			{"import-hash",        required_argument, 0, 0  },
 			{"delete-hash",        required_argument, 0, 0  },
 			{"set-verbosity",      required_argument, 0, 0  },
@@ -1957,7 +1957,7 @@ main (int argc, char *argv[])
 		};
 
 		int option_index = 0;
-		c = getopt_long (argc, argv, "cd:f:g::hi:pst:xP",
+		c = getopt_long (argc, argv, "cd:f:g::hi:lpst:xDNPX",
 				 long_options, &option_index);
 
 		if (c == -1)
@@ -1966,13 +1966,7 @@ main (int argc, char *argv[])
 		switch (c) {
 		case 0:
 			option = long_options[option_index].name;
-			if (strcmp (option, "list-enrolled") == 0) {
-				command |= LIST_ENROLLED;
-			} else if (strcmp (option, "list-new") == 0) {
-				command |= LIST_NEW;
-			} else if (strcmp (option, "list-delete") == 0) {
-				command |= LIST_DELETE;
-			} else if (strcmp (option, "revoke-import") == 0) {
+			if (strcmp (option, "revoke-import") == 0) {
 				command |= REVOKE_IMPORT;
 			} else if (strcmp (option, "revoke-delete") == 0) {
 				command |= REVOKE_DELETE;
@@ -1988,13 +1982,6 @@ main (int argc, char *argv[])
 				command |= IGNORE_DB;
 			} else if (strcmp (option, "use-db") == 0) {
 				command |= USE_DB;
-			} else if (strcmp (option, "mokx") == 0) {
-				if (db_name != MOK_LIST_RT) {
-					command |= HELP;
-				} else {
-					command |= MOKX;
-					db_name = MOK_LIST_X_RT;
-				}
 			} else if (strcmp (option, "import-hash") == 0) {
 				command |= IMPORT_HASH;
 				if (hash_str) {
@@ -2048,6 +2035,15 @@ main (int argc, char *argv[])
 			}
 
 			break;
+		case 'l':
+			command |= LIST_ENROLLED;
+			break;
+		case 'N':
+			command |= LIST_NEW;
+			break;
+		case 'D':
+			command |= LIST_DELETE;
+			break;
 		case 'd':
 		case 'i':
 			if (c == 'd')
@@ -2127,6 +2123,14 @@ main (int argc, char *argv[])
 			command |= SIMPLE_HASH;
 			use_simple_hash = 1;
 			break;
+		case 'X':
+			if (db_name != MOK_LIST_RT) {
+				command |= HELP;
+			} else {
+				command |= MOKX;
+				db_name = MOK_LIST_X_RT;
+			}
+			break;
 		case 'h':
 		case '?':
 			command |= HELP;
-- 
1.8.4


From 0ff8112146c355c1bc4eec57cdeb0aed4cc4065c Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 26 Nov 2013 18:13:20 +0800
Subject: [PATCH 18/20] Catch the error from strdup()

---
 src/mokutil.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index 6fe8ae2..27b9585 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1989,6 +1989,10 @@ main (int argc, char *argv[])
 					break;
 				}
 				hash_str = strdup (optarg);
+				if (hash_str == NULL) {
+					fprintf (stderr, "Could not allocate space: %m\n");
+					exit(1);
+				}
 			} else if (strcmp (option, "delete-hash") == 0) {
 				command |= DELETE_HASH;
 				if (hash_str) {
@@ -1996,6 +2000,10 @@ main (int argc, char *argv[])
 					break;
 				}
 				hash_str = strdup (optarg);
+				if (hash_str == NULL) {
+					fprintf (stderr, "Could not allocate space: %m\n");
+					exit(1);
+				}
 			} else if (strcmp (option, "set-verbosity") == 0) {
 				command |= VERBOSITY;
 				if (strcmp (optarg, "true") == 0)
@@ -2069,6 +2077,10 @@ main (int argc, char *argv[])
 			}
 
 			files = malloc (total * sizeof (char *));
+			if (files == NULL) {
+				fprintf (stderr, "Could not allocate space: %m\n");
+				exit(1);
+			}
 			for (i = 0; i < total; i++) {
 				f_ind = i + optind - 1;
 				files[i] = malloc (strlen(argv[f_ind]) + 1);
@@ -2082,6 +2094,10 @@ main (int argc, char *argv[])
 				break;
 			}
 			hash_file = strdup (optarg);
+			if (hash_file == NULL) {
+				fprintf (stderr, "Could not allocate space: %m\n");
+				exit(1);
+			}
 
 			break;
 		case 'g':
@@ -2089,8 +2105,13 @@ main (int argc, char *argv[])
 				command |= HELP;
 				break;
 			}
-			if (optarg)
+			if (optarg) {
 				input_pw = strdup (optarg);
+				if (input_pw == NULL) {
+					fprintf (stderr, "Could not allocate space: %m\n");
+					exit(1);
+				}
+			}
 
 			command |= GENERATE_PW_HASH;
 			break;
-- 
1.8.4


From f77d5e52b0318dbf8f92b2bd89aab0a3d5d77078 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 22 Jan 2014 13:46:24 +0800
Subject: [PATCH 19/20] Fix the test-key request check

---
 src/mokutil.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index 27b9585..dbec25b 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1776,7 +1776,7 @@ test_key (MokRequest req, const char *key_file)
 		goto error;
 	}
 
-	if (!is_valid_request (EfiCertX509Guid, key, read_size, req)) {
+	if (is_valid_request (EfiCertX509Guid, key, read_size, req)) {
 		printf ("%s is not enrolled\n", key_file);
 		ret = 0;
 	} else {
-- 
1.8.4


From d921883b2f8ce4e9e9304af5d9b44aac1e701e51 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 22 Jan 2014 13:51:36 +0800
Subject: [PATCH 20/20] Update manpage for --test-key

---
 man/mokutil.1 | 1 +
 1 file changed, 1 insertion(+)

diff --git a/man/mokutil.1 b/man/mokutil.1
index 02b346f..ca9380d 100644
--- a/man/mokutil.1
+++ b/man/mokutil.1
@@ -43,6 +43,7 @@ mokutil \- utility to manipulate machine owner keys
 \fBmokutil\fR [--sb-state]
 .br
 \fBmokutil\fR [--test-key \fIkeyfile\fR | -t \fIkeyfile\fR]
+        ([--mokx | -X])
 .br
 \fBmokutil\fR [--reset]
         ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
-- 
1.8.4

openSUSE Build Service is sponsored by