391395f6e3
fix and enable the supplementary programs: pesigcheck, authvar, efisiglist OBS-URL: https://build.opensuse.org/request/show/236930 OBS-URL: https://build.opensuse.org/package/show/Base:System/pesign?expand=0&rev=27
4705 lines
125 KiB
Diff
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
|
|
|