pesign/pesign-enable-supplementary-programs.patch
2014-06-12 03:26:16 +00:00

4705 lines
125 KiB
Diff

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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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/30] 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