diff --git a/pesign-enable-supplementary-programs.patch b/pesign-enable-supplementary-programs.patch new file mode 100644 index 0000000..0f64d02 --- /dev/null +++ b/pesign-enable-supplementary-programs.patch @@ -0,0 +1,4704 @@ +From 4d80fec4a38b5cb1a63262a323353c23b0172b77 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 + #include + ++#include ++#include ++#include ++#include ++#include ++ + #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 + #include + #include ++#include ++#include + + #include + ++#include + #include + #include ++#include + + #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 +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 +--- + 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 + #include + #include ++#include + + #include + #include +@@ -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", "" }, + {"dbxfile", 'X', POPT_ARG_STRING, &dbxfile, 0, + "use file for disallowed certificate list",""}, ++ {"certfile", 'c', POPT_ARG_STRING, &certfile, 0, ++ "the certificate (in DER form) for verification ",""}, + 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 +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 +--- + 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 +Date: Mon, 6 Jan 2014 14:11:34 -0500 +Subject: [PATCH 09/30] Rename peverify to pesigcheck + +Signed-off-by: Peter Jones +--- + 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 + #include + +-#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 . ++ * ++ * Author(s): Peter Jones ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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", ""}, ++ {"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", "" }, ++ {"dbxfile", 'X', POPT_ARG_STRING, &dbxfile, 0, ++ "use file for disallowed certificate list",""}, ++ {"certfile", 'c', POPT_ARG_STRING, &certfile, 0, ++ "the certificate (in DER form) for verification ",""}, ++ 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 . ++ * ++ * Author(s): Peter Jones ++ */ ++#ifndef PESIGN_H ++#define PESIGN_H 1 ++ ++#include ++#include ++ ++#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 . ++ * ++ * Author(s): Peter Jones ++ */ ++ ++#include ++#include ++ ++#include "pesigcheck.h" ++ ++#include ++#include ++ ++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 . ++ * ++ * Author(s): Peter Jones ++ */ ++#ifndef pesigcheck_CONTEXT_H ++#define pesigcheck_CONTEXT_H 1 ++ ++#include ++#include ++ ++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 . +- * +- * Author(s): Peter Jones +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-#include +-#include +-#include +-#include +- +-#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", ""}, +- {"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", "" }, +- {"dbxfile", 'X', POPT_ARG_STRING, &dbxfile, 0, +- "use file for disallowed certificate list",""}, +- {"certfile", 'c', POPT_ARG_STRING, &certfile, 0, +- "the certificate (in DER form) for verification ",""}, +- 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 . +- * +- * Author(s): Peter Jones +- */ +-#ifndef PESIGN_H +-#define PESIGN_H 1 +- +-#include +-#include +- +-#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 . +- * +- * Author(s): Peter Jones +- */ +- +-#include +-#include +- +-#include "peverify.h" +- +-#include +-#include +- +-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 . +- * +- * Author(s): Peter Jones +- */ +-#ifndef PEVERIFY_CONTEXT_H +-#define PEVERIFY_CONTEXT_H 1 +- +-#include +-#include +- +-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 +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 +--- + 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 + #include + #include +-#include + #include + + #include +@@ -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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 + #include + #include ++#include ++#include ++#include + + #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-type", 't', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT, + &hash_type, 0, "hash type to add", "" }, +- {"certificate", 'c', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, ++ {"certificate", 'c', POPT_ARG_STRING, + &certfile, 0, "certificate to add", "" }, + 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 +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 +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 +--- + 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 + #include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include + + #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", ++ "" }, + { "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[]) + "{|}" }, + { "name", 'n', POPT_ARG_STRING, &ctx.name, 0, "variable name", + "" }, ++ { "timestamp", 't', POPT_ARG_STRING, &time_str, 0, ++ "timestamp for the variable", "