File pesign-enable-supplementary-programs.patch of Package pesign

From 4d80fec4a38b5cb1a63262a323353c23b0172b77 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 24 Dec 2013 11:33:26 +0800
Subject: [PATCH 01/31] Allocate cms_context for peverify_context

This avoids the crash while freeing cms_context.

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/peverify.c         | 6 +++---
 src/peverify_context.c | 4 ++--
 src/peverify_context.h | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/peverify.c b/src/peverify.c
index fc6de05..62e9995 100644
--- a/src/peverify.c
+++ b/src/peverify.c
@@ -55,8 +55,8 @@ open_input(peverify_context *ctx)
 		exit(1);
 	}
 
-	int rc = parse_signatures(&ctx->cms_ctx.signatures,
-					&ctx->cms_ctx.num_signatures,
+	int rc = parse_signatures(&ctx->cms_ctx->signatures,
+					&ctx->cms_ctx->num_signatures,
 					ctx->inpe);
 	if (rc < 0) {
 		fprintf(stderr, "pesign: could not parse signature list in "
@@ -99,7 +99,7 @@ check_signature(peverify_context *ctx)
 
 	cert_iter iter;
 
-	generate_digest(&ctx->cms_ctx, ctx->inpe, 1);
+	generate_digest(ctx->cms_ctx, ctx->inpe, 1);
 	
 	if (check_db_hash(DBX, ctx) == FOUND)
 		return -1;
diff --git a/src/peverify_context.c b/src/peverify_context.c
index 2e59f74..44fc442 100644
--- a/src/peverify_context.c
+++ b/src/peverify_context.c
@@ -54,7 +54,7 @@ peverify_context_init(peverify_context *ctx)
 
 	ctx->infd = -1;
 
-	int rc = cms_context_init(&ctx->cms_ctx);
+	int rc = cms_context_alloc(&ctx->cms_ctx);
 	if (rc < 0)
 		return rc;
 
@@ -67,7 +67,7 @@ peverify_context_fini(peverify_context *ctx)
 	if (!ctx)
 		return;
 
-	cms_context_fini(&ctx->cms_ctx);
+	cms_context_fini(ctx->cms_ctx);
 
 	xfree(ctx->infile);
 
diff --git a/src/peverify_context.h b/src/peverify_context.h
index f9b0083..8599357 100644
--- a/src/peverify_context.h
+++ b/src/peverify_context.h
@@ -57,7 +57,7 @@ typedef struct peverify_context {
 	dblist *db;
 	dblist *dbx;
 
-	cms_context cms_ctx;
+	cms_context *cms_ctx;
 } peverify_context;
 
 extern int peverify_context_new(peverify_context **ctx);
-- 
1.8.4.5


From b6e40af634aa0b10f59b5936727ccfc260f3dcf0 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 24 Dec 2013 11:48:08 +0800
Subject: [PATCH 02/31] Calculate the dbsize to avoid the infinite loop

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/certdb.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/certdb.c b/src/certdb.c
index 5ef3ffe..b6e7c20 100644
--- a/src/certdb.c
+++ b/src/certdb.c
@@ -144,6 +144,10 @@ check_db(db_specifier which, peverify_context *ctx, checkfn check)
 				if (found == FOUND)
 					return FOUND;
 			}
+
+			dbsize -= certlist->SignatureListSize;
+			certlist = (EFI_SIGNATURE_LIST *)((uint8_t *)certlist +
+			            certlist->SignatureListSize);
 		}
 		dbl = dbl->next;
 	}
-- 
1.8.4.5


From cab9f9ff4737be3e3607caa6dd7f945c50fe64fa Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 24 Dec 2013 12:35:02 +0800
Subject: [PATCH 03/31] Update the pathes of db, MokListRT, and dbx

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/certdb.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/certdb.c b/src/certdb.c
index b6e7c20..f6f52bc 100644
--- a/src/certdb.c
+++ b/src/certdb.c
@@ -75,9 +75,9 @@ add_cert_dbx(peverify_context *ctx, const char *filename)
 	return add_db_file(ctx, DBX, filename);
 }
 
-#define DB_PATH "/sys/firmware/efi/vars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f/data"
-#define MOK_PATH "/sys/firmware/efi/vars/fixmefixmefixme/data"
-#define DBX_PATH "/sys/firmware/efi/vars/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f/data"
+#define DB_PATH "/sys/firmware/efi/efivars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f"
+#define MOK_PATH "/sys/firmware/efi/efivars/MokListRT-605dab50-e046-4300-abb6-3dd810dd8b23"
+#define DBX_PATH "/sys/firmware/efi/efivars/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f"
 
 void
 init_cert_db(peverify_context *ctx, int use_system_dbs)
@@ -97,7 +97,7 @@ init_cert_db(peverify_context *ctx, int use_system_dbs)
 	rc = add_db_file(ctx, DB, MOK_PATH);
 	if (rc < 0 && errno != ENOENT) {
 		fprintf(stderr, "peverify: Could not add key database "
-			"\"%s\": %m\n", DB_PATH);
+			"\"%s\": %m\n", MOK_PATH);
 		exit(1);
 	}
 
-- 
1.8.4.5


From 200bff332ee34de2e2679cfdddd8d09a78b536f7 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 24 Dec 2013 14:53:58 +0800
Subject: [PATCH 04/31] Skip the first 4 bytes in the efi variables

The first 4 bytes store the attributes of the efi variable.

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/certdb.c           | 25 +++++++++++++++++--------
 src/peverify_context.h |  2 ++
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/certdb.c b/src/certdb.c
index f6f52bc..d9d4dea 100644
--- a/src/certdb.c
+++ b/src/certdb.c
@@ -26,7 +26,7 @@
 #include "peverify.h"
 
 static int
-add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile)
+add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile, int efivar)
 {
 	dblist *db = calloc(1, sizeof (dblist));
 	
@@ -55,6 +55,15 @@ add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile)
 		return -1;
 	}
 
+	/* skip the first 4 bytes (EFI attributes) in the efi variable */
+	if (efivar == 1) {
+		db->data = db->map + 4;
+		db->datalen = db->size - 4;
+	} else {
+		db->data = db->map;
+		db->datalen = db->size;
+	}
+
 	dblist **tmp = which == DB ? &ctx->db : &ctx->dbx;
 
 	db->next = *tmp;
@@ -66,13 +75,13 @@ add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile)
 int
 add_cert_db(peverify_context *ctx, const char *filename)
 {
-	return add_db_file(ctx, DB, filename);
+	return add_db_file(ctx, DB, filename, 0);
 }
 
 int
 add_cert_dbx(peverify_context *ctx, const char *filename)
 {
-	return add_db_file(ctx, DBX, filename);
+	return add_db_file(ctx, DBX, filename, 0);
 }
 
 #define DB_PATH "/sys/firmware/efi/efivars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f"
@@ -87,14 +96,14 @@ init_cert_db(peverify_context *ctx, int use_system_dbs)
 	if (!use_system_dbs)
 		return;
 
-	rc = add_db_file(ctx, DB, DB_PATH);
+	rc = add_db_file(ctx, DB, DB_PATH, 1);
 	if (rc < 0 && errno != ENOENT) {
 		fprintf(stderr, "peverify: Could not add key database "
 			"\"%s\": %m\n", DB_PATH);
 		exit(1);
 	}
 
-	rc = add_db_file(ctx, DB, MOK_PATH);
+	rc = add_db_file(ctx, DB, MOK_PATH, 1);
 	if (rc < 0 && errno != ENOENT) {
 		fprintf(stderr, "peverify: Could not add key database "
 			"\"%s\": %m\n", MOK_PATH);
@@ -106,7 +115,7 @@ init_cert_db(peverify_context *ctx, int use_system_dbs)
 			"No key database available\n");
 	}
 
-	rc = add_db_file(ctx, DBX, DBX_PATH);
+	rc = add_db_file(ctx, DBX, DBX_PATH, 1);
 	if (rc < 0 && errno != ENOENT) {
 		fprintf(stderr, "peverify: Could not add revocation "
 			"database \"%s\": %m\n", DBX_PATH);
@@ -126,10 +135,10 @@ check_db(db_specifier which, peverify_context *ctx, checkfn check)
 	while (dbl) {
 		EFI_SIGNATURE_LIST *certlist;
 		EFI_SIGNATURE_DATA *cert;
-		size_t dbsize = dbl->size;
+		size_t dbsize = dbl->datalen;
 		unsigned long certcount;
 
-		certlist = dbl->map;
+		certlist = dbl->data;
 		while (dbsize > 0 && dbsize >= certlist->SignatureListSize) {
 			certcount = (certlist->SignatureListSize -
 				     certlist->SignatureHeaderSize)
diff --git a/src/peverify_context.h b/src/peverify_context.h
index 8599357..37f415b 100644
--- a/src/peverify_context.h
+++ b/src/peverify_context.h
@@ -31,6 +31,8 @@ struct dblist {
 	struct dblist *next;
 	size_t size;
 	void *map;
+	size_t datalen;
+	void *data;
 };
 
 typedef struct dblist dblist;
-- 
1.8.4.5


From 237e983fe11800e36074c2a50d6468b7ac45ef12 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 25 Dec 2013 14:14:48 +0800
Subject: [PATCH 05/31] Match the hashes in the db list

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/certdb.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/src/certdb.c b/src/certdb.c
index d9d4dea..470f7f3 100644
--- a/src/certdb.c
+++ b/src/certdb.c
@@ -144,7 +144,8 @@ check_db(db_specifier which, peverify_context *ctx, checkfn check)
 				     certlist->SignatureHeaderSize)
 				    / certlist->SignatureSize;
 			cert = (EFI_SIGNATURE_DATA *)((uint8_t *)certlist +
-				sizeof(*cert) + certlist->SignatureHeaderSize);
+				sizeof(EFI_SIGNATURE_LIST) +
+				certlist->SignatureHeaderSize);
 			
 			for (int i = 0; i < certcount; i++) {
 				found = check(ctx,
@@ -152,6 +153,8 @@ check_db(db_specifier which, peverify_context *ctx, checkfn check)
 					      &certlist->SignatureType);
 				if (found == FOUND)
 					return FOUND;
+				cert = (EFI_SIGNATURE_DATA *)((uint8_t *)cert +
+				        certlist->SignatureSize);
 			}
 
 			dbsize -= certlist->SignatureListSize;
@@ -166,6 +169,20 @@ check_db(db_specifier which, peverify_context *ctx, checkfn check)
 static db_status
 check_hash(peverify_context *ctx, void *sigdata, efi_guid_t *sigtype)
 {
+	efi_guid_t efi_sha256 = EFI_CERT_SHA256_GUID;
+	efi_guid_t efi_sha1 = EFI_CERT_SHA1_GUID;
+	void *digest;
+
+	if (memcmp(sigtype, &efi_sha256, sizeof(efi_guid_t)) == 0) {
+		digest = ctx->cms_ctx->digests[0].pe_digest->data;
+		if (memcmp (digest, sigdata, 32) == 0)
+			return FOUND;
+	} else if (memcmp(sigtype, &efi_sha1, sizeof(efi_guid_t)) == 0) {
+		digest = ctx->cms_ctx->digests[1].pe_digest->data;
+		if (memcmp (digest, sigdata, 20) == 0)
+			return FOUND;
+	}
+
 	return NOT_FOUND;
 }
 
-- 
1.8.4.5


From 135a083d0e648255096128a67463bc2191f4ac4a Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 24 Dec 2013 11:47:14 +0800
Subject: [PATCH 06/31] Verify the signature with the certs in the dblist

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/certdb.c   | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 src/peverify.c |  66 +++++++++++++++++++++++++++++-
 2 files changed, 179 insertions(+), 14 deletions(-)

diff --git a/src/certdb.c b/src/certdb.c
index 470f7f3..4937c44 100644
--- a/src/certdb.c
+++ b/src/certdb.c
@@ -23,6 +23,12 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <nss.h>
+#include <prerror.h>
+#include <cert.h>
+#include <pkcs7t.h>
+#include <pk11pub.h>
+
 #include "peverify.h"
 
 static int
@@ -123,15 +129,23 @@ init_cert_db(peverify_context *ctx, int use_system_dbs)
 	}
 }
 
-typedef db_status (*checkfn)(peverify_context *ctx, void *sigdata,
-			     efi_guid_t *sigtype);
+typedef db_status (*checkfn)(peverify_context *ctx, SECItem *sig,
+			     efi_guid_t *sigtype, SECItem *pkcs7sig);
 
 static db_status
-check_db(db_specifier which, peverify_context *ctx, checkfn check)
+check_db(db_specifier which, peverify_context *ctx, checkfn check,
+	 void *data, ssize_t datalen)
 {
+	SECItem pkcs7sig, sig;
 	dblist *dbl = which == DB ? ctx->db : ctx->dbx;
 	db_status found = NOT_FOUND;
 
+	pkcs7sig.data = data;
+	pkcs7sig.len = datalen;
+	pkcs7sig.type = siBuffer;
+
+	sig.type = siBuffer;
+
 	while (dbl) {
 		EFI_SIGNATURE_LIST *certlist;
 		EFI_SIGNATURE_DATA *cert;
@@ -148,9 +162,10 @@ check_db(db_specifier which, peverify_context *ctx, checkfn check)
 				certlist->SignatureHeaderSize);
 			
 			for (int i = 0; i < certcount; i++) {
-				found = check(ctx,
-					      cert->SignatureData,
-					      &certlist->SignatureType);
+				sig.data = cert->SignatureData;
+				sig.len = certlist->SignatureSize - sizeof(efi_guid_t);
+				found = check(ctx, &sig, &certlist->SignatureType,
+					      &pkcs7sig);
 				if (found == FOUND)
 					return FOUND;
 				cert = (EFI_SIGNATURE_DATA *)((uint8_t *)cert +
@@ -167,7 +182,8 @@ check_db(db_specifier which, peverify_context *ctx, checkfn check)
 }
 
 static db_status
-check_hash(peverify_context *ctx, void *sigdata, efi_guid_t *sigtype)
+check_hash(peverify_context *ctx, SECItem *sig, efi_guid_t *sigtype,
+	   SECItem *pkcs7sig)
 {
 	efi_guid_t efi_sha256 = EFI_CERT_SHA256_GUID;
 	efi_guid_t efi_sha1 = EFI_CERT_SHA1_GUID;
@@ -175,11 +191,11 @@ check_hash(peverify_context *ctx, void *sigdata, efi_guid_t *sigtype)
 
 	if (memcmp(sigtype, &efi_sha256, sizeof(efi_guid_t)) == 0) {
 		digest = ctx->cms_ctx->digests[0].pe_digest->data;
-		if (memcmp (digest, sigdata, 32) == 0)
+		if (memcmp (digest, sig->data, 32) == 0)
 			return FOUND;
 	} else if (memcmp(sigtype, &efi_sha1, sizeof(efi_guid_t)) == 0) {
 		digest = ctx->cms_ctx->digests[1].pe_digest->data;
-		if (memcmp (digest, sigdata, 20) == 0)
+		if (memcmp (digest, sig->data, 20) == 0)
 			return FOUND;
 	}
 
@@ -189,17 +205,102 @@ check_hash(peverify_context *ctx, void *sigdata, efi_guid_t *sigtype)
 db_status
 check_db_hash(db_specifier which, peverify_context *ctx)
 {
-	return check_db(which, ctx, check_hash);
+	return check_db(which, ctx, check_hash, NULL, 0);
 }
 
 static db_status
-check_cert(peverify_context *ctx, void *sigdata, efi_guid_t *sigtype)
+check_cert(peverify_context *ctx, SECItem *sig, efi_guid_t *sigtype,
+	   SECItem *pkcs7sig)
 {
-	return NOT_FOUND;
+	SEC_PKCS7ContentInfo *cinfo = NULL;
+	CERTCertificate *cert = NULL;
+	CERTCertTrust trust;
+	SECItem *content, *digest = NULL;
+	PK11Context *pk11ctx = NULL;
+	SECOidData *oid;
+	PRBool result;
+	SECStatus rv;
+	db_status status = NOT_FOUND;
+
+	efi_guid_t efi_x509 = EFI_CERT_X509_GUID;
+
+	if (memcmp(sigtype, &efi_x509, sizeof(efi_guid_t)) != 0)
+		return NOT_FOUND;
+
+	cinfo = SEC_PKCS7DecodeItem(pkcs7sig, NULL, NULL, NULL, NULL, NULL,
+				    NULL, NULL);
+	if (!cinfo)
+		goto out;
+
+	/* Generate the digest of contentInfo */
+	/* XXX support only sha256 for now */
+	digest = SECITEM_AllocItem(NULL, NULL, 32);
+	if (digest == NULL)
+		goto out;
+
+	content = cinfo->content.signedData->contentInfo.content.data;
+	oid = SECOID_FindOIDByTag(SEC_OID_SHA256);
+	if (oid == NULL)
+		goto out;
+	pk11ctx = PK11_CreateDigestContext(oid->offset);
+	if (ctx == NULL)
+		goto out;
+	if (PK11_DigestBegin(pk11ctx) != SECSuccess)
+		goto out;
+	/*   Skip the SEQUENCE tag */
+	if (PK11_DigestOp(pk11ctx, content->data + 2, content->len - 2) != SECSuccess)
+		goto out;
+	if (PK11_DigestFinal(pk11ctx, digest->data, &digest->len, 32) != SECSuccess)
+		goto out;
+
+	/* Import the trusted certificate */
+	cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), sig, "Temp CA",
+				       PR_FALSE, PR_TRUE);
+	if (!cert) {
+		fprintf(stderr, "Unable to create cert: %s\n",
+			PORT_ErrorToString(PORT_GetError()));
+		goto out;
+	}
+
+	rv = CERT_DecodeTrustString(&trust, ",,P");
+	if (rv != SECSuccess) {
+		fprintf(stderr, "Unable to decode trust string: %s\n",
+			PORT_ErrorToString(PORT_GetError()));
+		goto out;
+	}
+
+	rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
+	if (rv != SECSuccess) {
+		fprintf(stderr, "Failed to change cert trust: %s\n",
+			PORT_ErrorToString(PORT_GetError()));
+		goto out;
+	}
+
+	/* Verify the signature */
+	result = SEC_PKCS7VerifyDetachedSignature(cinfo, certUsageObjectSigner,
+						  digest, HASH_AlgSHA256,
+						  PR_FALSE);
+	if (!result) {
+		fprintf(stderr, "%s\n",	PORT_ErrorToString(PORT_GetError()));
+		goto out;
+	}
+
+	status = FOUND;
+out:
+	if (cinfo)
+		SEC_PKCS7DestroyContentInfo(cinfo);
+	if (cert)
+		CERT_DestroyCertificate(cert);
+	if (pk11ctx)
+		PK11_DestroyContext(pk11ctx, PR_TRUE);
+	if (digest)
+		SECITEM_FreeItem(digest, PR_FALSE);
+
+	return status;
 }
 
 db_status
 check_db_cert(db_specifier which, peverify_context *ctx, void *data, ssize_t datalen)
 {
-	return check_db(which, ctx, check_cert);
+	return check_db(which, ctx, check_cert, data, datalen);
 }
diff --git a/src/peverify.c b/src/peverify.c
index 62e9995..47d7ee1 100644
--- a/src/peverify.c
+++ b/src/peverify.c
@@ -24,11 +24,15 @@
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <ftw.h>
+#include <nss.h>
 
 #include <popt.h>
 
+#include <prerror.h>
 #include <cert.h>
 #include <pkcs7t.h>
+#include <pk11pub.h>
 
 #include "peverify.h"
 
@@ -87,7 +91,34 @@ check_inputs(peverify_context *ctx)
 static int
 cert_matches_digest(peverify_context *ctx, void *data, ssize_t datalen)
 {
-	return -1;
+	SECItem sig, *pe_digest, *content;
+	uint8_t *digest;
+	SEC_PKCS7ContentInfo *cinfo = NULL;
+	int ret = -1;
+
+	sig.data = data;
+	sig.len = datalen;
+	sig.type = siBuffer;
+
+	cinfo = SEC_PKCS7DecodeItem(&sig, NULL, NULL, NULL, NULL, NULL,
+				    NULL, NULL);
+
+	if (!SEC_PKCS7ContentIsSigned(cinfo))
+		goto out;
+
+	/* TODO Find out the digest type in spc_content */
+	pe_digest = ctx->cms_ctx->digests[0].pe_digest;
+	content = cinfo->content.signedData->contentInfo.content.data;
+	digest = content->data + content->len - pe_digest->len;
+	if (memcmp(pe_digest->data, digest, pe_digest->len) != 0)
+		goto out;
+
+	ret = 0;
+out:
+	if (cinfo)
+		SEC_PKCS7DestroyContentInfo(cinfo);
+
+	return ret;
 }
 
 static int
@@ -164,6 +195,23 @@ callback(poptContext con, enum poptCallbackReason reason,
 	}
 }
 
