From 4e39e383ddaeda2fd7f30abaceb54d985e456219759fe85788cbb427a92c2220 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Fri, 22 Feb 2013 10:15:20 +0000 Subject: [PATCH] - Add pesign-bnc805166-fix-signature-list.patch to fix the broken signature list when inserting signature into a signed EFI binary (bnc#805166) OBS-URL: https://build.opensuse.org/package/show/Base:System/pesign?expand=0&rev=9 --- pesign-bnc805166-fix-signature-list.patch | 781 ++++++++++++++++++++++ pesign.changes | 7 + pesign.spec | 3 + 3 files changed, 791 insertions(+) create mode 100644 pesign-bnc805166-fix-signature-list.patch diff --git a/pesign-bnc805166-fix-signature-list.patch b/pesign-bnc805166-fix-signature-list.patch new file mode 100644 index 0000000..133f59f --- /dev/null +++ b/pesign-bnc805166-fix-signature-list.patch @@ -0,0 +1,781 @@ +commit 63c6ad572b3c1a7041dc581072421c2c94ff5d35 +Author: Gary Ching-Pang Lin +Date: Fri Feb 22 15:13:08 2013 +0800 + + Backport patches to fix signature list + + Get cms_context out of wincert functions. + ee357451be9968cedda57ce13b103eb82c590e67 + + Rework siglist to be somewhat more useful. + a5ec0d2cd06dec0961fc3fed680e7e385dc5bec8 + + Don't allow our signature list iterator to walk off the end of the file. + 18980866e7952100d98510297c0e1cc25fca8fc8 + + Include old signatures in new space calculations. + 77d334d77435d64e88fcc772b5b58440b394584a + + Make implanting extracted certificates work again. + 5ceddd2f80dfea70d211236190943746c2d2f77b + + Add error handling macros to make code simpler. + 0bafa814b49a9556550cfbc373e0ea5b9edb929e + + Add is_issuer_of(cert, cert) helper function. + 7750aaeceb2655807788f8e45417e84cb5404a8e + + Add "find_named_certificate()" helper function. + c89c8dbf7929f8f8f36bc1c4045fcc17d5ce7e5c + + Make generate_certificate_list include the issuing certificate. + 8c3d82ceb5029bedfee1577682fec5ff3669ff3c + + Fix a casting problem on 32-bit. + + 9eb2814858270af2d7ecfbfa5ca131e7be2f9f53 + +diff --git a/libdpe/pe_addcert.c b/libdpe/pe_addcert.c +index e391242..b6ba969 100644 +--- a/libdpe/pe_addcert.c ++++ b/libdpe/pe_addcert.c +@@ -59,7 +59,7 @@ pe_alloccert(Pe *pe, size_t size) + memset(addr, '\0', size); + + dd->certs.virtual_address = compute_file_addr(pe, addr); +- dd->certs.size = size; ++ dd->certs.size += size; + + #if 0 + pe_set_image_size(pe); +diff --git a/libdpe/pe_updatefile.c b/libdpe/pe_updatefile.c +index 7a29757..a8fe769 100644 +--- a/libdpe/pe_updatefile.c ++++ b/libdpe/pe_updatefile.c +@@ -24,6 +24,7 @@ + #include + + static struct section_header * ++__attribute__((unused)) + __get_last_section(Pe *pe) + { + Pe_Scn *scn = NULL; +@@ -79,6 +80,7 @@ compare_sections (const void *a, const void *b) + } + + static void ++__attribute__((unused)) + sort_sections (Pe_Scn **scns, Pe_ScnList *list) + { + Pe_Scn **scnp = scns; +@@ -131,7 +133,16 @@ __pe_updatemmap(Pe *pe, size_t shnum) + msync(msync_start, msync_end - msync_start, MS_SYNC); + + #warning this is not done yet. +- struct section_header *sh = __get_last_section(pe); ++ //struct section_header *sh = __get_last_section(pe); ++ ++ size_t dd_size = sizeof (*dd) / sizeof (dd->exports); ++ data_dirent *dde = &dd->exports; ++ for (int i = 0; i < dd_size; i++, dde++) { ++ if (dde->size != 0) { ++ char *addr = compute_mem_addr(pe, dde->virtual_address); ++ msync(addr, dde->size, MS_SYNC); ++ } ++ } + + return 0; + } +diff --git a/src/actions.c b/src/actions.c +index 9e4ac59..5c5dd89 100644 +--- a/src/actions.c ++++ b/src/actions.c +@@ -268,7 +268,7 @@ failure: + return ret; + } + +-static void ++void + parse_signature(pesign_context *ctx) + { + int rc; +@@ -396,8 +396,6 @@ generate_sattr_blob(pesign_context *ctx) + void + check_signature_space(pesign_context *ctx) + { +- parse_signature(ctx); +- + ssize_t available = available_cert_space(ctx->outpe); + + if (available < ctx->cms_ctx->newsig.len) { +@@ -406,14 +404,6 @@ check_signature_space(pesign_context *ctx) + } + } + +-int +-import_signature(pesign_context *ctx) +-{ +- insert_signature(ctx->cms_ctx, ctx->signum); +- +- return finalize_signatures(ctx->cms_ctx, ctx->outpe); +-} +- + void + allocate_signature_space(Pe *pe, ssize_t sigspace) + { +diff --git a/src/actions.h b/src/actions.h +index 400876f..4ecaad8 100644 +--- a/src/actions.h ++++ b/src/actions.h +@@ -28,12 +28,12 @@ extern int list_signatures(pesign_context *ctx); + extern void check_signature_space(pesign_context *ctx); + extern void allocate_signature_space(Pe *pe, ssize_t sigspace); + extern off_t export_signature(cms_context *cms, int fd, int ascii_armor); +-extern int import_signature(pesign_context *ctx); + extern void import_raw_signature(pesign_context *pctx); + extern void remove_signature(pesign_context *ctx); + extern void export_pubkey(pesign_context *ctx); + extern void export_cert(pesign_context *ctx); + extern int generate_sattr_blob(pesign_context *pctx); ++extern void parse_signature(pesign_context *ctx); + extern void insert_signature(cms_context *cms, int signum); + + #endif /* PESIGN_CRYPTO_H */ +diff --git a/src/cms_common.c b/src/cms_common.c +index 9ab2021..3b2e71a 100644 +--- a/src/cms_common.c ++++ b/src/cms_common.c +@@ -304,6 +304,17 @@ is_valid_cert(CERTCertificate *cert, void *data) + return SECFailure; + } + ++int ++is_issuer_of(CERTCertificate *c0, CERTCertificate *c1) ++{ ++ if (c0->derSubject.len != c1->derIssuer.len) ++ return 0; ++ ++ if (memcmp(c0->derSubject.data, c1->derIssuer.data, c0->derSubject.len)) ++ return 0; ++ return 1; ++} ++ + /* This is the dumbest function ever, but we need it anyway, because nss + * is garbage. */ + static void +@@ -448,6 +459,88 @@ err_slots: + return 0; + } + ++int ++find_named_certificate(cms_context *cms, char *name, CERTCertificate **cert) ++{ ++ if (!name) { ++ cms->log(cms, LOG_ERR, "no certificate name specified"); ++ return -1; ++ } ++ ++ secuPWData pwdata_val = { 0, 0 }; ++ void *pwdata = cms->pwdata ? cms->pwdata : &pwdata_val; ++ PK11_SetPasswordFunc(cms->func ? cms->func : SECU_GetModulePassword); ++ ++ PK11SlotList *slots = NULL; ++ slots = PK11_GetAllTokens(CKM_RSA_PKCS, PR_FALSE, PR_TRUE, pwdata); ++ if (!slots) ++ cmsreterr(-1, cms, "could not get pk11 token list"); ++ ++ PK11SlotListElement *psle = NULL; ++ psle = PK11_GetFirstSafe(slots); ++ if (!psle) { ++ save_port_err(PK11_FreeSlotList(slots)); ++ cmsreterr(-1, cms, "could not get pk11 safe"); ++ } ++ ++ while (psle) { ++ if (!strcmp(cms->tokenname, PK11_GetTokenName(psle->slot))) ++ break; ++ ++ psle = PK11_GetNextSafe(slots, psle, PR_FALSE); ++ } ++ ++ if (!psle) { ++ save_port_err(PK11_FreeSlotList(slots)); ++ cms->log(cms, LOG_ERR, "could not find token \"%s\"", ++ cms->tokenname); ++ return -1; ++ } ++ ++ SECStatus status; ++ if (PK11_NeedLogin(psle->slot) && !PK11_IsLoggedIn(psle->slot, pwdata)) { ++ status = PK11_Authenticate(psle->slot, PR_TRUE, pwdata); ++ if (status != SECSuccess) { ++ PK11_DestroySlotListElement(slots, &psle); ++ PK11_FreeSlotList(slots); ++ cms->log(cms, LOG_ERR, "authentication failed for " ++ "token \"%s\"", cms->tokenname); ++ return -1; ++ } ++ } ++ ++ CERTCertList *certlist = NULL; ++ certlist = PK11_ListCertsInSlot(psle->slot); ++ if (!certlist) { ++ save_port_err( ++ PK11_DestroySlotListElement(slots, &psle); ++ PK11_FreeSlotList(slots)); ++ cmsreterr(-1, cms, "could not get certificate list"); ++ } ++ ++ CERTCertListNode *node = NULL; ++ for (node = CERT_LIST_HEAD(certlist); !CERT_LIST_END(node,certlist); ++ node = CERT_LIST_NEXT(node)) { ++ if (!strcmp(node->cert->subjectName, name)) ++ break; ++ } ++ if (!node) { ++ PK11_DestroySlotListElement(slots, &psle); ++ PK11_FreeSlotList(slots); ++ CERT_DestroyCertList(certlist); ++ ++ return -1; ++ } ++ ++ *cert = CERT_DupCertificate(node->cert); ++ ++ PK11_DestroySlotListElement(slots, &psle); ++ PK11_FreeSlotList(slots); ++ CERT_DestroyCertList(certlist); ++ ++ return 0; ++} ++ + static SEC_ASN1Template EmptySequenceTemplate[] = { + { + .kind = SEC_ASN1_SEQUENCE, +diff --git a/src/cms_common.h b/src/cms_common.h +index a3848cd..2b2d619 100644 +--- a/src/cms_common.h ++++ b/src/cms_common.h +@@ -19,9 +19,35 @@ + #ifndef CMS_COMMON_H + #define CMS_COMMON_H 1 + +-#include ++#include + #include + #include ++#include ++#include ++#include ++#include ++#include ++ ++#define save_port_err(x) \ ++ ({ \ ++ int __saved_errno = PORT_GetError(); \ ++ x; \ ++ PORT_SetError(__saved_errno); \ ++ }) ++ ++#define cmserr(rv, cms, fmt, args...) ({ \ ++ (cms)->log((cms), LOG_ERR, "%s:%s:%d: " fmt ": %s", \ ++ __FILE__, __func__, __LINE__, ## args, \ ++ PORT_ErrorToString(PORT_GetError())); \ ++ exit(rv); \ ++ }) ++#define cmsreterr(rv, cms, fmt, args...) ({ \ ++ (cms)->log((cms), LOG_ERR, "%s:%s:%d: " fmt ": %s", \ ++ __FILE__, __func__, __LINE__, ## args, \ ++ PORT_ErrorToString(PORT_GetError())); \ ++ return rv; \ ++ }) ++ + + struct digest { + PK11Context *pk11ctx; +@@ -109,6 +135,10 @@ extern int generate_digest(cms_context *cms, Pe *pe); + extern int generate_signature(cms_context *ctx); + extern int unlock_nss_token(cms_context *ctx); + extern int find_certificate(cms_context *ctx); ++extern int is_issuer_of(CERTCertificate *c0, CERTCertificate *c1); ++ ++extern int find_named_certificate(cms_context *cms, char *name, ++ CERTCertificate **cert); + + extern SECOidTag digest_get_digest_oid(cms_context *cms); + extern SECOidTag digest_get_encryption_oid(cms_context *cms); +diff --git a/src/daemon.c b/src/daemon.c +index 4a9af87..92ae856 100644 +--- a/src/daemon.c ++++ b/src/daemon.c +@@ -288,7 +288,8 @@ set_up_inpe(context *ctx, int fd, Pe **pe) + return -1; + } + +- int rc = parse_signatures(ctx->cms, *pe); ++ int rc = parse_signatures(&ctx->cms->signatures, ++ &ctx->cms->num_signatures, *pe); + if (rc < 0) { + ctx->cms->log(ctx->cms, ctx->priority|LOG_ERR, + "pesignd: could not parse signature list"); +@@ -454,7 +455,8 @@ err_attached: + if (rc < 0) + goto err_attached; + insert_signature(ctx->cms, ctx->cms->num_signatures); +- finalize_signatures(ctx->cms, outpe); ++ finalize_signatures(ctx->cms->signatures, ++ ctx->cms->num_signatures, outpe); + pe_end(outpe); + } else { + if (ftruncate(outfd, 0) != 0) { +diff --git a/src/pesign.c b/src/pesign.c +index bfda33b..fcb2dca 100644 +--- a/src/pesign.c ++++ b/src/pesign.c +@@ -104,7 +104,8 @@ open_input(pesign_context *ctx) + exit(1); + } + +- int rc = parse_signatures(ctx->cms_ctx, ctx->inpe); ++ 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 data\n"); + exit(1); +@@ -126,7 +127,8 @@ close_output(pesign_context *ctx) + { + Pe_Cmd cmd = ctx->outfd == STDOUT_FILENO ? PE_C_RDWR : PE_C_RDWR_MMAP; + +- finalize_signatures(ctx->cms_ctx, ctx->outpe); ++ finalize_signatures(ctx->cms_ctx->signatures, ++ ctx->cms_ctx->num_signatures, ctx->outpe); + pe_update(ctx->outpe, cmd); + pe_end(ctx->outpe); + ctx->outpe = NULL; +@@ -673,7 +675,9 @@ main(int argc, char *argv[]) + allocate_signature_space(ctxp->outpe, sigspace); + generate_signature(ctxp->cms_ctx); + insert_signature(ctxp->cms_ctx, ctxp->signum); +- finalize_signatures(ctxp->cms_ctx, ctxp->outpe); ++ finalize_signatures(ctxp->cms_ctx->signatures, ++ ctxp->cms_ctx->num_signatures, ++ ctxp->outpe); + close_output(ctxp); + break; + case EXPORT_SATTRS: +@@ -687,12 +691,27 @@ main(int argc, char *argv[]) + /* add a signature from a file */ + case IMPORT_SIGNATURE: + check_inputs(ctxp); ++ if (ctxp->signum > ctxp->cms_ctx->num_signatures + 1) { ++ fprintf(stderr, "Invalid signature number.\n"); ++ exit(1); ++ } + open_input(ctxp); + open_output(ctxp); + close_input(ctxp); + open_sig_input(ctxp); ++ parse_signature(ctxp); ++ sigspace = ++ calculate_signature_overhead( ++ ctxp->cms_ctx->newsig.len) + ++ ctxp->cms_ctx->newsig.len + ++ get_reserved_sig_space(ctxp->cms_ctx, ++ ctxp->outpe); ++ allocate_signature_space(ctxp->outpe, sigspace); + check_signature_space(ctxp); +- import_signature(ctxp); ++ insert_signature(ctxp->cms_ctx, ctxp->signum); ++ finalize_signatures(ctxp->cms_ctx->signatures, ++ ctxp->cms_ctx->num_signatures, ++ ctxp->outpe); + close_sig_input(ctxp); + close_output(ctxp); + break; +@@ -788,6 +807,10 @@ main(int argc, char *argv[]) + ctxp->cms_ctx->certname); + exit(1); + } ++ if (ctxp->signum > ctxp->cms_ctx->num_signatures + 1) { ++ fprintf(stderr, "Invalid signature number.\n"); ++ exit(1); ++ } + open_input(ctxp); + open_output(ctxp); + close_input(ctxp); +@@ -798,7 +821,9 @@ main(int argc, char *argv[]) + generate_digest(ctxp->cms_ctx, ctxp->outpe); + generate_signature(ctxp->cms_ctx); + insert_signature(ctxp->cms_ctx, ctxp->signum); +- finalize_signatures(ctxp->cms_ctx, ctxp->outpe); ++ finalize_signatures(ctxp->cms_ctx->signatures, ++ ctxp->cms_ctx->num_signatures, ++ ctxp->outpe); + close_output(ctxp); + break; + case DAEMONIZE: +diff --git a/src/peverify.c b/src/peverify.c +index 08aad27..e010d87 100644 +--- a/src/peverify.c ++++ b/src/peverify.c +@@ -55,9 +55,12 @@ open_input(peverify_context *ctx) + exit(1); + } + +- int rc = parse_signatures(&ctx->cms_ctx, ctx->inpe); ++ 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 data\n"); ++ fprintf(stderr, "pesign: could not parse signature list in " ++ "EFI binary\n"); + exit(1); + } + } +diff --git a/src/siglist.c b/src/siglist.c +index 1a933e7..ca097e6 100644 +--- a/src/siglist.c ++++ b/src/siglist.c +@@ -17,11 +17,15 @@ + * Author(s): Peter Jones + */ + ++#include + #include ++#include ++#include + #include + #include + +-#include "authvar.h" ++#include "efitypes.h" ++#include "siglist.h" + + struct efi_signature_data { + efi_guid_t SignatureOwner; +@@ -135,7 +139,10 @@ 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); +- } else if (sigsize != sl->SignatureSize) { ++ } else if (sigsize != get_sig_type_size(sl->SignatureType)) { ++ fprintf(stderr, "sigsize: %d sl->SignatureSize: %d\n", ++ sigsize, sl->SignatureSize); ++ errno = EINVAL; + return -1; + } + +@@ -162,11 +169,31 @@ signature_list_add_sig(signature_list *sl, efi_guid_t owner, + return 0; + } + +-void * +-signature_list_realize(signature_list *sl) ++#if 0 ++int ++signature_list_parse(signature_list *sl, uint8_t *data, size_t len) + { +- if (sl->realized) +- return sl->realized; ++ if (!sl) ++ return -1; ++ ++ if (sl->realized) { ++ free(sl->realized); ++ sl->realized = NULL; ++ } ++ ++ efi_signature_list *esl = data; ++ efi_signature_data *esd = NULL; ++ ++} ++#endif ++ ++int ++signature_list_realize(signature_list *sl, void **out, size_t *outsize) ++{ ++ if (sl->realized) { ++ free(sl->realized); ++ sl->realized = NULL; ++ } + + struct efi_signature_list *esl = NULL; + uint32_t size = sizeof (*esl) + +@@ -174,7 +201,7 @@ signature_list_realize(signature_list *sl) + + void *ret = calloc(1, size); + if (!ret) +- return NULL; ++ return -1; + esl = ret; + + memcpy(esl, sl, sizeof (*esl)); +@@ -186,7 +213,10 @@ signature_list_realize(signature_list *sl) + } + + sl->realized = ret; +- return ret; ++ ++ *out = ret; ++ *outsize = size; ++ return 0; + } + + void +diff --git a/src/siglist.h b/src/siglist.h +index 2961a39..a576ffd 100644 +--- a/src/siglist.h ++++ b/src/siglist.h +@@ -24,7 +24,8 @@ typedef struct signature_list signature_list; + extern signature_list *signature_list_new(efi_guid_t SignatureType); + extern int signature_list_add_sig(signature_list *sl, efi_guid_t owner, + uint8_t *sig, uint32_t sigsize); +-extern void *signature_list_realize(signature_list *sl); ++extern int signature_list_realize(signature_list *sl, ++ void **out, size_t *outsize); + extern void signature_list_free(signature_list *sl); + + #endif /* SIGLIST_H */ +diff --git a/src/signed_data.c b/src/signed_data.c +index e676cb3..83957d6 100644 +--- a/src/signed_data.c ++++ b/src/signed_data.c +@@ -76,20 +76,51 @@ static int + generate_certificate_list(cms_context *cms, SECItem ***certificate_list_p) + { + SECItem **certificates = NULL; ++ void *mark = PORT_ArenaMark(cms->arena); + +- certificates = PORT_ArenaZAlloc(cms->arena, sizeof (SECItem *) * 2); +- if (!certificates) +- return -1; +- +- certificates[0] = PORT_ArenaZAlloc(cms->arena, sizeof (SECItem)); +- if (!certificates[0]) { +- int err = PORT_GetError(); +- PORT_ZFree(certificates, sizeof (SECItem) * 2); +- PORT_SetError(err); +- return -1; ++ certificates = PORT_ArenaZAlloc(cms->arena, sizeof (SECItem *) * 3); ++ if (!certificates) { ++ save_port_err(PORT_ArenaRelease(cms->arena, mark)); ++ cmsreterr(-1, cms, "could not allocate certificate list"); ++ } ++ int i = 0; ++ ++ certificates[i] = PORT_ArenaZAlloc(cms->arena, sizeof (SECItem)); ++ if (!certificates[i]) { ++ save_port_err(PORT_ArenaRelease(cms->arena, mark)); ++ cmsreterr(-1, cms, "could not allocate certificate entry"); ++ } ++ SECITEM_CopyItem(cms->arena, certificates[i++], &cms->cert->derCert); ++ ++ if (!is_issuer_of(cms->cert, cms->cert)) { ++ CERTCertificate *signer = NULL; ++ int rc = find_named_certificate(cms, cms->cert->issuerName, ++ &signer); ++ if (rc < 0) { ++ PORT_ArenaRelease(cms->arena, mark); ++ return -1; ++ } ++ ++ if (signer) { ++ if (signer->derCert.len != cms->cert->derCert.len || ++ memcmp(signer->derCert.data, ++ cms->cert->derCert.data, ++ signer->derCert.len)) { ++ certificates[i] = PORT_ArenaZAlloc(cms->arena, ++ sizeof (SECItem)); ++ if (!certificates[i]) { ++ save_port_err( ++ PORT_ArenaRelease(cms->arena, mark)); ++ cmsreterr(-1, cms,"could not allocate " ++ "certificate entry"); ++ } ++ SECITEM_CopyItem(cms->arena, certificates[i++], ++ &signer->derCert); ++ } ++ CERT_DestroyCertificate(signer); ++ } + } + +- SECITEM_CopyItem(cms->arena, certificates[0], &cms->cert->derCert); + *certificate_list_p = certificates; + return 0; + } +diff --git a/src/wincert.c b/src/wincert.c +index 4b5ba45..4197a87 100644 +--- a/src/wincert.c ++++ b/src/wincert.c +@@ -25,13 +25,13 @@ struct cert_list_entry { + }; + + static int +-generate_cert_list(cms_context *cms, void **cert_list, +- size_t *cert_list_size) ++generate_cert_list(SECItem **signatures, int num_signatures, ++ void **cert_list, size_t *cert_list_size) + { + size_t cl_size = 0; +- for (int i = 0; i < cms->num_signatures; i++) { ++ for (int i = 0; i < num_signatures; i++) { + cl_size += sizeof (win_certificate); +- cl_size += cms->signatures[i]->len; ++ cl_size += signatures[i]->len; + } + + uint8_t *data = malloc(cl_size); +@@ -41,15 +41,15 @@ generate_cert_list(cms_context *cms, void **cert_list, + *cert_list = (void *)data; + *cert_list_size = cl_size; + +- for (int i = 0; i < cms->num_signatures; i++) { ++ for (int i = 0; i < num_signatures; i++) { + struct cert_list_entry *cle = (struct cert_list_entry *)data; +- cle->wc.length = cms->signatures[i]->len + ++ cle->wc.length = signatures[i]->len + + sizeof (win_certificate); + cle->wc.revision = WIN_CERT_REVISION_2_0; + cle->wc.cert_type = WIN_CERT_TYPE_PKCS_SIGNED_DATA; +- memcpy(&cle->data[0], cms->signatures[i]->data, +- cms->signatures[i]->len); +- data += sizeof (win_certificate) + cms->signatures[i]->len; ++ memcpy(&cle->data[0], signatures[i]->data, ++ signatures[i]->len); ++ data += sizeof (win_certificate) + signatures[i]->len; + } + + return 0; +@@ -62,12 +62,13 @@ implant_cert_list(Pe *pe, void *cert_list, size_t cert_list_size) + } + + int +-finalize_signatures(cms_context *cms, Pe *pe) ++finalize_signatures(SECItem **sigs, int num_sigs, Pe *pe) + { + void *clist = NULL; + size_t clist_size = 0; + +- if (generate_cert_list(cms, &clist, &clist_size) < 0) ++ if (generate_cert_list(sigs, num_sigs, ++ &clist, &clist_size) < 0) + return -1; + + if (implant_cert_list(pe, clist, clist_size) < 0) { +@@ -126,6 +127,13 @@ done: + void *certs = iter->certs; + size_t size = iter->size; + ++ void *map = NULL; ++ size_t map_size = 0; ++ ++ map = pe_rawfile(iter->pe, &map_size); ++ if (!map || map_size < 1) ++ return 0; ++ + while (1) { + win_certificate *tmpcert; + if (n + sizeof (*tmpcert) >= size) +@@ -133,6 +141,9 @@ done: + + tmpcert = (win_certificate *)((uint8_t *)certs + n); + ++ if ((intptr_t)tmpcert > (intptr_t)map + map_size) ++ return -1; ++ + /* length _includes_ the size of the structure. */ + uint32_t length = le32_to_cpu(tmpcert->length); + +@@ -193,7 +204,23 @@ available_cert_space(Pe *pe) + return totalsize - foundsize; + } + +-ssize_t calculate_signature_space(cms_context *cms, Pe *pe) ++size_t ++get_reserved_sig_space(cms_context *cms, Pe *pe) ++{ ++ size_t ret = 0; ++ for (int i = 0; i < cms->num_signatures; i++) ++ ret += cms->signatures[i]->len + sizeof (win_certificate); ++ return ret; ++} ++ ++ssize_t ++calculate_signature_overhead(ssize_t size) ++{ ++ return sizeof(win_certificate); ++} ++ ++ssize_t ++calculate_signature_space(cms_context *cms, Pe *pe) + { + int rc; + +@@ -209,7 +236,9 @@ err: + if (rc < 0) + goto err; + +- ssize_t ret = sig.len + dd->certs.size + sizeof(win_certificate) - ++ size_t res = get_reserved_sig_space(cms, pe); ++ ++ ssize_t ret = res + sig.len + sizeof(win_certificate) - + available_cert_space(pe); + + //free(sig.data); +@@ -218,7 +247,7 @@ err: + } + + int +-parse_signatures(cms_context *cms, Pe *pe) ++parse_signatures(SECItem ***sigs, int *num_sigs, Pe *pe) + { + cert_iter iter; + int rc = cert_iter_init(&iter, pe); +@@ -238,8 +267,8 @@ parse_signatures(cms_context *cms, Pe *pe) + } + + if (nsigs == 0) { +- cms->num_signatures = 0; +- cms->signatures = NULL; ++ *num_sigs = 0; ++ *sigs = NULL; + return 0; + } + +@@ -271,8 +300,8 @@ parse_signatures(cms_context *cms, Pe *pe) + i++; + } + +- cms->num_signatures = nsigs; +- cms->signatures = signatures; ++ *num_sigs = nsigs; ++ *sigs = signatures; + + return 0; + err: +diff --git a/src/wincert.h b/src/wincert.h +index 4309915..ed7e15c 100644 +--- a/src/wincert.h ++++ b/src/wincert.h +@@ -32,8 +32,6 @@ typedef struct win_certificate { + uint16_t cert_type; + } win_certificate; + +-extern int finalize_signatures(cms_context *cms, Pe *pe); +- + typedef struct cert_iter { + Pe *pe; + off_t n; +@@ -45,6 +43,10 @@ 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); + extern ssize_t calculate_signature_space(cms_context *cms, Pe *pe); +-extern int parse_signatures(cms_context *cms, Pe *pe); ++extern int parse_signatures(SECItem ***sigs, int *num_sigs, Pe *pe); ++extern int finalize_signatures(SECItem **sigs, int num_sigs, Pe *pe); ++extern size_t get_reserved_sig_space(cms_context *cms, Pe *pe); ++extern ssize_t calculate_signature_overhead(ssize_t size); ++ + + #endif /* PESIGN_WINCERT_H */ diff --git a/pesign.changes b/pesign.changes index cc993cf..f94f955 100644 --- a/pesign.changes +++ b/pesign.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Fri Feb 22 08:44:43 UTC 2013 - glin@suse.com + +- Add pesign-bnc805166-fix-signature-list.patch to fix the broken + signature list when inserting signature into a signed EFI binary + (bnc#805166) + ------------------------------------------------------------------- Tue Feb 12 15:32:11 CET 2013 - mls@suse.de diff --git a/pesign.spec b/pesign.spec index 180fdfa..b02c2f6 100644 --- a/pesign.spec +++ b/pesign.spec @@ -43,6 +43,8 @@ Patch9: pesign-fix-export-attributes.patch # PATCH-FIX-UPSTREAM pesign-privkey_unneeded.diff glin@suse.com -- Don't check the private key when importing the raw signature Patch10: pesign-privkey_unneeded.diff Patch11: pesign-no-set-image-size.patch +# PATCH-FIX-UPSTREAM pesign-bnc805166-fix-signature-list.patch bnc#805166 glin@suse.com -- Fix the broken signature list when inserting a new signature into a signed EFI binary. +Patch12: pesign-bnc805166-fix-signature-list.patch BuildRequires: mozilla-nss-devel BuildRequires: pkg-config BuildRequires: popt-devel @@ -78,6 +80,7 @@ Authors: %patch9 -p1 %patch10 -p1 %patch11 -p1 +%patch12 -p1 %build make OPTFLAGS="$RPM_OPT_FLAGS"