+static int
+delete_files(const char *fpath, const struct stat *sb, int typeflag)
+{
+	if (typeflag == FTW_F)
+		remove(fpath);
+
+	return 0;
+}
+
+static void
+remove_certdir(const char *certdir)
+{
+	ftw(certdir, delete_files, 3);
+
+	remove(certdir);
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -175,6 +223,10 @@ main(int argc, char *argv[])
 	char *dbxfile = NULL;
 	int use_system_dbs = 1;
 
+	char template[] = "/tmp/peverify-XXXXXX";
+	char *certdir = NULL;
+	SECStatus status;
+
 	poptContext optCon;
 	struct poptOption options[] = {
 		{"dbfile", 'D', POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)callback, 0, (void *)ctxp, NULL },
@@ -226,6 +278,14 @@ main(int argc, char *argv[])
 
 	init_cert_db(ctxp, use_system_dbs);
 
+	certdir = mkdtemp(template);
+	status = NSS_InitReadWrite(certdir);
+	if (status != SECSuccess) {
+		fprintf(stderr, "Could not initialize nss: %s\n",
+			PORT_ErrorToString(PORT_GetError()));
+		exit(1);
+	}
+
 	rc = check_signature(ctxp);
 
 	close_input(ctxp);
@@ -233,5 +293,9 @@ main(int argc, char *argv[])
 		printf("peverify: \"%s\" is %s.\n", ctx.infile,
 			rc >= 0 ? "valid" : "invalid");
 	peverify_context_fini(&ctx);
+
+	NSS_Shutdown();
+	remove_certdir(certdir);
+
 	return (rc < 0);
 }
-- 
1.8.4.5


From 35746653e0af5b129dfdfd33e9954ff5c47062aa Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Fri, 27 Dec 2013 17:42:19 +0800
Subject: [PATCH 07/31] Verify the PE image with a certificate

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/certdb.c           | 57 ++++++++++++++++++++++++++++++++++++++++----------
 src/certdb.h           |  1 +
 src/peverify.c         |  5 +++++
 src/peverify_context.c |  4 ++++
 src/peverify_context.h |  7 +++++++
 5 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/src/certdb.c b/src/certdb.c
index 4937c44..922b783 100644
--- a/src/certdb.c
+++ b/src/certdb.c
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <string.h>
 
 #include <nss.h>
 #include <prerror.h>
@@ -32,13 +33,16 @@
 #include "peverify.h"
 
 static int
-add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile, int efivar)
+add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile,
+	    db_f_type type)
 {
 	dblist *db = calloc(1, sizeof (dblist));
 	
 	if (!db)
 		return -1;
 
+	db->type = type;
+
 	db->fd = open(dbfile, O_RDONLY);
 	if (db->fd < 0) {
 		save_errno(free(db));
@@ -61,13 +65,38 @@ add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile, int e
 		return -1;
 	}
 
-	/* skip the first 4 bytes (EFI attributes) in the efi variable */
-	if (efivar == 1) {
-		db->data = db->map + 4;
-		db->datalen = db->size - 4;
-	} else {
+	EFI_SIGNATURE_LIST *certlist;
+	EFI_SIGNATURE_DATA *cert;
+	efi_guid_t efi_x509 = EFI_CERT_X509_GUID;
+
+	switch (type) {
+	case DB_FILE:
 		db->data = db->map;
 		db->datalen = db->size;
+		break;
+	case DB_EFIVAR:
+		/* skip the first 4 bytes (EFI attributes) */
+		db->data = db->map + 4;
+		db->datalen = db->size - 4;
+		break;
+	case DB_CERT:
+		db->datalen = db->size + sizeof(EFI_SIGNATURE_LIST) +
+			      sizeof(efi_guid_t);
+		db->data = calloc(1, db->datalen);
+		if (!db->data)
+			return -1;
+
+		certlist = (EFI_SIGNATURE_LIST *)db->data;
+		memcpy((void *)&certlist->SignatureType, &efi_x509, sizeof(efi_guid_t));
+		certlist->SignatureListSize = db->datalen;
+		certlist->SignatureHeaderSize = 0;
+		certlist->SignatureSize = db->size + sizeof(efi_guid_t);
+
+		cert = (EFI_SIGNATURE_DATA *)(db->data + sizeof(EFI_SIGNATURE_LIST));
+		memcpy((void *)cert->SignatureData, db->map, db->size);
+		break;
+	default:
+		break;
 	}
 
 	dblist **tmp = which == DB ? &ctx->db : &ctx->dbx;
@@ -81,13 +110,19 @@ add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile, int e
 int
 add_cert_db(peverify_context *ctx, const char *filename)
 {
-	return add_db_file(ctx, DB, filename, 0);
+	return add_db_file(ctx, DB, filename, DB_FILE);
 }
 
 int
 add_cert_dbx(peverify_context *ctx, const char *filename)
 {
-	return add_db_file(ctx, DBX, filename, 0);
+	return add_db_file(ctx, DBX, filename, DB_FILE);
+}
+
+int
+add_cert_file(peverify_context *ctx, const char *filename)
+{
+	return add_db_file(ctx, DB, filename, DB_CERT);
 }
 
 #define DB_PATH "/sys/firmware/efi/efivars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f"
@@ -102,14 +137,14 @@ init_cert_db(peverify_context *ctx, int use_system_dbs)
 	if (!use_system_dbs)
 		return;
 
-	rc = add_db_file(ctx, DB, DB_PATH, 1);
+	rc = add_db_file(ctx, DB, DB_PATH, DB_EFIVAR);
 	if (rc < 0 && errno != ENOENT) {
 		fprintf(stderr, "peverify: Could not add key database "
 			"\"%s\": %m\n", DB_PATH);
 		exit(1);
 	}
 
-	rc = add_db_file(ctx, DB, MOK_PATH, 1);
+	rc = add_db_file(ctx, DB, MOK_PATH, DB_EFIVAR);
 	if (rc < 0 && errno != ENOENT) {
 		fprintf(stderr, "peverify: Could not add key database "
 			"\"%s\": %m\n", MOK_PATH);
@@ -121,7 +156,7 @@ init_cert_db(peverify_context *ctx, int use_system_dbs)
 			"No key database available\n");
 	}
 
-	rc = add_db_file(ctx, DBX, DBX_PATH, 1);
+	rc = add_db_file(ctx, DBX, DBX_PATH, DB_EFIVAR);
 	if (rc < 0 && errno != ENOENT) {
 		fprintf(stderr, "peverify: Could not add revocation "
 			"database \"%s\": %m\n", DBX_PATH);
diff --git a/src/certdb.h b/src/certdb.h
index ee70ba6..d64494d 100644
--- a/src/certdb.h
+++ b/src/certdb.h
@@ -48,5 +48,6 @@ extern db_status check_db_cert(db_specifier which, peverify_context *ctx,
 extern void init_cert_db(peverify_context *ctx, int use_system_dbs);
 extern int add_cert_db(peverify_context *ctx, const char *filename);
 extern int add_cert_dbx(peverify_context *ctx, const char *filename);
+extern int add_cert_file(peverify_context *ctx, const char *filename);
 
 #endif /* CERTDB_H */
diff --git a/src/peverify.c b/src/peverify.c
index 47d7ee1..e4c3e13 100644
--- a/src/peverify.c
+++ b/src/peverify.c
@@ -187,6 +187,8 @@ callback(poptContext con, enum poptCallbackReason reason,
 		rc = add_cert_db(ctx, arg);
 	} else if (opt->shortName == 'X') {
 		rc = add_cert_dbx(ctx, arg);
+	} else if (opt->shortName == 'c') {
+		rc = add_cert_file(ctx, arg);
 	}
 	if (rc != 0) {
 		fprintf(stderr, "Could not add %s from file \"%s\": %m\n",
@@ -221,6 +223,7 @@ main(int argc, char *argv[])
 
 	char *dbfile = NULL;
 	char *dbxfile = NULL;
+	char *certfile = NULL;
 	int use_system_dbs = 1;
 
 	char template[] = "/tmp/peverify-XXXXXX";
@@ -242,6 +245,8 @@ main(int argc, char *argv[])
 			"use file for allowed certificate list", "<dbfile>" },
 		{"dbxfile", 'X', POPT_ARG_STRING, &dbxfile, 0,
 			"use file for disallowed certificate list","<dbxfile>"},
+		{"certfile", 'c', POPT_ARG_STRING, &certfile, 0,
+			"the certificate (in DER form) for verification ","<certfile>"},
 		POPT_AUTOALIAS
 		POPT_AUTOHELP
 		POPT_TABLEEND
diff --git a/src/peverify_context.c b/src/peverify_context.c
index 44fc442..d3aa53e 100644
--- a/src/peverify_context.c
+++ b/src/peverify_context.c
@@ -82,6 +82,8 @@ peverify_context_fini(peverify_context *ctx)
 	while (ctx->db) {
 		dblist *db = ctx->db;
 
+		if (db->type == DB_CERT)
+			free(db->data);
 		munmap(db->map, db->size);
 		close(db->fd);
 		ctx->db = db->next;
@@ -90,6 +92,8 @@ peverify_context_fini(peverify_context *ctx)
 	while (ctx->dbx) {
 		dblist *db = ctx->dbx;
 
+		if (db->type == DB_CERT)
+			free(db->data);
 		munmap(db->map, db->size);
 		close(db->fd);
 		ctx->dbx = db->next;
diff --git a/src/peverify_context.h b/src/peverify_context.h
index 37f415b..7e26d06 100644
--- a/src/peverify_context.h
+++ b/src/peverify_context.h
@@ -26,7 +26,14 @@ enum {
 	PEVERIFY_C_ALLOCATED = 1,
 };
 
+typedef enum {
+	DB_FILE,
+	DB_EFIVAR,
+	DB_CERT,
+} db_f_type;
+
 struct dblist {
+	db_f_type type;
 	int fd;
 	struct dblist *next;
 	size_t size;
-- 
1.8.4.5


From 23295225a732058edabc58ede7e863d347d2ac47 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Fri, 27 Dec 2013 17:43:32 +0800
Subject: [PATCH 08/31] It's peverify, not pesign :)

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/peverify.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/peverify.c b/src/peverify.c
index e4c3e13..ebd7ee7 100644
--- a/src/peverify.c
+++ b/src/peverify.c
@@ -40,21 +40,21 @@ static void
 open_input(peverify_context *ctx)
 {
 	if (!ctx->infile) {
-		fprintf(stderr, "pesign: No input file specified.\n");
+		fprintf(stderr, "peverify: No input file specified.\n");
 		exit(1);
 	}
 
 	ctx->infd = open(ctx->infile, O_RDONLY|O_CLOEXEC);
 
 	if (ctx->infd < 0) {
-		fprintf(stderr, "pesign: Error opening input: %m\n");
+		fprintf(stderr, "peverify: Error opening input: %m\n");
 		exit(1);
 	}
 
 	Pe_Cmd cmd = ctx->infd == STDIN_FILENO ? PE_C_READ : PE_C_READ_MMAP;
 	ctx->inpe = pe_begin(ctx->infd, cmd, NULL);
 	if (!ctx->inpe) {
-		fprintf(stderr, "pesign: could not load input file: %s\n",
+		fprintf(stderr, "peverify: could not load input file: %s\n",
 			pe_errmsg(pe_errno()));
 		exit(1);
 	}
@@ -63,7 +63,7 @@ open_input(peverify_context *ctx)
 					&ctx->cms_ctx->num_signatures,
 					ctx->inpe);
 	if (rc < 0) {
-		fprintf(stderr, "pesign: could not parse signature list in "
+		fprintf(stderr, "peverify: could not parse signature list in "
 			"EFI binary\n");
 		exit(1);
 	}
-- 
1.8.4.5


From b431e22f0e02e282ece114e1829575e7eedfcfb5 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 6 Jan 2014 14:11:34 -0500
Subject: [PATCH 09/31] Rename peverify to pesigcheck

Signed-off-by: Peter Jones <pjones@redhat.com>
---
 src/.gitignore           |   2 +-
 src/Makefile             |  16 +--
 src/certdb.c             |  32 ++---
 src/certdb.h             |  12 +-
 src/pesigcheck.1         |  25 ++++
 src/pesigcheck.c         | 306 +++++++++++++++++++++++++++++++++++++++++++++++
 src/pesigcheck.h         |  39 ++++++
 src/pesigcheck_context.c | 122 +++++++++++++++++++
 src/pesigcheck_context.h |  78 ++++++++++++
 src/peverify.1           |  25 ----
 src/peverify.c           | 306 -----------------------------------------------
 src/peverify.h           |  39 ------
 src/peverify_context.c   | 122 -------------------
 src/peverify_context.h   |  78 ------------
 14 files changed, 601 insertions(+), 601 deletions(-)
 create mode 100644 src/pesigcheck.1
 create mode 100644 src/pesigcheck.c
 create mode 100644 src/pesigcheck.h
 create mode 100644 src/pesigcheck_context.c
 create mode 100644 src/pesigcheck_context.h
 delete mode 100644 src/peverify.1
 delete mode 100644 src/peverify.c
 delete mode 100644 src/peverify.h
 delete mode 100644 src/peverify_context.c
 delete mode 100644 src/peverify_context.h

diff --git a/src/.gitignore b/src/.gitignore
index fec12ae..7215f64 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -12,4 +12,4 @@ ms
 client
 efikeygen
 efisiglist
-peverify
+pesigcheck
diff --git a/src/Makefile b/src/Makefile
index f478aa6..0aa13a1 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -10,7 +10,7 @@ LDFLAGS =
 CCLDFLAGS = -L../libdpe $(foreach pklib,$(PKLIBS), $(shell pkg-config --libs-only-L $(pklib)))
 CFLAGS += -I../include/ $(foreach pklib,$(PKLIBS), $(shell pkg-config --cflags $(pklib))) -Werror
 
-TARGETS = pesign authvar client efisiglist efikeygen peverify
+TARGETS = pesign authvar client efisiglist efikeygen pesigcheck
 
 all : $(TARGETS)
 
@@ -29,10 +29,10 @@ pesign_OBJECTS = $(foreach source,$(pesign_SOURCES),$(patsubst %.c,%,$(source)).
 pesign_DEPS = $(foreach source,$(pesign_SOURCES),.$(patsubst %.c,%,$(source)).P)
 pesign : $(pesign_OBJECTS) $(STATIC_LIBS)
 
-peverify_SOURCES = peverify.c peverify_context.c certdb.c
-peverify_OBJECTS = $(foreach source,$(peverify_SOURCES),$(patsubst %.c,%,$(source)).o) generic.a
-peverify_DEPS = $(foreach source,$(peverify_SOURCES),.$(patsubst %.c,%,$(source)).P)
-peverify : $(peverify_OBJECTS) $(STATIC_LIBS)
+pesigcheck_SOURCES = pesigcheck.c pesigcheck_context.c certdb.c
+pesigcheck_OBJECTS = $(foreach source,$(pesigcheck_SOURCES),$(patsubst %.c,%,$(source)).o) generic.a
+pesigcheck_DEPS = $(foreach source,$(pesigcheck_SOURCES),.$(patsubst %.c,%,$(source)).P)
+pesigcheck : $(pesigcheck_OBJECTS) $(STATIC_LIBS)
 
 client_SOURCES = pesign_context.c actions.c client.c
 client_OBJECTS = $(foreach source,$(client_SOURCES),$(patsubst %.c,%,$(source)).o) generic.a
@@ -55,7 +55,7 @@ fuzzsocket_DEPS = $(foreach source,$(fuzzsocket_SOURCES),.$(patsubst %.c,%,$(sou
 fuzzsocket : $(fuzzsocket_OBJECTS) -lrt
 
 DEPS = $(generic_DEPS) $(authvar_DEPS) $(pesign_DEPS) $(client_DEPS) \
-	$(peverify_DEPS) $(efisiglist_DEPS) $(efikeygen_DEPS)
+	$(pesigcheck_DEPS) $(efisiglist_DEPS) $(efikeygen_DEPS)
 
 deps : $(DEPS)
 
@@ -84,14 +84,14 @@ install :
 	$(INSTALL) -m 755 pesign $(INSTALLROOT)$(PREFIX)/bin/
 	$(INSTALL) -m 755 client $(INSTALLROOT)$(PREFIX)/bin/pesign-client
 	$(INSTALL) -m 755 efikeygen $(INSTALLROOT)$(PREFIX)/bin/
-	#$(INSTALL) -m 755 peverify $(INSTALLROOT)$(PREFIX)/bin/
+	#$(INSTALL) -m 755 pesigcheck $(INSTALLROOT)$(PREFIX)/bin/
 	$(INSTALL) -d -m 755 $(INSTALLROOT)/etc/popt.d/
 	$(INSTALL) -m 644 pesign.popt $(INSTALLROOT)/etc/popt.d/
 	$(INSTALL) -d -m 755 $(INSTALLROOT)/usr/share/man/man1/
 	$(INSTALL) -m 644 pesign.1 $(INSTALLROOT)/usr/share/man/man1/
 	$(INSTALL) -m 644 pesign-client.1 $(INSTALLROOT)/usr/share/man/man1/
 	$(INSTALL) -m 644 efikeygen.1 $(INSTALLROOT)/usr/share/man/man1/
-	#$(INSTALL) -m 644 peverify.1 $(INSTALLROOT)/usr/share/man/man1/
+	#$(INSTALL) -m 644 pesigcheck.1 $(INSTALLROOT)/usr/share/man/man1/
 	$(INSTALL) -d -m 755 $(INSTALLROOT)/etc/rpm/
 	$(INSTALL) -m 644 macros.pesign $(INSTALLROOT)/etc/rpm/
 
diff --git a/src/certdb.c b/src/certdb.c
index 922b783..24c319b 100644
--- a/src/certdb.c
+++ b/src/certdb.c
@@ -30,10 +30,10 @@
 #include <pkcs7t.h>
 #include <pk11pub.h>
 
-#include "peverify.h"
+#include "pesigcheck.h"
 
 static int
-add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile,
+add_db_file(pesigcheck_context *ctx, db_specifier which, const char *dbfile,
 	    db_f_type type)
 {
 	dblist *db = calloc(1, sizeof (dblist));
@@ -108,19 +108,19 @@ add_db_file(peverify_context *ctx, db_specifier which, const char *dbfile,
 }
 
 int
-add_cert_db(peverify_context *ctx, const char *filename)
+add_cert_db(pesigcheck_context *ctx, const char *filename)
 {
 	return add_db_file(ctx, DB, filename, DB_FILE);
 }
 
 int
-add_cert_dbx(peverify_context *ctx, const char *filename)
+add_cert_dbx(pesigcheck_context *ctx, const char *filename)
 {
 	return add_db_file(ctx, DBX, filename, DB_FILE);
 }
 
 int
-add_cert_file(peverify_context *ctx, const char *filename)
+add_cert_file(pesigcheck_context *ctx, const char *filename)
 {
 	return add_db_file(ctx, DB, filename, DB_CERT);
 }
@@ -130,7 +130,7 @@ add_cert_file(peverify_context *ctx, const char *filename)
 #define DBX_PATH "/sys/firmware/efi/efivars/dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f"
 
 void
-init_cert_db(peverify_context *ctx, int use_system_dbs)
+init_cert_db(pesigcheck_context *ctx, int use_system_dbs)
 {
 	int rc = 0;
 
@@ -139,36 +139,36 @@ init_cert_db(peverify_context *ctx, int use_system_dbs)
 
 	rc = add_db_file(ctx, DB, DB_PATH, DB_EFIVAR);
 	if (rc < 0 && errno != ENOENT) {
-		fprintf(stderr, "peverify: Could not add key database "
+		fprintf(stderr, "pesigcheck: Could not add key database "
 			"\"%s\": %m\n", DB_PATH);
 		exit(1);
 	}
 
 	rc = add_db_file(ctx, DB, MOK_PATH, DB_EFIVAR);
 	if (rc < 0 && errno != ENOENT) {
-		fprintf(stderr, "peverify: Could not add key database "
+		fprintf(stderr, "pesigcheck: Could not add key database "
 			"\"%s\": %m\n", MOK_PATH);
 		exit(1);
 	}
 
 	if (ctx->db == NULL) {
-		fprintf(stderr, "peverify: warning: "
+		fprintf(stderr, "pesigcheck: warning: "
 			"No key database available\n");
 	}
 
 	rc = add_db_file(ctx, DBX, DBX_PATH, DB_EFIVAR);
 	if (rc < 0 && errno != ENOENT) {
-		fprintf(stderr, "peverify: Could not add revocation "
+		fprintf(stderr, "pesigcheck: Could not add revocation "
 			"database \"%s\": %m\n", DBX_PATH);
 		exit(1);
 	}
 }
 
-typedef db_status (*checkfn)(peverify_context *ctx, SECItem *sig,
+typedef db_status (*checkfn)(pesigcheck_context *ctx, SECItem *sig,
 			     efi_guid_t *sigtype, SECItem *pkcs7sig);
 
 static db_status
-check_db(db_specifier which, peverify_context *ctx, checkfn check,
+check_db(db_specifier which, pesigcheck_context *ctx, checkfn check,
 	 void *data, ssize_t datalen)
 {
 	SECItem pkcs7sig, sig;
@@ -217,7 +217,7 @@ check_db(db_specifier which, peverify_context *ctx, checkfn check,
 }
 
 static db_status
-check_hash(peverify_context *ctx, SECItem *sig, efi_guid_t *sigtype,
+check_hash(pesigcheck_context *ctx, SECItem *sig, efi_guid_t *sigtype,
 	   SECItem *pkcs7sig)
 {
 	efi_guid_t efi_sha256 = EFI_CERT_SHA256_GUID;
@@ -238,13 +238,13 @@ check_hash(peverify_context *ctx, SECItem *sig, efi_guid_t *sigtype,
 }
 
 db_status
-check_db_hash(db_specifier which, peverify_context *ctx)
+check_db_hash(db_specifier which, pesigcheck_context *ctx)
 {
 	return check_db(which, ctx, check_hash, NULL, 0);
 }
 
 static db_status
-check_cert(peverify_context *ctx, SECItem *sig, efi_guid_t *sigtype,
+check_cert(pesigcheck_context *ctx, SECItem *sig, efi_guid_t *sigtype,
 	   SECItem *pkcs7sig)
 {
 	SEC_PKCS7ContentInfo *cinfo = NULL;
@@ -335,7 +335,7 @@ out:
 }
 
 db_status
-check_db_cert(db_specifier which, peverify_context *ctx, void *data, ssize_t datalen)
+check_db_cert(db_specifier which, pesigcheck_context *ctx, void *data, ssize_t datalen)
 {
 	return check_db(which, ctx, check_cert, data, datalen);
 }
diff --git a/src/certdb.h b/src/certdb.h
index d64494d..ccf3c87 100644
--- a/src/certdb.h
+++ b/src/certdb.h
@@ -41,13 +41,13 @@ typedef struct {
 	uint32_t	SignatureSize;
 } EFI_SIGNATURE_LIST;
 
-extern db_status check_db_hash(db_specifier which, peverify_context *ctx);
-extern db_status check_db_cert(db_specifier which, peverify_context *ctx,
+extern db_status check_db_hash(db_specifier which, pesigcheck_context *ctx);
+extern db_status check_db_cert(db_specifier which, pesigcheck_context *ctx,
 				void *data, ssize_t datalen);
 
-extern void init_cert_db(peverify_context *ctx, int use_system_dbs);
-extern int add_cert_db(peverify_context *ctx, const char *filename);
-extern int add_cert_dbx(peverify_context *ctx, const char *filename);
-extern int add_cert_file(peverify_context *ctx, const char *filename);
+extern void init_cert_db(pesigcheck_context *ctx, int use_system_dbs);
+extern int add_cert_db(pesigcheck_context *ctx, const char *filename);
+extern int add_cert_dbx(pesigcheck_context *ctx, const char *filename);
+extern int add_cert_file(pesigcheck_context *ctx, const char *filename);
 
 #endif /* CERTDB_H */
diff --git a/src/pesigcheck.1 b/src/pesigcheck.1
new file mode 100644
index 0000000..55101ab
--- /dev/null
+++ b/src/pesigcheck.1
@@ -0,0 +1,25 @@
+.TH pesigcheck 1 "Mon Sep 10 2012"
+.SH NAME
+pesign \- command line tool for verifying UEFI applications
+
+.SH SYNOPSIS
+\fBpesign\fR [--in=\fIinfile\fR | -i \fIinfile\fR] [--quiet | -q ]
+       [--db=\fIdbfile\fR | -D \fIdbfile\fR ]
+       [--dbx=\fIdbxfile\fR | -X \fIdbxfile\fR ]
+
+.SH DESCRIPTION
+\fBpesigcheck\fR is a command line tool for verifying the signature of UEFI
+applications.
+
+.SH OPTIONS
+.TP
+\fB-\-in\fR=\fIinfile\fR
+Specify input binary.
+
+.SH "SEE ALSO"
+.BR pesigcheck (1)
+
+.SH AUTHORS
+.nf
+Peter Jones
+.fi
diff --git a/src/pesigcheck.c b/src/pesigcheck.c
new file mode 100644
index 0000000..7cd98c9
--- /dev/null
+++ b/src/pesigcheck.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2011-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones@redhat.com>
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <ftw.h>
+#include <nss.h>
+
+#include <popt.h>
+
+#include <prerror.h>
+#include <cert.h>
+#include <pkcs7t.h>
+#include <pk11pub.h>
+
+#include "pesigcheck.h"
+
+static void
+open_input(pesigcheck_context *ctx)
+{
+	if (!ctx->infile) {
+		fprintf(stderr, "pesigcheck: No input file specified.\n");
+		exit(1);
+	}
+
+	ctx->infd = open(ctx->infile, O_RDONLY|O_CLOEXEC);
+
+	if (ctx->infd < 0) {
+		fprintf(stderr, "pesigcheck: Error opening input: %m\n");
+		exit(1);
+	}
+
+	Pe_Cmd cmd = ctx->infd == STDIN_FILENO ? PE_C_READ : PE_C_READ_MMAP;
+	ctx->inpe = pe_begin(ctx->infd, cmd, NULL);
+	if (!ctx->inpe) {
+		fprintf(stderr, "pesigcheck: could not load input file: %s\n",
+			pe_errmsg(pe_errno()));
+		exit(1);
+	}
+
+	int rc = parse_signatures(&ctx->cms_ctx->signatures,
+					&ctx->cms_ctx->num_signatures,
+					ctx->inpe);
+	if (rc < 0) {
+		fprintf(stderr, "pesigcheck: could not parse signature list in "
+			"EFI binary\n");
+		exit(1);
+	}
+}
+
+static void
+close_input(pesigcheck_context *ctx)
+{
+	pe_end(ctx->inpe);
+	ctx->inpe = NULL;
+
+	close(ctx->infd);
+	ctx->infd = -1;
+}
+
+static void
+check_inputs(pesigcheck_context *ctx)
+{
+	if (!ctx->infile) {
+		fprintf(stderr, "pesign: No input file specified.\n");
+		exit(1);
+	}
+}
+
+static int
+cert_matches_digest(pesigcheck_context *ctx, void *data, ssize_t datalen)
+{
+	SECItem sig, *pe_digest, *content;
+	uint8_t *digest;
+	SEC_PKCS7ContentInfo *cinfo = NULL;
+	int ret = -1;
+
+	sig.data = data;
+	sig.len = datalen;
+	sig.type = siBuffer;
+
+	cinfo = SEC_PKCS7DecodeItem(&sig, NULL, NULL, NULL, NULL, NULL,
+				    NULL, NULL);
+
+	if (!SEC_PKCS7ContentIsSigned(cinfo))
+		goto out;
+
+	/* TODO Find out the digest type in spc_content */
+	pe_digest = ctx->cms_ctx->digests[0].pe_digest;
+	content = cinfo->content.signedData->contentInfo.content.data;
+	digest = content->data + content->len - pe_digest->len;
+	if (memcmp(pe_digest->data, digest, pe_digest->len) != 0)
+		goto out;
+
+	ret = 0;
+out:
+	if (cinfo)
+		SEC_PKCS7DestroyContentInfo(cinfo);
+
+	return ret;
+}
+
+static int
+check_signature(pesigcheck_context *ctx)
+{
+	int has_valid_cert = 0;
+	int has_invalid_cert = 0;
+	int rc = 0;
+
+	cert_iter iter;
+
+	generate_digest(ctx->cms_ctx, ctx->inpe, 1);
+	
+	if (check_db_hash(DBX, ctx) == FOUND)
+		return -1;
+
+	if (check_db_hash(DB, ctx) == FOUND)
+		has_valid_cert = 1;
+
+	rc = cert_iter_init(&iter, ctx->inpe);
+	if (rc < 0)
+		goto err;
+
+	void *data;
+	ssize_t datalen;
+
+	while (1) {
+		rc = next_cert(&iter, &data, &datalen);
+		if (rc <= 0)
+			break;
+
+		if (cert_matches_digest(ctx, data, datalen) < 0) {
+			has_invalid_cert = 1;
+			break;
+		}
+
+		if (check_db_cert(DBX, ctx, data, datalen) == FOUND) {
+			has_invalid_cert = 1;
+			break;
+		}
+
+		if (check_db_cert(DB, ctx, data, datalen) == FOUND)
+			has_valid_cert = 1;
+	}
+
+err:
+	if (has_invalid_cert)
+		return -1;
+
+	if (has_valid_cert)
+		return 0;
+
+	return -1;
+}
+
+void
+callback(poptContext con, enum poptCallbackReason reason,
+	 const struct poptOption *opt,
+	 const char *arg, const void *data)
+{
+	pesigcheck_context *ctx = (pesigcheck_context *)data;
+	int rc = 0;
+	if (!opt)
+		return;
+	if (opt->shortName == 'D') {
+		rc = add_cert_db(ctx, arg);
+	} else if (opt->shortName == 'X') {
+		rc = add_cert_dbx(ctx, arg);
+	} else if (opt->shortName == 'c') {
+		rc = add_cert_file(ctx, arg);
+	}
+	if (rc != 0) {
+		fprintf(stderr, "Could not add %s from file \"%s\": %m\n",
+			opt->shortName == 'D' ? "DB" : "DBX", arg);
+		exit(1);
+	}
+}
+
+static int
+delete_files(const char *fpath, const struct stat *sb, int typeflag)
+{
+	if (typeflag == FTW_F)
+		remove(fpath);
+
+	return 0;
+}
+
+static void
+remove_certdir(const char *certdir)
+{
+	ftw(certdir, delete_files, 3);
+
+	remove(certdir);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int rc;
+
+	pesigcheck_context ctx, *ctxp = &ctx;
+
+	char *dbfile = NULL;
+	char *dbxfile = NULL;
+	char *certfile = NULL;
+	int use_system_dbs = 1;
+
+	char template[] = "/tmp/pesigcheck-XXXXXX";
+	char *certdir = NULL;
+	SECStatus status;
+
+	poptContext optCon;
+	struct poptOption options[] = {
+		{"dbfile", 'D', POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)callback, 0, (void *)ctxp, NULL },
+		{NULL, '\0', POPT_ARG_INTL_DOMAIN, "pesign" },
+		{"in", 'i', POPT_ARG_STRING, &ctx.infile, 0,
+			"specify input file", "<infile>"},
+		{"quiet", 'q', POPT_BIT_SET, &ctx.quiet, 1,
+			"return only; no text output.", NULL },
+		{"no-system-db", 'n', POPT_ARG_INT, &use_system_dbs, 0,
+			"inhibit the use of DB and DBX from the running system",
+			NULL },
+		{"dbfile", 'D', POPT_ARG_STRING, &dbfile, 0,
+			"use file for allowed certificate list", "<dbfile>" },
+		{"dbxfile", 'X', POPT_ARG_STRING, &dbxfile, 0,
+			"use file for disallowed certificate list","<dbxfile>"},
+		{"certfile", 'c', POPT_ARG_STRING, &certfile, 0,
+			"the certificate (in DER form) for verification ","<certfile>"},
+		POPT_AUTOALIAS
+		POPT_AUTOHELP
+		POPT_TABLEEND
+	};
+
+	rc = pesigcheck_context_init(ctxp);
+	if (rc < 0) {
+		fprintf(stderr, "pesigcheck: Could not initialize context: %m\n");
+		exit(1);
+	}
+
+	optCon = poptGetContext("pesigcheck", argc, (const char **)argv,
+				options,0);
+
+	while ((rc = poptGetNextOpt(optCon)) > 0)
+		;
+
+	if (rc < -1) {
+		fprintf(stderr, "pesigcheck: Invalid argument: %s: %s\n",
+			poptBadOption(optCon, 0), poptStrerror(rc));
+		exit(1);
+	}
+
+	if (poptPeekArg(optCon)) {
+		fprintf(stderr, "pesigcheck: Invalid Argument: \"%s\"\n",
+				poptPeekArg(optCon));
+		exit(1);
+	}
+
+	poptFreeContext(optCon);
+
+	check_inputs(ctxp);
+	open_input(ctxp);
+
+	init_cert_db(ctxp, use_system_dbs);
+
+	certdir = mkdtemp(template);
+	status = NSS_InitReadWrite(certdir);
+	if (status != SECSuccess) {
+		fprintf(stderr, "Could not initialize nss: %s\n",
+			PORT_ErrorToString(PORT_GetError()));
+		exit(1);
+	}
+
+	rc = check_signature(ctxp);
+
+	close_input(ctxp);
+	if (!ctx.quiet)
+		printf("pesigcheck: \"%s\" is %s.\n", ctx.infile,
+			rc >= 0 ? "valid" : "invalid");
+	pesigcheck_context_fini(&ctx);
+
+	NSS_Shutdown();
+	remove_certdir(certdir);
+
+	return (rc < 0);
+}
diff --git a/src/pesigcheck.h b/src/pesigcheck.h
new file mode 100644
index 0000000..ee0b63c
--- /dev/null
+++ b/src/pesigcheck.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones@redhat.com>
+ */
+#ifndef PESIGN_H
+#define PESIGN_H 1
+
+#include <libdpe/libdpe.h>
+#include <libdpe/pe.h>
+
+#include "efitypes.h"
+#include "cms_common.h"
+#include "pesigcheck_context.h"
+#include "certdb.h"
+
+#include "util.h"
+#include "endian.h"
+#include "oid.h"
+#include "wincert.h"
+#include "content_info.h"
+#include "signer_info.h"
+#include "signed_data.h"
+#include "password.h"
+
+#endif /* PESIGN_H */
diff --git a/src/pesigcheck_context.c b/src/pesigcheck_context.c
new file mode 100644
index 0000000..b934cbe
--- /dev/null
+++ b/src/pesigcheck_context.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones@redhat.com>
+ */
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "pesigcheck.h"
+
+#include <nss.h>
+#include <secitem.h>
+
+int
+pesigcheck_context_new(pesigcheck_context **ctx)
+{
+	pesigcheck_context *context = NULL;
+	int rc = 0;
+
+	if (ctx == NULL)
+		return -1;
+
+	context = malloc(sizeof (*context));
+	if (!context)
+		return -1;
+
+	pesigcheck_context_init(context);
+	context->flags |= pesigcheck_C_ALLOCATED;
+
+	*ctx = context;
+	return rc;
+}
+
+int
+pesigcheck_context_init(pesigcheck_context *ctx)
+{
+	if (!ctx)
+		return -1;
+	memset(ctx, '\0', sizeof (*ctx));
+
+	ctx->infd = -1;
+
+	int rc = cms_context_alloc(&ctx->cms_ctx);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+void
+pesigcheck_context_fini(pesigcheck_context *ctx)
+{
+	if (!ctx)
+		return;
+
+	cms_context_fini(ctx->cms_ctx);
+
+	xfree(ctx->infile);
+
+	if (ctx->inpe) {
+		pe_end(ctx->inpe);
+		ctx->inpe = NULL;
+	}
+
+	if (!(ctx->flags & pesigcheck_C_ALLOCATED))
+		pesigcheck_context_init(ctx);
+
+	while (ctx->db) {
+		dblist *db = ctx->db;
+
+		if (db->type == DB_CERT)
+			free(db->data);
+		munmap(db->map, db->size);
+		close(db->fd);
+		ctx->db = db->next;
+		free(db);
+	}
+	while (ctx->dbx) {
+		dblist *db = ctx->dbx;
+
+		if (db->type == DB_CERT)
+			free(db->data);
+		munmap(db->map, db->size);
+		close(db->fd);
+		ctx->dbx = db->next;
+		free(db);
+	}
+	while (ctx->hashes) {
+		hashlist *hashes = ctx->hashes;
+		free(hashes->data);
+		ctx->hashes = hashes->next;
+		free(hashes);
+	}
+}
+
+void
+pesigcheck_context_free_private(pesigcheck_context **ctx_ptr)
+{
+	pesigcheck_context *ctx;
+	if (!ctx_ptr || !*ctx_ptr)
+		return;
+
+	ctx = *ctx_ptr;
+	pesigcheck_context_fini(ctx);
+
+	if (ctx->flags & pesigcheck_C_ALLOCATED)
+		xfree(*ctx_ptr);
+}
diff --git a/src/pesigcheck_context.h b/src/pesigcheck_context.h
new file mode 100644
index 0000000..1b916e3
--- /dev/null
+++ b/src/pesigcheck_context.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones@redhat.com>
+ */
+#ifndef pesigcheck_CONTEXT_H
+#define pesigcheck_CONTEXT_H 1
+
+#include <cert.h>
+#include <secpkcs7.h>
+
+enum {
+	pesigcheck_C_ALLOCATED = 1,
+};
+
+typedef enum {
+	DB_FILE,
+	DB_EFIVAR,
+	DB_CERT,
+} db_f_type;
+
+struct dblist {
+	db_f_type type;
+	int fd;
+	struct dblist *next;
+	size_t size;
+	void *map;
+	size_t datalen;
+	void *data;
+};
+
+typedef struct dblist dblist;
+
+struct hashlist {
+	efi_guid_t *hash_type;
+	void *data;
+	size_t datalen;
+	struct hashlist *next;
+};
+typedef struct hashlist hashlist;
+
+typedef struct pesigcheck_context {
+	int flags;
+
+	char *infile;
+	int infd;
+	Pe *inpe;
+
+	int quiet;
+
+	hashlist *hashes;
+
+	dblist *db;
+	dblist *dbx;
+
+	cms_context *cms_ctx;
+} pesigcheck_context;
+
+extern int pesigcheck_context_new(pesigcheck_context **ctx);
+extern void pesigcheck_context_free_private(pesigcheck_context **ctx_ptr);
+extern int pesigcheck_context_init(pesigcheck_context *ctx);
+extern void pesigcheck_context_fini(pesigcheck_context *ctx);
+#define pesigcheck_context_free(ctx) pesigcheck_context_free_private(&(ctx))
+
+#endif /* pesigcheck_CONTEXT_H */
diff --git a/src/peverify.1 b/src/peverify.1
deleted file mode 100644
index ce8da2a..0000000
--- a/src/peverify.1
+++ /dev/null
@@ -1,25 +0,0 @@
-.TH PEVERIFY 1 "Mon Sep 10 2012"
-.SH NAME
-pesign \- command line tool for verifying UEFI applications
-
-.SH SYNOPSIS
-\fBpesign\fR [--in=\fIinfile\fR | -i \fIinfile\fR] [--quiet | -q ]
-       [--db=\fIdbfile\fR | -D \fIdbfile\fR ]
-       [--dbx=\fIdbxfile\fR | -X \fIdbxfile\fR ]
-
-.SH DESCRIPTION
-\fBpeverify\fR is a command line tool for verifying the signature of UEFI
-applications.
-
-.SH OPTIONS
-.TP
-\fB-\-in\fR=\fIinfile\fR
-Specify input binary.
-
-.SH "SEE ALSO"
-.BR peverify (1)
-
-.SH AUTHORS
-.nf
-Peter Jones
-.fi
diff --git a/src/peverify.c b/src/peverify.c
deleted file mode 100644
index ebd7ee7..0000000
--- a/src/peverify.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright 2011-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Author(s): Peter Jones <pjones@redhat.com>
- */
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <ftw.h>
-#include <nss.h>
-
-#include <popt.h>
-
-#include <prerror.h>
-#include <cert.h>
-#include <pkcs7t.h>
-#include <pk11pub.h>
-
-#include "peverify.h"
-
-static void
-open_input(peverify_context *ctx)
-{
-	if (!ctx->infile) {
-		fprintf(stderr, "peverify: No input file specified.\n");
-		exit(1);
-	}
-
-	ctx->infd = open(ctx->infile, O_RDONLY|O_CLOEXEC);
-
-	if (ctx->infd < 0) {
-		fprintf(stderr, "peverify: Error opening input: %m\n");
-		exit(1);
-	}
-
-	Pe_Cmd cmd = ctx->infd == STDIN_FILENO ? PE_C_READ : PE_C_READ_MMAP;
-	ctx->inpe = pe_begin(ctx->infd, cmd, NULL);
-	if (!ctx->inpe) {
-		fprintf(stderr, "peverify: could not load input file: %s\n",
-			pe_errmsg(pe_errno()));
-		exit(1);
-	}
-
-	int rc = parse_signatures(&ctx->cms_ctx->signatures,
-					&ctx->cms_ctx->num_signatures,
-					ctx->inpe);
-	if (rc < 0) {
-		fprintf(stderr, "peverify: could not parse signature list in "
-			"EFI binary\n");
-		exit(1);
-	}
-}
-
-static void
-close_input(peverify_context *ctx)
-{
-	pe_end(ctx->inpe);
-	ctx->inpe = NULL;
-
-	close(ctx->infd);
-	ctx->infd = -1;
-}
-
-static void
-check_inputs(peverify_context *ctx)
-{
-	if (!ctx->infile) {
-		fprintf(stderr, "pesign: No input file specified.\n");
-		exit(1);
-	}
-}
-
-static int
-cert_matches_digest(peverify_context *ctx, void *data, ssize_t datalen)
-{
-	SECItem sig, *pe_digest, *content;
-	uint8_t *digest;
-	SEC_PKCS7ContentInfo *cinfo = NULL;
-	int ret = -1;
-
-	sig.data = data;
-	sig.len = datalen;
-	sig.type = siBuffer;
-
-	cinfo = SEC_PKCS7DecodeItem(&sig, NULL, NULL, NULL, NULL, NULL,
-				    NULL, NULL);
-
-	if (!SEC_PKCS7ContentIsSigned(cinfo))
-		goto out;
-
-	/* TODO Find out the digest type in spc_content */
-	pe_digest = ctx->cms_ctx->digests[0].pe_digest;
-	content = cinfo->content.signedData->contentInfo.content.data;
-	digest = content->data + content->len - pe_digest->len;
-	if (memcmp(pe_digest->data, digest, pe_digest->len) != 0)
-		goto out;
-
-	ret = 0;
-out:
-	if (cinfo)
-		SEC_PKCS7DestroyContentInfo(cinfo);
-
-	return ret;
-}
-
-static int
-check_signature(peverify_context *ctx)
-{
-	int has_valid_cert = 0;
-	int has_invalid_cert = 0;
-	int rc = 0;
-
-	cert_iter iter;
-
-	generate_digest(ctx->cms_ctx, ctx->inpe, 1);
-	
-	if (check_db_hash(DBX, ctx) == FOUND)
-		return -1;
-
-	if (check_db_hash(DB, ctx) == FOUND)
-		has_valid_cert = 1;
-
-	rc = cert_iter_init(&iter, ctx->inpe);
-	if (rc < 0)
-		goto err;
-
-	void *data;
-	ssize_t datalen;
-
-	while (1) {
-		rc = next_cert(&iter, &data, &datalen);
-		if (rc <= 0)
-			break;
-
-		if (cert_matches_digest(ctx, data, datalen) < 0) {
-			has_invalid_cert = 1;
-			break;
-		}
-
-		if (check_db_cert(DBX, ctx, data, datalen) == FOUND) {
-			has_invalid_cert = 1;
-			break;
-		}
-
-		if (check_db_cert(DB, ctx, data, datalen) == FOUND)
-			has_valid_cert = 1;
-	}
-
-err:
-	if (has_invalid_cert)
-		return -1;
-
-	if (has_valid_cert)
-		return 0;
-
-	return -1;
-}
-
-void
-callback(poptContext con, enum poptCallbackReason reason,
-	 const struct poptOption *opt,
-	 const char *arg, const void *data)
-{
-	peverify_context *ctx = (peverify_context *)data;
-	int rc = 0;
-	if (!opt)
-		return;
-	if (opt->shortName == 'D') {
-		rc = add_cert_db(ctx, arg);
-	} else if (opt->shortName == 'X') {
-		rc = add_cert_dbx(ctx, arg);
-	} else if (opt->shortName == 'c') {
-		rc = add_cert_file(ctx, arg);
-	}
-	if (rc != 0) {
-		fprintf(stderr, "Could not add %s from file \"%s\": %m\n",
-			opt->shortName == 'D' ? "DB" : "DBX", arg);
-		exit(1);
-	}
-}
-
-static int
-delete_files(const char *fpath, const struct stat *sb, int typeflag)
-{
-	if (typeflag == FTW_F)
-		remove(fpath);
-
-	return 0;
-}
-
-static void
-remove_certdir(const char *certdir)
-{
-	ftw(certdir, delete_files, 3);
-
-	remove(certdir);
-}
-
-int
-main(int argc, char *argv[])
-{
-	int rc;
-
-	peverify_context ctx, *ctxp = &ctx;
-
-	char *dbfile = NULL;
-	char *dbxfile = NULL;
-	char *certfile = NULL;
-	int use_system_dbs = 1;
-
-	char template[] = "/tmp/peverify-XXXXXX";
-	char *certdir = NULL;
-	SECStatus status;
-
-	poptContext optCon;
-	struct poptOption options[] = {
-		{"dbfile", 'D', POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)callback, 0, (void *)ctxp, NULL },
-		{NULL, '\0', POPT_ARG_INTL_DOMAIN, "pesign" },
-		{"in", 'i', POPT_ARG_STRING, &ctx.infile, 0,
-			"specify input file", "<infile>"},
-		{"quiet", 'q', POPT_BIT_SET, &ctx.quiet, 1,
-			"return only; no text output.", NULL },
-		{"no-system-db", 'n', POPT_ARG_INT, &use_system_dbs, 0,
-			"inhibit the use of DB and DBX from the running system",
-			NULL },
-		{"dbfile", 'D', POPT_ARG_STRING, &dbfile, 0,
-			"use file for allowed certificate list", "<dbfile>" },
-		{"dbxfile", 'X', POPT_ARG_STRING, &dbxfile, 0,
-			"use file for disallowed certificate list","<dbxfile>"},
-		{"certfile", 'c', POPT_ARG_STRING, &certfile, 0,
-			"the certificate (in DER form) for verification ","<certfile>"},
-		POPT_AUTOALIAS
-		POPT_AUTOHELP
-		POPT_TABLEEND
-	};
-
-	rc = peverify_context_init(ctxp);
-	if (rc < 0) {
-		fprintf(stderr, "peverify: Could not initialize context: %m\n");
-		exit(1);
-	}
-
-	optCon = poptGetContext("peverify", argc, (const char **)argv,
-				options,0);
-
-	while ((rc = poptGetNextOpt(optCon)) > 0)
-		;
-
-	if (rc < -1) {
-		fprintf(stderr, "peverify: Invalid argument: %s: %s\n",
-			poptBadOption(optCon, 0), poptStrerror(rc));
-		exit(1);
-	}
-
-	if (poptPeekArg(optCon)) {
-		fprintf(stderr, "peverify: Invalid Argument: \"%s\"\n",
-				poptPeekArg(optCon));
-		exit(1);
-	}
-
-	poptFreeContext(optCon);
-
-	check_inputs(ctxp);
-	open_input(ctxp);
-
-	init_cert_db(ctxp, use_system_dbs);
-
-	certdir = mkdtemp(template);
-	status = NSS_InitReadWrite(certdir);
-	if (status != SECSuccess) {
-		fprintf(stderr, "Could not initialize nss: %s\n",
-			PORT_ErrorToString(PORT_GetError()));
-		exit(1);
-	}
-
-	rc = check_signature(ctxp);
-
-	close_input(ctxp);
-	if (!ctx.quiet)
-		printf("peverify: \"%s\" is %s.\n", ctx.infile,
-			rc >= 0 ? "valid" : "invalid");
-	peverify_context_fini(&ctx);
-
-	NSS_Shutdown();
-	remove_certdir(certdir);
-
-	return (rc < 0);
-}
diff --git a/src/peverify.h b/src/peverify.h
deleted file mode 100644
index 572c3ef..0000000
--- a/src/peverify.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Author(s): Peter Jones <pjones@redhat.com>
- */
-#ifndef PESIGN_H
-#define PESIGN_H 1
-
-#include <libdpe/libdpe.h>
-#include <libdpe/pe.h>
-
-#include "efitypes.h"
-#include "cms_common.h"
-#include "peverify_context.h"
-#include "certdb.h"
-
-#include "util.h"
-#include "endian.h"
-#include "oid.h"
-#include "wincert.h"
-#include "content_info.h"
-#include "signer_info.h"
-#include "signed_data.h"
-#include "password.h"
-
-#endif /* PESIGN_H */
diff --git a/src/peverify_context.c b/src/peverify_context.c
deleted file mode 100644
index d3aa53e..0000000
--- a/src/peverify_context.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Author(s): Peter Jones <pjones@redhat.com>
- */
-
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include "peverify.h"
-
-#include <nss.h>
-#include <secitem.h>
-
-int
-peverify_context_new(peverify_context **ctx)
-{
-	peverify_context *context = NULL;
-	int rc = 0;
-
-	if (ctx == NULL)
-		return -1;
-
-	context = malloc(sizeof (*context));
-	if (!context)
-		return -1;
-
-	peverify_context_init(context);
-	context->flags |= PEVERIFY_C_ALLOCATED;
-
-	*ctx = context;
-	return rc;
-}
-
-int
-peverify_context_init(peverify_context *ctx)
-{
-	if (!ctx)
-		return -1;
-	memset(ctx, '\0', sizeof (*ctx));
-
-	ctx->infd = -1;
-
-	int rc = cms_context_alloc(&ctx->cms_ctx);
-	if (rc < 0)
-		return rc;
-
-	return 0;
-}
-
-void
-peverify_context_fini(peverify_context *ctx)
-{
-	if (!ctx)
-		return;
-
-	cms_context_fini(ctx->cms_ctx);
-
-	xfree(ctx->infile);
-
-	if (ctx->inpe) {
-		pe_end(ctx->inpe);
-		ctx->inpe = NULL;
-	}
-
-	if (!(ctx->flags & PEVERIFY_C_ALLOCATED))
-		peverify_context_init(ctx);
-
-	while (ctx->db) {
-		dblist *db = ctx->db;
-
-		if (db->type == DB_CERT)
-			free(db->data);
-		munmap(db->map, db->size);
-		close(db->fd);
-		ctx->db = db->next;
-		free(db);
-	}
-	while (ctx->dbx) {
-		dblist *db = ctx->dbx;
-
-		if (db->type == DB_CERT)
-			free(db->data);
-		munmap(db->map, db->size);
-		close(db->fd);
-		ctx->dbx = db->next;
-		free(db);
-	}
-	while (ctx->hashes) {
-		hashlist *hashes = ctx->hashes;
-		free(hashes->data);
-		ctx->hashes = hashes->next;
-		free(hashes);
-	}
-}
-
-void
-peverify_context_free_private(peverify_context **ctx_ptr)
-{
-	peverify_context *ctx;
-	if (!ctx_ptr || !*ctx_ptr)
-		return;
-
-	ctx = *ctx_ptr;
-	peverify_context_fini(ctx);
-
-	if (ctx->flags & PEVERIFY_C_ALLOCATED)
-		xfree(*ctx_ptr);
-}
diff --git a/src/peverify_context.h b/src/peverify_context.h
deleted file mode 100644
index 7e26d06..0000000
--- a/src/peverify_context.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Author(s): Peter Jones <pjones@redhat.com>
- */
-#ifndef PEVERIFY_CONTEXT_H
-#define PEVERIFY_CONTEXT_H 1
-
-#include <cert.h>
-#include <secpkcs7.h>
-
-enum {
-	PEVERIFY_C_ALLOCATED = 1,
-};
-
-typedef enum {
-	DB_FILE,
-	DB_EFIVAR,
-	DB_CERT,
-} db_f_type;
-
-struct dblist {
-	db_f_type type;
-	int fd;
-	struct dblist *next;
-	size_t size;
-	void *map;
-	size_t datalen;
-	void *data;
-};
-
-typedef struct dblist dblist;
-
-struct hashlist {
-	efi_guid_t *hash_type;
-	void *data;
-	size_t datalen;
-	struct hashlist *next;
-};
-typedef struct hashlist hashlist;
-
-typedef struct peverify_context {
-	int flags;
-
-	char *infile;
-	int infd;
-	Pe *inpe;
-
-	int quiet;
-
-	hashlist *hashes;
-
-	dblist *db;
-	dblist *dbx;
-
-	cms_context *cms_ctx;
-} peverify_context;
-
-extern int peverify_context_new(peverify_context **ctx);
-extern void peverify_context_free_private(peverify_context **ctx_ptr);
-extern int peverify_context_init(peverify_context *ctx);
-extern void peverify_context_fini(peverify_context *ctx);
-#define peverify_context_free(ctx) peverify_context_free_private(&(ctx))
-
-#endif /* PEVERIFY_CONTEXT_H */
-- 
1.8.4.5


From 4191f24b18f1bf2a7be5da498b36f016bf115919 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 7 Jan 2014 12:02:47 +0800
Subject: [PATCH 10/31] Drop the temporary nss dir in pesigcheck

I thought we need a "physical" database for the certificates but
it's actually not necessary. Drop the nss dir creation/deletion
code to avoid the extra file system access.

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/pesigcheck.c | 24 +-----------------------
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/src/pesigcheck.c b/src/pesigcheck.c
index 7cd98c9..9cf33be 100644
--- a/src/pesigcheck.c
+++ b/src/pesigcheck.c
@@ -24,7 +24,6 @@
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <ftw.h>
 #include <nss.h>
 
 #include <popt.h>
@@ -197,23 +196,6 @@ callback(poptContext con, enum poptCallbackReason reason,
 	}
 }
 
-static int
-delete_files(const char *fpath, const struct stat *sb, int typeflag)
-{
-	if (typeflag == FTW_F)
-		remove(fpath);
-
-	return 0;
-}
-
-static void
-remove_certdir(const char *certdir)
-{
-	ftw(certdir, delete_files, 3);
-
-	remove(certdir);
-}
-
 int
 main(int argc, char *argv[])
 {
@@ -226,8 +208,6 @@ main(int argc, char *argv[])
 	char *certfile = NULL;
 	int use_system_dbs = 1;
 
-	char template[] = "/tmp/pesigcheck-XXXXXX";
-	char *certdir = NULL;
 	SECStatus status;
 
 	poptContext optCon;
@@ -283,8 +263,7 @@ main(int argc, char *argv[])
 
 	init_cert_db(ctxp, use_system_dbs);
 
-	certdir = mkdtemp(template);
-	status = NSS_InitReadWrite(certdir);
+	status = NSS_NoDB_Init(NULL);
 	if (status != SECSuccess) {
 		fprintf(stderr, "Could not initialize nss: %s\n",
 			PORT_ErrorToString(PORT_GetError()));
@@ -300,7 +279,6 @@ main(int argc, char *argv[])
 	pesigcheck_context_fini(&ctx);
 
 	NSS_Shutdown();
-	remove_certdir(certdir);
 
 	return (rc < 0);
 }
-- 
1.8.4.5


From c61386706b169ec02f55880a11dd8097b68d6180 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 8 Jan 2014 14:17:30 +0800
Subject: [PATCH 11/31] efisiglist: convert the hex array properly

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/efisiglist.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/efisiglist.c b/src/efisiglist.c
index b7190cb..e01ab73 100644
--- a/src/efisiglist.c
+++ b/src/efisiglist.c
@@ -70,9 +70,9 @@ static int8_t hexchar_to_bin(char hex)
 	if (hex >= '0' && hex <= '9')
 		return hex - '0';
 	if (hex >= 'A' && hex <= 'F')
-		return hex - 'A';
+		return hex - 'A' + 10;
 	if (hex >= 'a' && hex <= 'f')
-		return hex - 'a';
+		return hex - 'a' + 10;
 	return -1;
 }
 
@@ -83,7 +83,7 @@ hex_to_bin(char *hex, size_t size)
 	if (!ret)
 		return NULL;
 
-	for (int i = 0, j = 0; i < size; i+= 2, j++) {
+	for (int i = 0, j = 0; i < size*2; i+= 2, j++) {
 		uint8_t val;
 
 		val = hexchar_to_bin(hex[i]);
@@ -94,7 +94,7 @@ out_of_range:
 			return NULL;
 		}
 		ret[j] = (val & 0xf) << 4;
-		val = hexchar_to_bin(hex[i]);
+		val = hexchar_to_bin(hex[i+1]);
 		if (val < 0)
 			goto out_of_range;
 		ret[j] |= val & 0xf;
-- 
1.8.4.5


From 65b8b80de336920cb464d5b5881a66bbeebaa343 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 8 Jan 2014 14:20:38 +0800
Subject: [PATCH 12/31] efisiglist: Correct the calulation of SignatureListSize

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/siglist.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/src/siglist.c b/src/siglist.c
index ca097e6..0457208 100644
--- a/src/siglist.c
+++ b/src/siglist.c
@@ -100,6 +100,7 @@ signature_list_new(efi_guid_t SignatureType)
 
 	sl->SignatureType = SignatureType;
 	sl->SignatureSize = size + sizeof (efi_guid_t);
+	sl->SignatureListSize = sizeof (struct efi_signature_list);
 
 	return sl;
 }
@@ -107,7 +108,8 @@ signature_list_new(efi_guid_t SignatureType)
 static int
 resize_entries(signature_list *sl, uint32_t newsize)
 {
-	for (int i = 0; i < sl->SignatureListSize; i++) {
+	int count = (sl->SignatureListSize - sizeof (struct efi_signature_list)) / sl->SignatureSize;
+	for (int i = 0; i < count; i++) {
 		struct efi_signature_data *sd = sl->Signatures[i];
 		struct efi_signature_data *new_sd = calloc(1, newsize);
 
@@ -118,7 +120,8 @@ resize_entries(signature_list *sl, uint32_t newsize)
 		free(sd);
 		sl->Signatures[i] = sd;
 	}
-	sl->SignatureListSize = newsize;
+	sl->SignatureSize = newsize;
+	sl->SignatureListSize = sizeof (struct efi_signature_list) + count * newsize;
 	return 0;
 }
 
@@ -151,17 +154,17 @@ signature_list_add_sig(signature_list *sl, efi_guid_t owner,
 	memcpy(sd->SignatureData, sig, sl->SignatureSize -
 						sizeof (efi_guid_t));
 
-	struct efi_signature_data **sdl = calloc(sl->SignatureListSize+1,
+	int count = (sl->SignatureListSize - sizeof (struct efi_signature_list)) / sl->SignatureSize;
+	struct efi_signature_data **sdl = calloc(count+1,
 					sizeof (struct efi_signature_data *));
 	if (!sdl) {
 		free(sd);
 		return -1;
 	}
 
-	memcpy(sdl, sl->Signatures, sl->SignatureListSize *
-					sizeof (struct efi_signature_data *));
-	sdl[sl->SignatureListSize] = sd;
-	sl->SignatureListSize++;
+	memcpy(sdl, sl->Signatures, count * sl->SignatureSize);
+	sdl[count] = sd;
+	sl->SignatureListSize += sl->SignatureSize;
 
 	free(sl->Signatures);
 	sl->Signatures = sdl;
@@ -195,9 +198,10 @@ signature_list_realize(signature_list *sl, void **out, size_t *outsize)
 		sl->realized = NULL;
 	}
 
+	int count = (sl->SignatureListSize - sizeof (struct efi_signature_list)) / sl->SignatureSize;
 	struct efi_signature_list *esl = NULL;
 	uint32_t size = sizeof (*esl) +
-			+ sl->SignatureListSize * sl->SignatureSize;
+			+ count * sl->SignatureSize;
 
 	void *ret = calloc(1, size);
 	if (!ret)
@@ -207,7 +211,7 @@ signature_list_realize(signature_list *sl, void **out, size_t *outsize)
 	memcpy(esl, sl, sizeof (*esl));
 
 	uint8_t *pos = ret + sizeof (*esl);
-	for (int i = 0; i < sl->SignatureListSize; i++) {
+	for (int i = 0; i < count; i++) {
 		memcpy(pos, sl->Signatures[i], sl->SignatureSize);
 		pos += sl->SignatureSize;
 	}
@@ -225,7 +229,8 @@ signature_list_free(signature_list *sl)
 	if (sl->realized)
 		free(sl->realized);
 
-	for (int i = 0; i < sl->SignatureListSize; i++)
+	int count = (sl->SignatureListSize - sizeof (struct efi_signature_list)) / sl->SignatureSize;
+	for (int i = 0; i < count; i++)
 		free(sl->Signatures[i]);
 
 	free(sl);
-- 
1.8.4.5


From b51e250f52fe599cf1713c3c91a4b29f0b73fc4c Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 8 Jan 2014 15:10:18 +0800
Subject: [PATCH 13/31] efisiglist: support adding a certificate in DER form

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/efisiglist.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 70 insertions(+), 2 deletions(-)

diff --git a/src/efisiglist.c b/src/efisiglist.c
index e01ab73..b96553b 100644
--- a/src/efisiglist.c
+++ b/src/efisiglist.c
@@ -23,6 +23,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
 
 #include "efitypes.h"
 #include "siglist.h"
@@ -106,11 +109,15 @@ int
 main(int argc, char *argv[])
 {
 	poptContext optCon;
+	efi_guid_t owner = RH_GUID;
 	int rc;
 	char *outfile = NULL;
 	char *hash = NULL;
 	char *hash_type = "sha256";
 	char *certfile = NULL;
+	int certfd = -1;
+	void *cert_data = NULL;
+	size_t cert_size = 0;
 
 	int add = 1;
 
@@ -126,7 +133,7 @@ main(int argc, char *argv[])
 			"hash value to add", "<hash>" },
 		{"hash-type", 't', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
 			&hash_type, 0, "hash type to add", "<hash-type>" },
-		{"certificate", 'c', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,
+		{"certificate", 'c', POPT_ARG_STRING,
 			&certfile, 0, "certificate to add", "<certfile>" },
 		POPT_AUTOALIAS
 		POPT_AUTOHELP
@@ -197,6 +204,29 @@ main(int argc, char *argv[])
 				hash_params[hash_index].size * 8, x * 4);
 			exit(1);
 		}
+	} else if (certfile) {
+		certfd = open(certfile, O_RDONLY, 0644);
+		if (certfd < 0) {
+			fprintf(stderr, "efisiglist: could not open \"%s\": "
+				"%m\n", certfile);
+			exit(1);
+		}
+
+		struct stat sb;
+		if (fstat(certfd, &sb) < 0) {
+			fprintf(stderr, "efisiglist: could not get the size "
+				"of \"%s\": %m\n", certfile);
+			exit(1);
+		}
+		cert_size = sb.st_size;
+
+		cert_data = mmap(NULL, cert_size, PROT_READ, MAP_PRIVATE,
+				 certfd, 0);
+		if (cert_data == MAP_FAILED) {
+			fprintf(stderr, "efisiglist: could not map \"%s\": "
+				"%m\n", certfile);
+			exit(1);
+		}
 	}
 
 	if (add) {
@@ -209,7 +239,6 @@ main(int argc, char *argv[])
 				unlink(outfile);
 				exit(1);
 			}
-			efi_guid_t owner = RH_GUID;
 			uint8_t *binary_hash = hex_to_bin(hash,
 				hash_params[hash_index].size);
 			if (!binary_hash) {
@@ -245,6 +274,45 @@ main(int argc, char *argv[])
 			}
 			close(outfd);
 			exit(0);
+		} else if (certfile) {
+			efi_guid_t sig_type = EFI_CERT_X509_GUID;
+			signature_list *sl = signature_list_new(sig_type);
+			if (!sl) {
+				fprintf(stderr, "efisiglist: could not "
+					"allocate signature list: %m\n");
+				unlink(outfile);
+				exit(1);
+			}
+			rc = signature_list_add_sig(sl, owner, cert_data,
+				cert_size);
+			if (rc < 0) {
+				fprintf(stderr,"efisiglist: could not add "
+					"cert to list: %m\n");
+				unlink(outfile);
+				exit(1);
+			}
+
+			void *blah;
+			size_t size = 0;
+			rc = signature_list_realize(sl, &blah, &size);
+			if (rc < 0) {
+				fprintf(stderr, "efisiglist: Could not realize "
+					"signature list: %m\n");
+				unlink(outfile);
+				exit(1);
+			}
+			rc = write(outfd, blah, size);
+			if (rc < 0) {
+				fprintf(stderr, "efisiglist: Could not write "
+					"signature list: %m\n");
+				unlink(outfile);
+				exit(1);
+			}
+
+			munmap(cert_data, cert_size);
+			close(certfd);
+			close(outfd);
+			exit(0);
 		}
 	}
 	exit(1);
-- 
1.8.4.5


From a2a7e57e1786a65bac95d1ce03ceda0487c9c2bf Mon Sep 17 00:00:00 2001
From: Michael Scherer <misc@zarb.org>
Date: Mon, 6 Jan 2014 00:48:54 +0100
Subject: [PATCH 14/31] Fix incorrect assignation, and fix memleak ( since
 new_sd is allocated and never used )

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

diff --git a/src/siglist.c b/src/siglist.c
index 0457208..e001493 100644
--- a/src/siglist.c
+++ b/src/siglist.c
@@ -118,7 +118,7 @@ resize_entries(signature_list *sl, uint32_t newsize)
 
 		memcpy(new_sd, sd, sl->SignatureSize);
 		free(sd);
-		sl->Signatures[i] = sd;
+		sl->Signatures[i] = new_sd;
 	}
 	sl->SignatureSize = newsize;
 	sl->SignatureListSize = sizeof (struct efi_signature_list) + count * newsize;
-- 
1.8.4.5


From 3e3f152387dfc54598c29b5db7540fad9a9043d8 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Fri, 30 May 2014 18:16:53 +0800
Subject: [PATCH 15/31] authvar: fill some baisc functions

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar.c         | 223 ++++++++++++++++++++++++++++++++++++++++++++------
 src/authvar.h         |   1 +
 src/authvar_context.c | 148 ++++++++++++++++++++++++++++++++-
 src/authvar_context.h |  20 ++++-
 src/efitypes.h        |   4 +-
 src/wincert.h         |  13 +++
 6 files changed, 375 insertions(+), 34 deletions(-)

diff --git a/src/authvar.c b/src/authvar.c
index 1a05e6b..cfa9de3 100644
--- a/src/authvar.c
+++ b/src/authvar.c
@@ -19,6 +19,17 @@
 
 #include <errno.h>
 #include <popt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include <prerror.h>
+#include <nss.h>
 
 #include "authvar.h"
 
@@ -86,6 +97,75 @@ check_value(authvar_context *ctx, int needed)
 				"authvar: command does not take a value.\n");
 		exit(1);
 	}
+
+	if (ctx->value) {
+		ctx->value_size = strlen(ctx->value);
+	}
+}
+
+static void
+open_input(authvar_context *ctx)
+{
+	struct stat sb;
+
+	if (!ctx->valuefile)
+		return;
+
+	ctx->valuefd = open(ctx->valuefile, O_RDONLY|O_CLOEXEC);
+	if (ctx->valuefd < 0) {
+		fprintf(stderr, "authvar: Error opening valuefile: %m\n");
+		exit(1);
+	}
+
+	if (fstat(ctx->valuefd, &sb) < 0) {
+		fprintf(stderr, "authvar: Error mapping valuefile: %m\n");
+		exit(1);
+	}
+	ctx->value_size = sb.st_size;
+
+	ctx->value = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE,
+			     ctx->valuefd, 0);
+	if (ctx->value == MAP_FAILED) {
+		fprintf(stderr, "authvar: Error mapping valuefile: %m\n");
+		exit(1);
+	}
+}
+
+#define EFIVAR_DIR "/sys/firmware/efi/efivars/"
+
+static void
+generate_efivars_filename(authvar_context *ctx)
+{
+	efi_guid_t guid = ctx->guid;
+	size_t length;
+
+	length = strlen(EFIVAR_DIR) + strlen(ctx->name) + 38;
+	ctx->exportfile = (char *)malloc(length);
+
+	sprintf(ctx->exportfile, "%s%s-%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+		EFIVAR_DIR, ctx->name, guid.data1, guid.data2, guid.data3,
+		guid.data4[0], guid.data4[1], guid.data4[2],
+		guid.data4[3], guid.data4[4], guid.data4[5],
+		guid.data4[6], guid.data4[7]);
+}
+
+static void
+open_output(authvar_context *ctx)
+{
+	int flags;
+	mode_t mode;
+
+	if (!ctx->exportfile) {
+		generate_efivars_filename(ctx);
+	}
+
+	flags = O_CREAT|O_RDWR|O_CLOEXEC;
+	mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+	ctx->exportfd = open(ctx->exportfile, flags, mode);
+	if (ctx->exportfd < 0) {
+		fprintf(stderr, "authvar: Error opening exportfile: %m\n");
+		exit(1);
+	}
 }
 
 static int
@@ -163,11 +243,41 @@ find_namespace_guid(authvar_context *ctx)
 	return parse_guid(ctx->namespace, &ctx->guid);
 }
 
+static void
+set_timestamp(authvar_context *ctx, const char *time_str)
+{
+	time_t t;
+	struct tm *tm;
+
+	if (time_str) {
+		/* TODO parse the string */
+	} else {
+		time(&t);
+		tm = gmtime(&t);
+	}
+
+	ctx->timestamp.year = tm->tm_year + 1900;
+	ctx->timestamp.month = tm->tm_mon + 1;
+	ctx->timestamp.day = tm->tm_mday;
+	ctx->timestamp.hour = tm->tm_hour;
+	ctx->timestamp.minute = tm->tm_min;
+	ctx->timestamp.second = tm->tm_sec;
+
+	ctx->timestamp.pad1 = 0;
+	ctx->timestamp.nanosecond = 0;
+	ctx->timestamp.timezone = 0;
+	ctx->timestamp.daylight = 0;
+	ctx->timestamp.pad2 = 0;
+}
+
 int main(int argc, char *argv[])
 {
 	int rc;
 	authvar_context ctx = { 0, };
 	authvar_context *ctxp = &ctx;
+	char *time_str = NULL;
+	char *certdir = "/etc/pki/pesign";
+	SECStatus status;
 
 	int action = 0;
 
@@ -182,6 +292,10 @@ int main(int argc, char *argv[])
 		{ NULL, '\0', POPT_ARG_INTL_DOMAIN, "pesign" },
 		{ "append", 'a', POPT_ARG_VAL|POPT_ARGFLAG_OR, &action,
 			GENERATE_APPEND, "append to variable" },
+		{"certdir", 'd', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
+			&certdir, 0,
+			"specify nss certificate database directory",
+			"<certificate directory path>" },
 		{ "clear", 'c', POPT_ARG_VAL|POPT_ARGFLAG_OR, &action,
 			GENERATE_CLEAR, "clear variable" },
 		{ "set", 's', POPT_ARG_VAL|POPT_ARGFLAG_OR, &action,
@@ -192,6 +306,8 @@ int main(int argc, char *argv[])
 			"{<namespace>|<guid>}" },
 		{ "name", 'n', POPT_ARG_STRING, &ctx.name, 0, "variable name",
 			"<name>" },
+		{ "timestamp", 't', POPT_ARG_STRING, &time_str, 0,
+			"timestamp for the variable", "<time>" },
 		{ "value", 'v', POPT_ARG_STRING, &ctx.value, 0,
 			"value to set or append", "<value>" },
 		{ "valuefile", 'f', POPT_ARG_STRING, &ctx.valuefile, 0,
@@ -201,7 +317,7 @@ int main(int argc, char *argv[])
 		{ "export", 'e', POPT_ARG_STRING, &ctx.exportfile, 0,
 			"export variable to <file> instead of firmware",
 			"<file>" },
-		{ "sign", 'S', POPT_ARG_STRING, &ctx.cms_ctx.certname, 0,
+		{ "sign", 'S', POPT_ARG_STRING, &ctx.cms_ctx->certname, 0,
 			"sign variable with certificate <nickname>",
 			"<nickname>" },
 		POPT_AUTOALIAS
@@ -209,6 +325,25 @@ int main(int argc, char *argv[])
 		POPT_TABLEEND
 	};
 
+	optCon = poptGetContext("authvar", argc, (const char **)argv,
+				options, 0);
+	while ((rc = poptGetNextOpt(optCon)) > 0)
+		;
+
+	if (rc < -1) {
+		fprintf(stderr, "authvar: Invalid argument: %s: %s\n",
+			poptBadOption(optCon, 0), poptStrerror(rc));
+		exit(1);
+	}
+
+	if (poptPeekArg(optCon)) {
+		fprintf(stderr, "authvar: Invalid Argument: \"%s\"\n",
+			poptPeekArg(optCon));
+		exit(1);
+	}
+
+	poptFreeContext(optCon);
+
 	if (ctx.importfile)
 		action |= IMPORT;
 	if (ctx.exportfile)
@@ -216,14 +351,12 @@ int main(int argc, char *argv[])
 	if (!(action & (IMPORT|EXPORT)))
 		action |= SET;
 
-	if (ctx.cms_ctx.certname && *ctx.cms_ctx.certname) {
-		rc = find_certificate(&ctx.cms_ctx, 1);
-		if (rc < 0) {
-			fprintf(stderr, "authvar: Could not find certificate "
-				"for \"%s\"\n", ctx.cms_ctx.certname);
+	if ((action & GENERATE_APPEND) || (action & GENERATE_CLEAR) ||
+	    (action & GENERATE_SET)) {
+		if (!ctx.cms_ctx->certname || !*ctx.cms_ctx->certname) {
+			fprintf(stderr, "authvar: Require a certificate to sign\n");
 			exit(1);
 		}
-		action |= SIGN;
 	}
 
 	rc = find_namespace_guid(ctxp);
@@ -233,25 +366,30 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	optCon = poptGetContext("authvar", argc, (const char **)argv,
-				options, 0);
-	while ((rc = poptGetNextOpt(optCon)) > 0)
-		;
+	set_timestamp(ctxp, time_str);
 
-	if (rc < -1) {
-		fprintf(stderr, "authvar: Invalid argument: %s: %s\n",
-			poptBadOption(optCon, 0), poptStrerror(rc));
+	/* Initialize the NSS db */
+	if ((action & GENERATE_APPEND) || (action & GENERATE_CLEAR) ||
+	    (action & GENERATE_SET)    || (action & SIGN))
+		status = NSS_Init(certdir);
+	else
+		status = NSS_NoDB_Init(NULL);
+	if (status != SECSuccess) {
+		fprintf(stderr, "Could not initialize nss: %s\n",
+			PORT_ErrorToString(PORT_GetError()));
 		exit(1);
 	}
 
-	if (poptPeekArg(optCon)) {
-		fprintf(stderr, "authvar: Invalid Argument: \"%s\"\n",
-			poptPeekArg(optCon));
-		exit(1);
+	if (ctx.cms_ctx->certname && *ctx.cms_ctx->certname) {
+		rc = find_certificate(ctx.cms_ctx, 1);
+		if (rc < 0) {
+			fprintf(stderr, "authvar: Could not find certificate "
+				"for \"%s\"\n", ctx.cms_ctx->certname);
+			exit(1);
+		}
+		action |= SIGN;
 	}
 
-	poptFreeContext(optCon);
-
 	print_flag_name(stdout, action);
 	printf("\n");
 	switch (action) {
@@ -259,20 +397,48 @@ int main(int argc, char *argv[])
 		fprintf(stderr, "authvar: No action specified\n");
 		exit(1);
 		break;
-	case GENERATE_APPEND|EXPORT:
-	case GENERATE_APPEND|SET:
+	case GENERATE_APPEND|EXPORT|SIGN:
+	case GENERATE_APPEND|SET|SIGN:
 		check_name(ctxp);
 		check_value(ctxp, 1);
+		open_input(ctxp);
+		ctxp->attr |= EFI_VARIABLE_APPEND_WRITE;
+		/* TODO Set Day and Month to 0 */
+
+		rc = generate_descriptor(ctxp);
+		if (rc < 0) {
+			fprintf(stderr, "authvar: unable to generate descriptor\n");
+			exit(1);
+		}
+		open_output(ctxp);
+		write_authvar(ctxp);
 		break;
-	case GENERATE_CLEAR|EXPORT:
-	case GENERATE_CLEAR|SET:
+	case GENERATE_CLEAR|EXPORT|SIGN:
+	case GENERATE_CLEAR|SET|SIGN:
 		check_name(ctxp);
 		check_value(ctxp, 0);
+
+		rc = generate_descriptor(ctxp);
+		if (rc < 0) {
+			fprintf(stderr, "authvar: unable to generate descriptor\n");
+			exit(1);
+		}
+		open_output(ctxp);
+		write_authvar(ctxp);
 		break;
-	case GENERATE_SET|EXPORT:
-	case GENERATE_SET|SET:
+	case GENERATE_SET|EXPORT|SIGN:
+	case GENERATE_SET|SET|SIGN:
 		check_name(ctxp);
 		check_value(ctxp, 1);
+		open_input(ctxp);
+
+		rc = generate_descriptor(ctxp);
+		if (rc < 0) {
+			fprintf(stderr, "authvar: unable to generate descriptor\n");
+			exit(1);
+		}
+		open_output(ctxp);
+		write_authvar(ctxp);
 		break;
 	case IMPORT|SET:
 	case IMPORT|SIGN|SET:
@@ -286,5 +452,10 @@ int main(int argc, char *argv[])
 	}
 
 	authvar_context_fini(ctxp);
+	if (time_str)
+		xfree(time_str);
+
+	NSS_Shutdown();
+
 	return 0;
 }
diff --git a/src/authvar.h b/src/authvar.h
index d8a6b9a..3e7364a 100644
--- a/src/authvar.h
+++ b/src/authvar.h
@@ -24,6 +24,7 @@
 
 #include "efitypes.h"
 #include "cms_common.h"
+#include "wincert.h"
 #include "authvar_context.h"
 #include "util.h"
 #include "siglist.h"
diff --git a/src/authvar_context.c b/src/authvar_context.c
index b7230b0..53c6f98 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -17,6 +17,14 @@
  * Author(s): Peter Jones <pjones@redhat.com>
  */
 
+#include <sys/mman.h>
+
+#include <prerror.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <secport.h>
+#include <secerr.h>
+
 #include "authvar.h"
 
 static char *default_namespace="global";
@@ -28,7 +36,12 @@ authvar_context_init(authvar_context *ctx)
 
 	ctx->namespace = default_namespace;
 
-	int rc = cms_context_init(&ctx->cms_ctx);
+	int rc = cms_context_alloc(&ctx->cms_ctx);
+	ctx->attr = EFI_VARIABLE_NON_VOLATILE |
+		    EFI_VARIABLE_RUNTIME_ACCESS |
+		    EFI_VARIABLE_BOOTSERVICE_ACCESS |
+		    EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+	ctx->exportfd = -1;
 
 	return rc;
 }
@@ -39,7 +52,136 @@ authvar_context_fini(authvar_context *ctx)
 	if (!ctx)
 		return;
 
-	cms_context_fini(&ctx->cms_ctx);
+	cms_context_fini(ctx->cms_ctx);
 
-	memset(ctx, '\0', sizeof (*ctx));
+	if (ctx->name) {
+		xfree(ctx->name);
+	}
+
+	if (ctx->valuefile) {
+		munmap(ctx->value, ctx->value_size);
+		ctx->value = NULL;
+
+		close(ctx->valuefd);
+		ctx->valuefd = -1;
+		ctx->value_size = 0;
+
+		xfree(ctx->valuefile);
+		ctx->valuefile = NULL;
+	} else if (ctx->value) {
+		xfree(ctx->value);
+		ctx->value = NULL;
+		ctx->value_size = 0;
+	}
+
+	if (ctx->exportfd >= 0) {
+		close(ctx->exportfd);
+		ctx->exportfd = -1;
+	}
+}
+
+static SECItem*
+generate_buffer_digest(cms_context *cms, uint8_t *buf, size_t buf_len)
+{
+	PK11Context *pk11ctx = NULL;
+	SECItem *digest = NULL;
+
+	pk11ctx = PK11_CreateDigestContext(SEC_OID_SHA256);
+	if (!pk11ctx) {
+		cms->log(cms, LOG_ERR, "%s:%s:%d could not create "
+			"digest context: %s",
+			__FILE__, __func__, __LINE__,
+			PORT_ErrorToString(PORT_GetError()));
+		goto err;
+	}
+
+	PK11_DigestBegin(pk11ctx);
+	PK11_DigestOp(pk11ctx, buf, buf_len);
+
+	digest = PORT_ArenaZAlloc(cms->arena, sizeof (SECItem));
+	if (!digest) {
+		cms->log(cms, LOG_ERR, "%s:%s:%d could not allocate "
+			"memory: %s", __FILE__, __func__, __LINE__,
+			PORT_ErrorToString(PORT_GetError()));
+		goto err;
+	}
+
+	digest->type = siBuffer;
+	digest->len = 32;
+	digest->data = PORT_ArenaZAlloc(cms->arena, 32);
+	if (!digest->data) {
+		cms->log(cms, LOG_ERR, "%s:%s:%d could not allocate "
+			"memory: %s", __FILE__, __func__, __LINE__,
+			PORT_ErrorToString(PORT_GetError()));
+		goto err;
+	}
+
+	PK11_DigestFinal(pk11ctx, digest->data, &digest->len, 32);
+	PK11_Finalize(pk11ctx);
+	PK11_DestroyContext(pk11ctx, PR_TRUE);
+
+err:
+	return digest;
+}
+
+int
+generate_descriptor(authvar_context *ctx)
+{
+	win_cert_uefi_guid_t *authinfo;
+	SECItem *digest;
+	char *name_ptr;
+	uint8_t *buf, *ptr;
+	size_t buf_len;
+
+	/* prepare buffer for varname, vendor_guid, attr, timestamp, value */
+	buf_len = strlen(ctx->name)*2 + sizeof(efi_guid_t) + sizeof(uint32_t) +
+		  sizeof(efi_time_t) + ctx->value_size;
+	buf = calloc(1, buf_len);
+	if (!buf)
+		return -1;
+
+	ptr = buf;
+	name_ptr = ctx->name;
+	while (*name_ptr != '\0') {
+		ptr++;
+		*ptr = *name_ptr;
+		name_ptr++;
+	}
+	ptr++;
+
+	memcpy(ptr, &ctx->guid, sizeof(efi_guid_t));
+	ptr += sizeof(efi_guid_t);
+
+	memcpy(ptr, &ctx->attr, sizeof(uint32_t));
+	ptr += sizeof(uint32_t);
+
+	memcpy(ptr, &ctx->timestamp, sizeof(efi_time_t));
+	ptr += sizeof(efi_time_t);
+
+	memcpy(ptr, ctx->value, ctx->value_size);
+
+	digest = generate_buffer_digest(ctx->cms_ctx, buf, buf_len);
+	if (!digest || !digest->data) {
+		xfree(buf);
+		return -1;
+	}
+
+	/* TODO sign the digest */
+
+	// TODO complete authinfo
+	authinfo = &ctx->des.authinfo;
+	//authinfo->hdr.length
+	authinfo->hdr.revision = WIN_CERT_REVISION_2_0;
+	authinfo->hdr.cert_type = WIN_CERT_TYPE_EFI_GUID;
+	authinfo->type = (efi_guid_t)EFI_CERT_TYPE_PKCS7_GUID;
+	// TODO append the signed data to authinfo->data
+
+
+	return 0;
+}
+
+int
+write_authvar(authvar_context *ctx)
+{
+	return 0;
 }
diff --git a/src/authvar_context.h b/src/authvar_context.h
index 88d145d..9647849 100644
--- a/src/authvar_context.h
+++ b/src/authvar_context.h
@@ -23,15 +23,29 @@ typedef struct {
 	char *namespace;
 	efi_guid_t guid;
 	char *name;
-	char *value;
-	char *valuefile;
+	uint32_t attr;
+
+	char  *value;
+	char  *valuefile;
+	int    valuefd;
+	size_t value_size;
+
+	efi_time_t timestamp;
+
 	char *importfile;
+	int   inmportfd;
+
 	char *exportfile;
+	int   exportfd;
+
+	efi_var_auth_2_t des;
 
-	cms_context cms_ctx;
+	cms_context *cms_ctx;
 } authvar_context;
 
 extern int authvar_context_init(authvar_context *ctx);
 extern void authvar_context_fini(authvar_context *ctx);
+extern int generate_descriptor(authvar_context *ctx);
+extern int write_authvar(authvar_context *ctx);
 
 #endif /* AUTHVAR_CONTEXT_H */
diff --git a/src/efitypes.h b/src/efitypes.h
index ebd5fef..64683e8 100644
--- a/src/efitypes.h
+++ b/src/efitypes.h
@@ -50,10 +50,10 @@ typedef struct {
 } efi_time_t;
 
 struct efi_variable {
-	efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
+	efi_char16_t *VariableName;
 	efi_guid_t VendorGuid;
 	unsigned long DataSize;
-	uint8_t Data[1024];
+	uint8_t *Data;
 	efi_status_t Status;
 	uint32_t Attributes;
 };
diff --git a/src/wincert.h b/src/wincert.h
index 77e94b4..bd822d4 100644
--- a/src/wincert.h
+++ b/src/wincert.h
@@ -19,6 +19,8 @@
 #ifndef PESIGN_WINCERT_H
 #define PESIGN_WINCERT_H 1
 
+#include "efitypes.h"
+
 #define WIN_CERT_TYPE_PKCS_SIGNED_DATA	0x0002
 #define WIN_CERT_TYPE_EFI_OKCS115	0x0EF0
 #define WIN_CERT_TYPE_EFI_GUID		0x0EF1
@@ -39,6 +41,17 @@ typedef struct cert_iter {
 	size_t size;
 } cert_iter;
 
+typedef struct {
+	win_certificate	hdr;
+	efi_guid_t	type;
+	uint8_t		data[1];
+} win_cert_uefi_guid_t;
+
+typedef struct {
+	efi_time_t		timestamp;
+	win_cert_uefi_guid_t	authinfo;
+} efi_var_auth_2_t;
+
 extern int cert_iter_init(cert_iter *iter, Pe *pe);
 extern int next_cert(cert_iter *iter, void **cert, ssize_t *cert_size);
 extern ssize_t available_cert_space(Pe *pe);
-- 
1.8.4.5


From 1a349b52fd37e71226fd01a75298c9b6f3e25277 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 3 Jun 2014 16:38:43 +0800
Subject: [PATCH 16/31] authvar: generate and write the EFI AUTH variable

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar.c         | 18 ++++++++++
 src/authvar.h         |  2 ++
 src/authvar_context.c | 93 +++++++++++++++++++++++++++++++++++++++++----------
 src/authvar_context.h |  2 +-
 4 files changed, 96 insertions(+), 19 deletions(-)

diff --git a/src/authvar.c b/src/authvar.c
index cfa9de3..4fb3145 100644
--- a/src/authvar.c
+++ b/src/authvar.c
@@ -276,6 +276,8 @@ int main(int argc, char *argv[])
 	authvar_context ctx = { 0, };
 	authvar_context *ctxp = &ctx;
 	char *time_str = NULL;
+	char *tokenname = "NSS Certificate DB";
+	char *origtoken = tokenname;
 	char *certdir = "/etc/pki/pesign";
 	SECStatus status;
 
@@ -380,6 +382,22 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
+	status = register_oids(ctxp->cms_ctx);
+	if (status != SECSuccess) {
+		fprintf(stderr, "Could not register OIDs\n");
+		exit(1);
+	}
+
+	ctxp->cms_ctx->tokenname = tokenname ?
+		PORT_ArenaStrdup(ctxp->cms_ctx->arena, tokenname) : NULL;
+	if (tokenname && !ctxp->cms_ctx->tokenname) {
+		fprintf(stderr, "could not allocate token name: %s\n",
+			PORT_ErrorToString(PORT_GetError()));
+		exit(1);
+	}
+	if (tokenname != origtoken)
+		free(tokenname);
+
 	if (ctx.cms_ctx->certname && *ctx.cms_ctx->certname) {
 		rc = find_certificate(ctx.cms_ctx, 1);
 		if (rc < 0) {
diff --git a/src/authvar.h b/src/authvar.h
index 3e7364a..3da5906 100644
--- a/src/authvar.h
+++ b/src/authvar.h
@@ -31,5 +31,7 @@
 #include "endian.h"
 #include "ucs2.h"
 #include "varfile.h"
+#include "signed_data.h"
+#include "oid.h"
 
 #endif /* AUTHVAR_H */
diff --git a/src/authvar_context.c b/src/authvar_context.c
index 53c6f98..fdc6d7e 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -17,6 +17,7 @@
  * Author(s): Peter Jones <pjones@redhat.com>
  */
 
+#include <unistd.h>
 #include <sys/mman.h>
 
 #include <prerror.h>
@@ -80,14 +81,22 @@ authvar_context_fini(authvar_context *ctx)
 	}
 }
 
-static SECItem*
+static int
 generate_buffer_digest(cms_context *cms, uint8_t *buf, size_t buf_len)
 {
-	PK11Context *pk11ctx = NULL;
+	struct digest *digests = NULL;
 	SECItem *digest = NULL;
 
-	pk11ctx = PK11_CreateDigestContext(SEC_OID_SHA256);
-	if (!pk11ctx) {
+	if (cms->digests) {
+		digests = cms->digests;
+	} else {
+		digests = PORT_ZAlloc(sizeof (struct digest));
+		if (digests == NULL)
+			cmsreterr(-1, cms, "could not allocate digest context");
+	}
+
+	digests[0].pk11ctx = PK11_CreateDigestContext(SEC_OID_SHA256);
+	if (!digests[0].pk11ctx) {
 		cms->log(cms, LOG_ERR, "%s:%s:%d could not create "
 			"digest context: %s",
 			__FILE__, __func__, __LINE__,
@@ -95,8 +104,8 @@ generate_buffer_digest(cms_context *cms, uint8_t *buf, size_t buf_len)
 		goto err;
 	}
 
-	PK11_DigestBegin(pk11ctx);
-	PK11_DigestOp(pk11ctx, buf, buf_len);
+	PK11_DigestBegin(digests[0].pk11ctx);
+	PK11_DigestOp(digests[0].pk11ctx, buf, buf_len);
 
 	digest = PORT_ArenaZAlloc(cms->arena, sizeof (SECItem));
 	if (!digest) {
@@ -116,22 +125,39 @@ generate_buffer_digest(cms_context *cms, uint8_t *buf, size_t buf_len)
 		goto err;
 	}
 
-	PK11_DigestFinal(pk11ctx, digest->data, &digest->len, 32);
-	PK11_Finalize(pk11ctx);
-	PK11_DestroyContext(pk11ctx, PR_TRUE);
+	PK11_DigestFinal(digests[0].pk11ctx, digest->data, &digest->len, 32);
+	PK11_Finalize(digests[0].pk11ctx);
+	PK11_DestroyContext(digests[0].pk11ctx, PR_TRUE);
 
+	cms->digests = digests;
+	cms->digests[0].pk11ctx = NULL;
+	/* XXX sure seems like we should be freeing it here,
+	 * but that's segfaulting, and we know it'll get
+	 * cleaned up with PORT_FreeArena a couple of lines
+	 * down.
+	 */
+	cms->digests[0].pe_digest = digest;
+	cms->selected_digest = 0;
+
+	return 0;
 err:
-	return digest;
+	if (digests[0].pk11ctx)
+		PK11_DestroyContext(digests[0].pk11ctx, PR_TRUE);
+
+	free(digests);
+
+	return -1;
 }
 
 int
 generate_descriptor(authvar_context *ctx)
 {
 	win_cert_uefi_guid_t *authinfo;
-	SECItem *digest;
+	SECItem sd_der;
 	char *name_ptr;
 	uint8_t *buf, *ptr;
 	size_t buf_len;
+	int rc;
 
 	/* prepare buffer for varname, vendor_guid, attr, timestamp, value */
 	buf_len = strlen(ctx->name)*2 + sizeof(efi_guid_t) + sizeof(uint32_t) +
@@ -160,22 +186,28 @@ generate_descriptor(authvar_context *ctx)
 
 	memcpy(ptr, ctx->value, ctx->value_size);
 
-	digest = generate_buffer_digest(ctx->cms_ctx, buf, buf_len);
-	if (!digest || !digest->data) {
+	if (generate_buffer_digest(ctx->cms_ctx, buf, buf_len) < 0) {
 		xfree(buf);
 		return -1;
 	}
 
-	/* TODO sign the digest */
+	/* sign the digest */
+	memset(&sd_der, '\0', sizeof(sd_der));
+	rc = generate_spc_signed_data(ctx->cms_ctx, &sd_der);
+	if (rc < 0)
+		cmsreterr(-1, ctx->cms_ctx, "could not create signed data");
+
+	authinfo = calloc(sizeof(win_cert_uefi_guid_t) + sd_der.len, 1);
+	if (!authinfo)
+		cmsreterr(-1, ctx->cms_ctx, "could not allocate authinfo");
 
-	// TODO complete authinfo
-	authinfo = &ctx->des.authinfo;
-	//authinfo->hdr.length
+	authinfo->hdr.length = sd_der.len + sizeof(win_cert_uefi_guid_t) - 1;
 	authinfo->hdr.revision = WIN_CERT_REVISION_2_0;
 	authinfo->hdr.cert_type = WIN_CERT_TYPE_EFI_GUID;
 	authinfo->type = (efi_guid_t)EFI_CERT_TYPE_PKCS7_GUID;
-	// TODO append the signed data to authinfo->data
+	memcpy(&authinfo->data, sd_der.data, sd_der.len);
 
+	ctx->authinfo = authinfo;
 
 	return 0;
 }
@@ -183,5 +215,30 @@ generate_descriptor(authvar_context *ctx)
 int
 write_authvar(authvar_context *ctx)
 {
+	efi_var_auth_2_t *descriptor;
+	size_t des_len;
+
+	if (!ctx->authinfo)
+		cmsreterr(-1, ctx->cms_ctx, "Not a valid authvar");
+
+	/* The attributes of the variable */
+	write(ctx->exportfd, &ctx->attr, sizeof(ctx->attr));
+
+	/* The EFI_VARIABLE_AUTHENTICATION_2 */
+	des_len = sizeof(efi_var_auth_2_t) + ctx->authinfo->hdr.length -
+		  sizeof(win_cert_uefi_guid_t) + 1;
+	descriptor = calloc(des_len, 1);
+	if (!descriptor)
+		cmsreterr(-1, ctx->cms_ctx, "could not allocate descriptor");
+
+	memcpy(&descriptor->timestamp, &ctx->timestamp, sizeof(efi_time_t));
+	memcpy(&descriptor->authinfo, ctx->authinfo, ctx->authinfo->hdr.length);
+
+	write(ctx->exportfd, descriptor, des_len);
+
+	/* The Data */
+	if (ctx->value_size > 0)
+		write(ctx->exportfd, ctx->value, ctx->value_size);
+
 	return 0;
 }
diff --git a/src/authvar_context.h b/src/authvar_context.h
index 9647849..7e3c696 100644
--- a/src/authvar_context.h
+++ b/src/authvar_context.h
@@ -38,7 +38,7 @@ typedef struct {
 	char *exportfile;
 	int   exportfd;
 
-	efi_var_auth_2_t des;
+	win_cert_uefi_guid_t *authinfo;
 
 	cms_context *cms_ctx;
 } authvar_context;
-- 
1.8.4.5


From 6a5b541d6fc333aa30ec9e80ff82ea4df318e136 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 3 Jun 2014 17:56:57 +0800
Subject: [PATCH 17/31] authvar: collect everything in buffer and write it
 later

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar_context.c | 38 ++++++++++++++++++++++++++------------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/src/authvar_context.c b/src/authvar_context.c
index fdc6d7e..7bfb0d1 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -216,29 +216,43 @@ int
 write_authvar(authvar_context *ctx)
 {
 	efi_var_auth_2_t *descriptor;
-	size_t des_len;
+	void *buffer, *ptr;
+	size_t buf_len, des_len, remain;
+	ssize_t wlen;
 
 	if (!ctx->authinfo)
 		cmsreterr(-1, ctx->cms_ctx, "Not a valid authvar");
 
-	/* The attributes of the variable */
-	write(ctx->exportfd, &ctx->attr, sizeof(ctx->attr));
-
-	/* The EFI_VARIABLE_AUTHENTICATION_2 */
 	des_len = sizeof(efi_var_auth_2_t) + ctx->authinfo->hdr.length -
 		  sizeof(win_cert_uefi_guid_t) + 1;
-	descriptor = calloc(des_len, 1);
-	if (!descriptor)
-		cmsreterr(-1, ctx->cms_ctx, "could not allocate descriptor");
+	buf_len = 4 + des_len + ctx->value_size;
+
+	buffer = calloc(buf_len, 1);
+	if (!buffer)
+		cmsreterr(-1, ctx->cms_ctx, "could not allocate buffer");
+	ptr = buffer;
 
+	/* The attribute of the variable */
+	memcpy(ptr, &ctx->attr, sizeof(ctx->attr));
+	ptr += sizeof(ctx->attr);
+
+	/* EFI_VARIABLE_AUTHENTICATION_2 */
+	descriptor = (efi_var_auth_2_t *)ptr;
 	memcpy(&descriptor->timestamp, &ctx->timestamp, sizeof(efi_time_t));
 	memcpy(&descriptor->authinfo, ctx->authinfo, ctx->authinfo->hdr.length);
+	ptr += des_len;
 
-	write(ctx->exportfd, descriptor, des_len);
-
-	/* The Data */
+	/* Data */
 	if (ctx->value_size > 0)
-		write(ctx->exportfd, ctx->value, ctx->value_size);
+		memcpy(ptr, ctx->value, ctx->value_size);
+
+	remain = buf_len;
+	do {
+		wlen = write(ctx->exportfd, buffer, remain);
+		if (wlen < 0)
+			cmsreterr(-1, ctx->cms_ctx, "failed to write authvar");
+		remain -= wlen;
+	} while (remain > 0);
 
 	return 0;
 }
-- 
1.8.4.5


From b522876182bf87220da5e40c53e0b38c0f5f14d4 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 3 Jun 2014 18:23:09 +0800
Subject: [PATCH 18/31] authvar: parse the timestamp string

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/src/authvar.c b/src/authvar.c
index 4fb3145..5923e86 100644
--- a/src/authvar.c
+++ b/src/authvar.c
@@ -247,21 +247,23 @@ static void
 set_timestamp(authvar_context *ctx, const char *time_str)
 {
 	time_t t;
-	struct tm *tm;
+	struct tm tm;
 
+	memset(&tm, 0, sizeof(struct tm));
 	if (time_str) {
-		/* TODO parse the string */
+		/* Accept the string like "2001-11-12 18:31:01" */
+		strptime(time_str, "%Y-%m-%d %H:%M:%S", &tm);
 	} else {
 		time(&t);
-		tm = gmtime(&t);
+		gmtime_r(&t, &tm);
 	}
 
-	ctx->timestamp.year = tm->tm_year + 1900;
-	ctx->timestamp.month = tm->tm_mon + 1;
-	ctx->timestamp.day = tm->tm_mday;
-	ctx->timestamp.hour = tm->tm_hour;
-	ctx->timestamp.minute = tm->tm_min;
-	ctx->timestamp.second = tm->tm_sec;
+	ctx->timestamp.year = tm.tm_year + 1900;
+	ctx->timestamp.month = tm.tm_mon + 1;
+	ctx->timestamp.day = tm.tm_mday;
+	ctx->timestamp.hour = tm.tm_hour;
+	ctx->timestamp.minute = tm.tm_min;
+	ctx->timestamp.second = tm.tm_sec;
 
 	ctx->timestamp.pad1 = 0;
 	ctx->timestamp.nanosecond = 0;
-- 
1.8.4.5


From f376705cefa78845f55d070cf3ac060567636576 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 3 Jun 2014 18:25:22 +0800
Subject: [PATCH 19/31] authvar: adjust timestamp for append

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/authvar.c b/src/authvar.c
index 5923e86..b333139 100644
--- a/src/authvar.c
+++ b/src/authvar.c
@@ -423,7 +423,8 @@ int main(int argc, char *argv[])
 		check_value(ctxp, 1);
 		open_input(ctxp);
 		ctxp->attr |= EFI_VARIABLE_APPEND_WRITE;
-		/* TODO Set Day and Month to 0 */
+		ctxp->timestamp.day = 0;
+		ctxp->timestamp.month = 0;
 
 		rc = generate_descriptor(ctxp);
 		if (rc < 0) {
-- 
1.8.4.5


From 9ef7442bbe8f520b61c2397cdabd577401130fbb Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 5 Jun 2014 14:50:20 +0800
Subject: [PATCH 20/31] authvar: modify the content of SignedData for authvar

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar_context.c |  7 +----
 src/content_info.c    | 28 +++++++++++++++++
 src/content_info.h    |  1 +
 src/signed_data.c     | 85 ++++++++++++++++++++++++++++++++++++++++++++++++---
 src/signed_data.h     |  1 +
 src/signer_info.c     | 45 +++++++++++++++++++++++++++
 src/signer_info.h     |  1 +
 7 files changed, 158 insertions(+), 10 deletions(-)

diff --git a/src/authvar_context.c b/src/authvar_context.c
index 7bfb0d1..95d684c 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -131,11 +131,6 @@ generate_buffer_digest(cms_context *cms, uint8_t *buf, size_t buf_len)
 
 	cms->digests = digests;
 	cms->digests[0].pk11ctx = NULL;
-	/* XXX sure seems like we should be freeing it here,
-	 * but that's segfaulting, and we know it'll get
-	 * cleaned up with PORT_FreeArena a couple of lines
-	 * down.
-	 */
 	cms->digests[0].pe_digest = digest;
 	cms->selected_digest = 0;
 
@@ -193,7 +188,7 @@ generate_descriptor(authvar_context *ctx)
 
 	/* sign the digest */
 	memset(&sd_der, '\0', sizeof(sd_der));
-	rc = generate_spc_signed_data(ctx->cms_ctx, &sd_der);
+	rc = generate_authvar_signed_data(ctx->cms_ctx, &sd_der);
 	if (rc < 0)
 		cmsreterr(-1, ctx->cms_ctx, "could not create signed data");
 
diff --git a/src/content_info.c b/src/content_info.c
index 1e1fb0e..bae8f8a 100644
--- a/src/content_info.c
+++ b/src/content_info.c
@@ -388,6 +388,34 @@ generate_spc_content_info(cms_context *cms, SpcContentInfo *cip)
 	return 0;
 }
 
+int
+generate_authvar_content_info(cms_context *cms, SpcContentInfo *cip)
+{
+	SECOidData *oid;
+
+	if (!cip)
+		return -1;
+
+	SpcContentInfo ci;
+	memset(&ci, '\0', sizeof (ci));
+
+	oid = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
+	if (oid == NULL) {
+		cms->log(cms, LOG_ERR, "could not get OID for "
+			"SEC_OID_PKCS7_DATA");
+		return -1;
+	}
+	if (SECITEM_CopyItem(cms->arena, &ci.contentType, &oid->oid))
+		return -1;
+
+	ci.content.len = 0;
+	ci.content.data = NULL;
+
+	memcpy(cip, &ci, sizeof *cip);
+
+	return 0;
+}
+
 void
 free_spc_content_info(cms_context *cms, SpcContentInfo *cip)
 {
diff --git a/src/content_info.h b/src/content_info.h
index 2c96135..d0cc5a1 100644
--- a/src/content_info.h
+++ b/src/content_info.h
@@ -35,5 +35,6 @@ extern const SEC_ASN1Template SpcContentInfoTemplate[];
 extern int generate_spc_content_info(cms_context *cms, SpcContentInfo *cip);
 extern void free_spc_content_info(cms_context *cms, SpcContentInfo *cip);
 extern int register_content_info(void);
+extern int generate_authvar_content_info(cms_context *cms, SpcContentInfo *cip);
 
 #endif /* CONTENT_INFO_H */
diff --git a/src/signed_data.c b/src/signed_data.c
index 2f4b498..2fa1cdd 100644
--- a/src/signed_data.c
+++ b/src/signed_data.c
@@ -121,11 +121,17 @@ generate_certificate_list(cms_context *cms, SECItem ***certificate_list_p)
 	return 0;
 }
 
+typedef enum {
+	PE_SIGNER_INFO,
+	AUTHVAR_SIGNER_INFO,
+	END_SIGNER_INFO_LIST
+} SignerInfoType;
+
 int
-generate_signerInfo_list(cms_context *cms, SpcSignerInfo ***signerInfo_list_p)
+generate_signerInfo_list(cms_context *cms, SpcSignerInfo ***signerInfo_list_p, SignerInfoType type)
 {
 	SpcSignerInfo **signerInfo_list;
-	int err;
+	int err, rc;
 
 	if (!signerInfo_list_p)
 		return -1;
@@ -142,7 +148,13 @@ generate_signerInfo_list(cms_context *cms, SpcSignerInfo ***signerInfo_list_p)
 		goto err_list;
 	}
 
-	if (generate_spc_signer_info(cms, signerInfo_list[0]) < 0) {
+	if (type == PE_SIGNER_INFO)
+		rc = generate_spc_signer_info(cms, signerInfo_list[0]);
+	else if (type == AUTHVAR_SIGNER_INFO)
+		rc = generate_authvar_signer_info(cms, signerInfo_list[0]);
+	else
+		goto err_item;
+	if (rc < 0) {
 		err = PORT_GetError();
 		goto err_item;
 	}
@@ -282,7 +294,72 @@ generate_spc_signed_data(cms_context *cms, SECItem *sdp)
 
 	sd.crls = NULL;
 
-	if (generate_signerInfo_list(cms, &sd.signerInfos) < 0) {
+	if (generate_signerInfo_list(cms, &sd.signerInfos, PE_SIGNER_INFO) < 0) {
+		PORT_ArenaRelease(cms->arena, mark);
+		return -1;
+	}
+
+	SECItem encoded = { 0, };
+	if (SEC_ASN1EncodeItem(cms->arena, &encoded, &sd, SignedDataTemplate)
+			== NULL) {
+		save_port_err(PORT_ArenaRelease(cms->arena, mark));
+		cmsreterr(-1, cms, "could not encode SignedData");
+	}
+
+	ContentInfo sdw;
+	memset(&sdw, '\0', sizeof (sdw));
+
+	SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS7_SIGNED_DATA);
+
+	memcpy(&sdw.contentType, &oid->oid, sizeof (sdw.contentType));
+	memcpy(&sdw.content, &encoded, sizeof (sdw.content));
+
+	SECItem wrapper = { 0, };
+	if (SEC_ASN1EncodeItem(cms->arena, &wrapper, &sdw,
+			ContentInfoTemplate) == NULL) {
+		save_port_err(PORT_ArenaRelease(cms->arena, mark));
+		cmsreterr(-1, cms, "could not encode SignedData");
+	}
+
+	memcpy(sdp, &wrapper, sizeof(*sdp));
+	PORT_ArenaUnmark(cms->arena, mark);
+	return 0;
+}
+
+int
+generate_authvar_signed_data(cms_context *cms, SECItem *sdp)
+{
+	SignedData sd;
+
+	if (!sdp)
+		return -1;
+
+	memset(&sd, '\0', sizeof (sd));
+	void *mark = PORT_ArenaMark(cms->arena);
+
+	if (SEC_ASN1EncodeInteger(cms->arena, &sd.version, 1) == NULL) {
+		save_port_err(PORT_ArenaRelease(cms->arena, mark));
+		cmsreterr(-1, cms, "could not encode integer");
+	}
+
+	if (generate_algorithm_id_list(cms, &sd.algorithms) < 0) {
+		PORT_ArenaRelease(cms->arena, mark);
+		return -1;
+	}
+
+	if (generate_authvar_content_info(cms, &sd.cinfo) < 0) {
+		PORT_ArenaRelease(cms->arena, mark);
+		return -1;
+	}
+
+	if (generate_certificate_list(cms, &sd.certificates) < 0) {
+		PORT_ArenaRelease(cms->arena, mark);
+		return -1;
+	}
+
+	sd.crls = NULL;
+
+	if (generate_signerInfo_list(cms, &sd.signerInfos, AUTHVAR_SIGNER_INFO) < 0) {
 		PORT_ArenaRelease(cms->arena, mark);
 		return -1;
 	}
diff --git a/src/signed_data.h b/src/signed_data.h
index 7e438fc..645f15e 100644
--- a/src/signed_data.h
+++ b/src/signed_data.h
@@ -20,5 +20,6 @@
 #define SIGNED_DATA_H 1
 
 extern int generate_spc_signed_data(cms_context *cms, SECItem *sdp);
+extern int generate_authvar_signed_data(cms_context *cms, SECItem *sdp);
 
 #endif /* SIGNED_DATA_H */
diff --git a/src/signer_info.c b/src/signer_info.c
index 0a0621e..ef05b7c 100644
--- a/src/signer_info.c
+++ b/src/signer_info.c
@@ -400,3 +400,48 @@ generate_spc_signer_info(cms_context *cms, SpcSignerInfo *sip)
 err:
 	return -1;
 }
+
+int
+generate_authvar_signer_info(cms_context *cms, SpcSignerInfo *sip)
+{
+	SpcSignerInfo si;
+	SECItem *authvar_digest;
+
+	if (!sip)
+		return -1;
+
+	memset(&si, '\0', sizeof (si));
+
+	if (SEC_ASN1EncodeInteger(cms->arena, &si.CMSVersion, 1) == NULL) {
+		cms->log(cms, LOG_ERR, "could not encode CMSVersion: %s",
+			PORT_ErrorToString(PORT_GetError()));
+		goto err;
+	}
+
+	si.sid.signerType = signerTypeIssuerAndSerialNumber;
+	si.sid.signerValue.iasn.issuer = cms->cert->derIssuer;
+	si.sid.signerValue.iasn.serial = cms->cert->serialNumber;
+
+	if (generate_algorithm_id(cms, &si.digestAlgorithm,
+			digest_get_digest_oid(cms)) < 0)
+		goto err;
+
+	si.signedAttrs.len = 0;
+	si.signedAttrs.data = NULL;
+
+	authvar_digest = cms->digests[0].pe_digest;
+	if (sign_blob(cms, &si.signature, authvar_digest) < 0)
+		goto err;
+
+	if (generate_algorithm_id(cms, &si.signatureAlgorithm,
+				digest_get_encryption_oid(cms)) < 0)
+		goto err;
+
+	si.unsignedAttrs.len = 0;
+	si.unsignedAttrs.data = NULL;
+
+	memcpy(sip, &si, sizeof(si));
+	return 0;
+err:
+	return -1;
+}
diff --git a/src/signer_info.h b/src/signer_info.h
index f1c9828..724aa7d 100644
--- a/src/signer_info.h
+++ b/src/signer_info.h
@@ -63,5 +63,6 @@ extern SEC_ASN1Template SpcSignerInfoTemplate[];
 
 extern int generate_signed_attributes(cms_context *cms, SECItem *sattrs);
 extern int generate_spc_signer_info(cms_context *cms, SpcSignerInfo *sip);
+extern int generate_authvar_signer_info(cms_context *cms, SpcSignerInfo *sip);
 
 #endif /* SIGNER_INFO */
-- 
1.8.4.5


From 7064f04c884fc62bf85b0a03fbc86a078037f03a Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Mon, 9 Jun 2014 10:30:00 +0800
Subject: [PATCH 21/31] authvar: fix USC2 conversion and the length of the
 header

Also truncate the export file.

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar_context.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/src/authvar_context.c b/src/authvar_context.c
index 95d684c..8344e82 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -152,6 +152,8 @@ generate_descriptor(authvar_context *ctx)
 	char *name_ptr;
 	uint8_t *buf, *ptr;
 	size_t buf_len;
+	uint64_t offset;
+	efi_char16_t *wptr;
 	int rc;
 
 	/* prepare buffer for varname, vendor_guid, attr, timestamp, value */
@@ -164,11 +166,11 @@ generate_descriptor(authvar_context *ctx)
 	ptr = buf;
 	name_ptr = ctx->name;
 	while (*name_ptr != '\0') {
-		ptr++;
-		*ptr = *name_ptr;
+		wptr = (efi_char16_t *)ptr;
+		*wptr = *name_ptr;
 		name_ptr++;
+		ptr += sizeof(efi_char16_t);
 	}
-	ptr++;
 
 	memcpy(ptr, &ctx->guid, sizeof(efi_guid_t));
 	ptr += sizeof(efi_guid_t);
@@ -192,11 +194,12 @@ generate_descriptor(authvar_context *ctx)
 	if (rc < 0)
 		cmsreterr(-1, ctx->cms_ctx, "could not create signed data");
 
-	authinfo = calloc(sizeof(win_cert_uefi_guid_t) + sd_der.len, 1);
+	offset = (uint64_t) &((win_cert_uefi_guid_t *)0)->data;
+	authinfo = calloc(offset + sd_der.len, 1);
 	if (!authinfo)
 		cmsreterr(-1, ctx->cms_ctx, "could not allocate authinfo");
 
-	authinfo->hdr.length = sd_der.len + sizeof(win_cert_uefi_guid_t) - 1;
+	authinfo->hdr.length = sd_der.len + (uint32_t)offset;
 	authinfo->hdr.revision = WIN_CERT_REVISION_2_0;
 	authinfo->hdr.cert_type = WIN_CERT_TYPE_EFI_GUID;
 	authinfo->type = (efi_guid_t)EFI_CERT_TYPE_PKCS7_GUID;
@@ -219,8 +222,8 @@ write_authvar(authvar_context *ctx)
 		cmsreterr(-1, ctx->cms_ctx, "Not a valid authvar");
 
 	des_len = sizeof(efi_var_auth_2_t) + ctx->authinfo->hdr.length -
-		  sizeof(win_cert_uefi_guid_t) + 1;
-	buf_len = 4 + des_len + ctx->value_size;
+		  sizeof(win_cert_uefi_guid_t);
+	buf_len = sizeof(ctx->attr) + des_len + ctx->value_size;
 
 	buffer = calloc(buf_len, 1);
 	if (!buffer)
@@ -241,6 +244,10 @@ write_authvar(authvar_context *ctx)
 	if (ctx->value_size > 0)
 		memcpy(ptr, ctx->value, ctx->value_size);
 
+	/* TODO skip ftruncate while writing a EFI variable in sysfs */
+	ftruncate(ctx->exportfd, buf_len);
+	lseek(ctx->exportfd, 0, SEEK_SET);
+
 	remain = buf_len;
 	do {
 		wlen = write(ctx->exportfd, buffer, remain);
-- 
1.8.4.5


From 9906a3cc8efd133edcc57aeb582b22c92011d7f1 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 10 Jun 2014 12:13:04 +0800
Subject: [PATCH 22/31] authvar: sign the right content

We don't have to calculate the digest first.

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar_context.c | 77 ++++++---------------------------------------------
 src/cms_common.c      |  5 ++++
 src/cms_common.h      |  3 ++
 src/signer_info.c     |  7 +++--
 4 files changed, 20 insertions(+), 72 deletions(-)

diff --git a/src/authvar_context.c b/src/authvar_context.c
index 8344e82..78bacc4 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -81,69 +81,6 @@ authvar_context_fini(authvar_context *ctx)
 	}
 }
 
-static int
-generate_buffer_digest(cms_context *cms, uint8_t *buf, size_t buf_len)
-{
-	struct digest *digests = NULL;
-	SECItem *digest = NULL;
-
-	if (cms->digests) {
-		digests = cms->digests;
-	} else {
-		digests = PORT_ZAlloc(sizeof (struct digest));
-		if (digests == NULL)
-			cmsreterr(-1, cms, "could not allocate digest context");
-	}
-
-	digests[0].pk11ctx = PK11_CreateDigestContext(SEC_OID_SHA256);
-	if (!digests[0].pk11ctx) {
-		cms->log(cms, LOG_ERR, "%s:%s:%d could not create "
-			"digest context: %s",
-			__FILE__, __func__, __LINE__,
-			PORT_ErrorToString(PORT_GetError()));
-		goto err;
-	}
-
-	PK11_DigestBegin(digests[0].pk11ctx);
-	PK11_DigestOp(digests[0].pk11ctx, buf, buf_len);
-
-	digest = PORT_ArenaZAlloc(cms->arena, sizeof (SECItem));
-	if (!digest) {
-		cms->log(cms, LOG_ERR, "%s:%s:%d could not allocate "
-			"memory: %s", __FILE__, __func__, __LINE__,
-			PORT_ErrorToString(PORT_GetError()));
-		goto err;
-	}
-
-	digest->type = siBuffer;
-	digest->len = 32;
-	digest->data = PORT_ArenaZAlloc(cms->arena, 32);
-	if (!digest->data) {
-		cms->log(cms, LOG_ERR, "%s:%s:%d could not allocate "
-			"memory: %s", __FILE__, __func__, __LINE__,
-			PORT_ErrorToString(PORT_GetError()));
-		goto err;
-	}
-
-	PK11_DigestFinal(digests[0].pk11ctx, digest->data, &digest->len, 32);
-	PK11_Finalize(digests[0].pk11ctx);
-	PK11_DestroyContext(digests[0].pk11ctx, PR_TRUE);
-
-	cms->digests = digests;
-	cms->digests[0].pk11ctx = NULL;
-	cms->digests[0].pe_digest = digest;
-	cms->selected_digest = 0;
-
-	return 0;
-err:
-	if (digests[0].pk11ctx)
-		PK11_DestroyContext(digests[0].pk11ctx, PR_TRUE);
-
-	free(digests);
-
-	return -1;
-}
-
 int
 generate_descriptor(authvar_context *ctx)
 {
@@ -157,8 +94,8 @@ generate_descriptor(authvar_context *ctx)
 	int rc;
 
 	/* prepare buffer for varname, vendor_guid, attr, timestamp, value */
-	buf_len = strlen(ctx->name)*2 + sizeof(efi_guid_t) + sizeof(uint32_t) +
-		  sizeof(efi_time_t) + ctx->value_size;
+	buf_len = strlen(ctx->name)*sizeof(efi_char16_t) + sizeof(efi_guid_t) +
+		  sizeof(uint32_t) + sizeof(efi_time_t) + ctx->value_size;
 	buf = calloc(1, buf_len);
 	if (!buf)
 		return -1;
@@ -183,10 +120,12 @@ generate_descriptor(authvar_context *ctx)
 
 	memcpy(ptr, ctx->value, ctx->value_size);
 
-	if (generate_buffer_digest(ctx->cms_ctx, buf, buf_len) < 0) {
-		xfree(buf);
-		return -1;
-	}
+	ctx->cms_ctx->authbuf_len = buf_len;
+	ctx->cms_ctx->authbuf = buf;
+
+	/* XXX set the value to get SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION
+	   from digest_get_signature_oid(). */
+	ctx->cms_ctx->selected_digest = 0;
 
 	/* sign the digest */
 	memset(&sd_der, '\0', sizeof(sd_der));
diff --git a/src/cms_common.c b/src/cms_common.c
index 8f035f7..9c99f6a 100644
--- a/src/cms_common.c
+++ b/src/cms_common.c
@@ -218,6 +218,11 @@ cms_context_fini(cms_context *cms)
 	xfree(cms->signatures);
 	cms->num_signatures = 0;
 
+	if (cms->authbuf) {
+		xfree(cms->authbuf);
+		cms->authbuf_len = 0;
+	}
+
 	PORT_FreeArena(cms->arena, PR_TRUE);
 	memset(cms, '\0', sizeof(*cms));
 	xfree(cms);
diff --git a/src/cms_common.h b/src/cms_common.h
index 019ae40..0d9893f 100644
--- a/src/cms_common.h
+++ b/src/cms_common.h
@@ -83,6 +83,9 @@ typedef struct cms_context {
 	int num_signatures;
 	SECItem **signatures;
 
+	int authbuf_len;
+	void *authbuf;
+
 	cms_common_logger log;
 	void *log_priv;
 } cms_context;
diff --git a/src/signer_info.c b/src/signer_info.c
index ef05b7c..afa00e2 100644
--- a/src/signer_info.c
+++ b/src/signer_info.c
@@ -405,7 +405,7 @@ int
 generate_authvar_signer_info(cms_context *cms, SpcSignerInfo *sip)
 {
 	SpcSignerInfo si;
-	SECItem *authvar_digest;
+	SECItem buf;
 
 	if (!sip)
 		return -1;
@@ -429,8 +429,9 @@ generate_authvar_signer_info(cms_context *cms, SpcSignerInfo *sip)
 	si.signedAttrs.len = 0;
 	si.signedAttrs.data = NULL;
 
-	authvar_digest = cms->digests[0].pe_digest;
-	if (sign_blob(cms, &si.signature, authvar_digest) < 0)
+	buf.len = cms->authbuf_len;
+	buf.data = cms->authbuf;
+	if (sign_blob(cms, &si.signature, &buf) < 0)
 		goto err;
 
 	if (generate_algorithm_id(cms, &si.signatureAlgorithm,
-- 
1.8.4.5


From d69d64cc43c630446eed0e851cf22a4b512780fb Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 10 Jun 2014 12:25:07 +0800
Subject: [PATCH 23/31] authvar: don't exit if no value for CLEAR

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/authvar.c b/src/authvar.c
index b333139..4a9fcac 100644
--- a/src/authvar.c
+++ b/src/authvar.c
@@ -84,8 +84,7 @@ check_value(authvar_context *ctx, int needed)
 		if (needed)
 			fprintf(stderr, "authvar: no value specified.\n");
 		else
-			fprintf(stderr,
-				"authvar: command does not take a value.\n");
+			return;
 		exit(1);
 	}
 	if (ctx->value && *ctx->value && ctx->valuefile && *ctx->valuefile) {
-- 
1.8.4.5


From 301e729061406bd4388febc9737c475f2ff873dc Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 10 Jun 2014 12:32:05 +0800
Subject: [PATCH 24/31] authvar: mark "import" as unimplemented

Will do it later...

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/authvar.c b/src/authvar.c
index 4a9fcac..dfd40f2 100644
--- a/src/authvar.c
+++ b/src/authvar.c
@@ -409,8 +409,6 @@ int main(int argc, char *argv[])
 		action |= SIGN;
 	}
 
-	print_flag_name(stdout, action);
-	printf("\n");
 	switch (action) {
 	case NO_FLAGS:
 		fprintf(stderr, "authvar: No action specified\n");
@@ -462,7 +460,7 @@ int main(int argc, char *argv[])
 		break;
 	case IMPORT|SET:
 	case IMPORT|SIGN|SET:
-
+		fprintf(stderr, "authvar: not implemented\n");
 	case IMPORT|SIGN|EXPORT:
 	default:
 		fprintf(stderr, "authvar: invalid flags: ");
-- 
1.8.4.5


From c756c108fce07576a67fc4a2719cad7639566604 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 10 Jun 2014 12:48:43 +0800
Subject: [PATCH 25/31] authvar: check the export file

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar.c         | 4 ++++
 src/authvar_context.c | 7 ++++---
 src/authvar_context.h | 1 +
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/authvar.c b/src/authvar.c
index dfd40f2..7e0f54c 100644
--- a/src/authvar.c
+++ b/src/authvar.c
@@ -156,6 +156,10 @@ open_output(authvar_context *ctx)
 
 	if (!ctx->exportfile) {
 		generate_efivars_filename(ctx);
+		ctx->to_firmware = 1;
+	} else if (access(ctx->exportfile, F_OK) == 0) {
+		fprintf(stderr, "authvar: \"%s\" exists\n", ctx->exportfile);
+		exit(1);
 	}
 
 	flags = O_CREAT|O_RDWR|O_CLOEXEC;
diff --git a/src/authvar_context.c b/src/authvar_context.c
index 78bacc4..3c82225 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -183,9 +183,10 @@ write_authvar(authvar_context *ctx)
 	if (ctx->value_size > 0)
 		memcpy(ptr, ctx->value, ctx->value_size);
 
-	/* TODO skip ftruncate while writing a EFI variable in sysfs */
-	ftruncate(ctx->exportfd, buf_len);
-	lseek(ctx->exportfd, 0, SEEK_SET);
+	if (!ctx->to_firmware) {
+		ftruncate(ctx->exportfd, buf_len);
+		lseek(ctx->exportfd, 0, SEEK_SET);
+	}
 
 	remain = buf_len;
 	do {
diff --git a/src/authvar_context.h b/src/authvar_context.h
index 7e3c696..e9250dd 100644
--- a/src/authvar_context.h
+++ b/src/authvar_context.h
@@ -37,6 +37,7 @@ typedef struct {
 
 	char *exportfile;
 	int   exportfd;
+	uint8_t to_firmware;
 
 	win_cert_uefi_guid_t *authinfo;
 
-- 
1.8.4.5


From 6ec83a5cb8710082b9761e46e54f52c07edff6a5 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 11 Jun 2014 15:45:03 +0800
Subject: [PATCH 26/31] efisiglist: adjust the signature size

I forgot the size of the owner GUID.

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/siglist.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/siglist.c b/src/siglist.c
index e001493..e6a9817 100644
--- a/src/siglist.c
+++ b/src/siglist.c
@@ -141,7 +141,7 @@ signature_list_add_sig(signature_list *sl, efi_guid_t owner,
 
 	if (memcmp(&sl->SignatureType, &x509_guid, sizeof (efi_guid_t)) == 0) {
 		if (sigsize > sl->SignatureSize)
-			resize_entries(sl, sigsize);
+			resize_entries(sl, sigsize + sizeof (efi_guid_t));
 	} else if (sigsize != get_sig_type_size(sl->SignatureType)) {
 		fprintf(stderr, "sigsize: %d sl->SignatureSize: %d\n",
 			sigsize, sl->SignatureSize);
-- 
1.8.4.5


From 6e284c09d1c84900cfcbb237e467544667568a87 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 12 Jun 2014 10:41:50 +0800
Subject: [PATCH 27/31] Install pesigcheck, authvar, and efisiglist

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/Makefile b/src/Makefile
index 0aa13a1..9d14d81 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -84,7 +84,9 @@ install :
 	$(INSTALL) -m 755 pesign $(INSTALLROOT)$(PREFIX)/bin/
 	$(INSTALL) -m 755 client $(INSTALLROOT)$(PREFIX)/bin/pesign-client
 	$(INSTALL) -m 755 efikeygen $(INSTALLROOT)$(PREFIX)/bin/
-	#$(INSTALL) -m 755 pesigcheck $(INSTALLROOT)$(PREFIX)/bin/
+	$(INSTALL) -m 755 pesigcheck $(INSTALLROOT)$(PREFIX)/bin/
+	$(INSTALL) -m 755 authvar $(INSTALLROOT)$(PREFIX)/bin/
+	$(INSTALL) -m 755 efisiglist $(INSTALLROOT)$(PREFIX)/bin/
 	$(INSTALL) -d -m 755 $(INSTALLROOT)/etc/popt.d/
 	$(INSTALL) -m 644 pesign.popt $(INSTALLROOT)/etc/popt.d/
 	$(INSTALL) -d -m 755 $(INSTALLROOT)/usr/share/man/man1/
-- 
1.8.4.5


From afe4aa85503eae83c073c11f8b2fbcb266093726 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 8 Jan 2014 17:41:20 +0800
Subject: [PATCH 28/31] pesigcheck: choose the proper digest algorithm

Check the digest algorithm in SignerInfo before calculate/compare
the digest

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/certdb.c     | 44 +++++++++++++++++++++++++++++++++++++++++---
 src/certdb.h     |  2 ++
 src/pesigcheck.c | 17 +++++++++++++++--
 3 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/src/certdb.c b/src/certdb.c
index 24c319b..4239eff 100644
--- a/src/certdb.c
+++ b/src/certdb.c
@@ -29,6 +29,7 @@
 #include <cert.h>
 #include <pkcs7t.h>
 #include <pk11pub.h>
+#include <sechash.h>
 
 #include "pesigcheck.h"
 
@@ -243,6 +244,32 @@ check_db_hash(db_specifier which, pesigcheck_context *ctx)
 	return check_db(which, ctx, check_hash, NULL, 0);
 }
 
+SECOidTag
+find_signer_digest_tag(SEC_PKCS7ContentInfo *cinfo)
+{
+	SEC_PKCS7SignedData *sdp;
+	SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
+	SECOidTag digest_tag;
+
+	sdp = cinfo->content.signedData;
+	signerinfos = sdp->signerInfos;
+
+	if ((signerinfos == NULL) || (signerinfos[0] == NULL)) {
+		return SEC_OID_UNKNOWN;
+	}
+
+	/* The authenticode signature only supports one signer. */
+	if (signerinfos[1] != NULL) {
+		return SEC_OID_UNKNOWN;
+	}
+
+	signerinfo = signerinfos[0];
+
+	digest_tag = SECOID_FindOIDTag(&(signerinfo->digestAlg.algorithm));
+
+	return digest_tag;
+}
+
 static db_status
 check_cert(pesigcheck_context *ctx, SECItem *sig, efi_guid_t *sigtype,
 	   SECItem *pkcs7sig)
@@ -252,6 +279,9 @@ check_cert(pesigcheck_context *ctx, SECItem *sig, efi_guid_t *sigtype,
 	CERTCertTrust trust;
 	SECItem *content, *digest = NULL;
 	PK11Context *pk11ctx = NULL;
+	SECOidTag digest_tag;
+	HASH_HashType hash_type;
+	uint32_t hash_size;
 	SECOidData *oid;
 	PRBool result;
 	SECStatus rv;
@@ -268,13 +298,21 @@ check_cert(pesigcheck_context *ctx, SECItem *sig, efi_guid_t *sigtype,
 		goto out;
 
 	/* Generate the digest of contentInfo */
-	/* XXX support only sha256 for now */
-	digest = SECITEM_AllocItem(NULL, NULL, 32);
+	digest_tag = find_signer_digest_tag(cinfo);
+	if (digest_tag == SEC_OID_UNKNOWN)
+		goto out;
+
+	hash_type = HASH_GetHashTypeByOidTag(digest_tag);
+	if (hash_type == HASH_AlgNULL)
+		goto out;
+
+	hash_size = HASH_ResultLen(hash_type);
+	digest = SECITEM_AllocItem(NULL, NULL, hash_size);
 	if (digest == NULL)
 		goto out;
 
 	content = cinfo->content.signedData->contentInfo.content.data;
-	oid = SECOID_FindOIDByTag(SEC_OID_SHA256);
+	oid = SECOID_FindOIDByTag(digest_tag);
 	if (oid == NULL)
 		goto out;
 	pk11ctx = PK11_CreateDigestContext(oid->offset);
diff --git a/src/certdb.h b/src/certdb.h
index ccf3c87..6aaa58b 100644
--- a/src/certdb.h
+++ b/src/certdb.h
@@ -50,4 +50,6 @@ extern int add_cert_db(pesigcheck_context *ctx, const char *filename);
 extern int add_cert_dbx(pesigcheck_context *ctx, const char *filename);
 extern int add_cert_file(pesigcheck_context *ctx, const char *filename);
 
+extern SECOidTag find_signer_digest_tag(SEC_PKCS7ContentInfo *cinfo);
+
 #endif /* CERTDB_H */
diff --git a/src/pesigcheck.c b/src/pesigcheck.c
index 9cf33be..f173121 100644
--- a/src/pesigcheck.c
+++ b/src/pesigcheck.c
@@ -93,6 +93,7 @@ cert_matches_digest(pesigcheck_context *ctx, void *data, ssize_t datalen)
 	SECItem sig, *pe_digest, *content;
 	uint8_t *digest;
 	SEC_PKCS7ContentInfo *cinfo = NULL;
+	SECOidTag digest_tag;
 	int ret = -1;
 
 	sig.data = data;
@@ -105,9 +106,21 @@ cert_matches_digest(pesigcheck_context *ctx, void *data, ssize_t datalen)
 	if (!SEC_PKCS7ContentIsSigned(cinfo))
 		goto out;
 
-	/* TODO Find out the digest type in spc_content */
-	pe_digest = ctx->cms_ctx->digests[0].pe_digest;
+	/* The file digest algorithm is the same as the signerinfo digest
+	    algorithm. Utilize the parsed PKC#7 content instead of parsing
+	    SpcContentInfo */
+	digest_tag = find_signer_digest_tag(cinfo);
+
+	if (digest_tag == SEC_OID_SHA256)
+		pe_digest = ctx->cms_ctx->digests[0].pe_digest;
+	else if (digest_tag == SEC_OID_SHA1)
+		pe_digest = ctx->cms_ctx->digests[1].pe_digest;
+	else
+		goto out;
+
 	content = cinfo->content.signedData->contentInfo.content.data;
+	if (content->len < pe_digest->len)
+		goto out;
 	digest = content->data + content->len - pe_digest->len;
 	if (memcmp(pe_digest->data, digest, pe_digest->len) != 0)
 		goto out;
-- 
1.8.4.5


From ef7b38cdb8a1f23cd3cfcbe19835677a9eec2a03 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 12 Jun 2014 11:07:24 +0800
Subject: [PATCH 29/31] make gcc happy

---
 src/authvar_context.c | 3 ++-
 src/signed_data.c     | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/authvar_context.c b/src/authvar_context.c
index 3c82225..5444d3a 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -184,7 +184,8 @@ write_authvar(authvar_context *ctx)
 		memcpy(ptr, ctx->value, ctx->value_size);
 
 	if (!ctx->to_firmware) {
-		ftruncate(ctx->exportfd, buf_len);
+		if (ftruncate(ctx->exportfd, buf_len) < 0)
+			return -1;
 		lseek(ctx->exportfd, 0, SEEK_SET);
 	}
 
diff --git a/src/signed_data.c b/src/signed_data.c
index 2fa1cdd..5371a9c 100644
--- a/src/signed_data.c
+++ b/src/signed_data.c
@@ -133,6 +133,8 @@ generate_signerInfo_list(cms_context *cms, SpcSignerInfo ***signerInfo_list_p, S
 	SpcSignerInfo **signerInfo_list;
 	int err, rc;
 
+	err = 0;
+
 	if (!signerInfo_list_p)
 		return -1;
 
-- 
1.8.4.5


From 741515622a6864668db35318bcb2703d1a8d3883 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 12 Jun 2014 11:20:24 +0800
Subject: [PATCH 30/31] authvar: fix the type cast for 32bit systems

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar_context.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/authvar_context.c b/src/authvar_context.c
index 5444d3a..22e28ce 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -133,7 +133,11 @@ generate_descriptor(authvar_context *ctx)
 	if (rc < 0)
 		cmsreterr(-1, ctx->cms_ctx, "could not create signed data");
 
+#if __WORDSIZE == 64
 	offset = (uint64_t) &((win_cert_uefi_guid_t *)0)->data;
+#else
+	offset = (uint32_t) &((win_cert_uefi_guid_t *)0)->data;
+#endif
 	authinfo = calloc(offset + sd_der.len, 1);
 	if (!authinfo)
 		cmsreterr(-1, ctx->cms_ctx, "could not allocate authinfo");
-- 
1.8.4.5


From c72d3e454c8cd5ed4290d7c16027e74f5df3cfe8 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 1 Jul 2014 14:43:35 +0800
Subject: [PATCH 31/31] authvar: fix the write loop

I forgot to move the pointer...

Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
---
 src/authvar_context.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/authvar_context.c b/src/authvar_context.c
index 22e28ce..53855f2 100644
--- a/src/authvar_context.c
+++ b/src/authvar_context.c
@@ -18,6 +18,7 @@
  */
 
 #include <unistd.h>
+#include <stddef.h>
 #include <sys/mman.h>
 
 #include <prerror.h>
@@ -133,11 +134,7 @@ generate_descriptor(authvar_context *ctx)
 	if (rc < 0)
 		cmsreterr(-1, ctx->cms_ctx, "could not create signed data");
 
-#if __WORDSIZE == 64
-	offset = (uint64_t) &((win_cert_uefi_guid_t *)0)->data;
-#else
-	offset = (uint32_t) &((win_cert_uefi_guid_t *)0)->data;
-#endif
+	offset = offsetof(win_cert_uefi_guid_t, data);
 	authinfo = calloc(offset + sd_der.len, 1);
 	if (!authinfo)
 		cmsreterr(-1, ctx->cms_ctx, "could not allocate authinfo");
@@ -160,6 +157,7 @@ write_authvar(authvar_context *ctx)
 	void *buffer, *ptr;
 	size_t buf_len, des_len, remain;
 	ssize_t wlen;
+	off_t offset;
 
 	if (!ctx->authinfo)
 		cmsreterr(-1, ctx->cms_ctx, "Not a valid authvar");
@@ -187,18 +185,17 @@ write_authvar(authvar_context *ctx)
 	if (ctx->value_size > 0)
 		memcpy(ptr, ctx->value, ctx->value_size);
 
-	if (!ctx->to_firmware) {
-		if (ftruncate(ctx->exportfd, buf_len) < 0)
-			return -1;
+	if (!ctx->to_firmware)
 		lseek(ctx->exportfd, 0, SEEK_SET);
-	}
 
 	remain = buf_len;
+	offset = 0;
 	do {
-		wlen = write(ctx->exportfd, buffer, remain);
+		wlen = write(ctx->exportfd, buffer + offset, remain);
 		if (wlen < 0)
 			cmsreterr(-1, ctx->cms_ctx, "failed to write authvar");
 		remain -= wlen;
+		offset += wlen;
 	} while (remain > 0);
 
 	return 0;
-- 
1.8.4.5

openSUSE Build Service is sponsored by