From f22c83514cb032b9cc6b5c825d1188776c244194 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 23 Jan 2024 15:13:21 +0100 Subject: [PATCH] Simplify obtaining an existing signature and creating a new one --- appx.c | 115 +++++++++++++++---------------- cab.c | 125 ++++++++++++++++----------------- cat.c | 50 ++++++-------- helpers.c | 58 ---------------- helpers.h | 2 - msi.c | 184 ++++++++++++++++++++++++------------------------- osslsigncode.c | 139 ++++++++++++++++++++++++++++++++++--- osslsigncode.h | 5 +- pe.c | 111 ++++++++++++++--------------- 9 files changed, 406 insertions(+), 383 deletions(-) diff --git a/appx.c b/appx.c index 097023c5..c15696a7 100644 --- a/appx.c +++ b/appx.c @@ -6,6 +6,7 @@ * Copyright (C) 2023 Michał Trojnara * Author: Małgorzata Olszówka * + * APPX files do not support nesting (multiple signature) */ #define _FILE_OFFSET_BITS 64 @@ -241,7 +242,8 @@ static int appx_check_file(FILE_FORMAT_CTX *ctx, int detached); static int appx_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static PKCS7 *appx_pkcs7_extract(FILE_FORMAT_CTX *ctx); static int appx_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); -static PKCS7 *appx_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); +static int appx_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); +static PKCS7 *appx_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash); static int appx_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static BIO *appx_bio_free(BIO *hash, BIO *outdata); static void appx_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); @@ -256,7 +258,8 @@ FILE_FORMAT file_format_appx = { .verify_digests = appx_verify_digests, .pkcs7_extract = appx_pkcs7_extract, .remove_pkcs7 = appx_remove_pkcs7, - .pkcs7_prepare = appx_pkcs7_prepare, + .process_data = appx_process_data, + .pkcs7_signature_new = appx_pkcs7_signature_new, .append_pkcs7 = appx_append_pkcs7, .bio_free = appx_bio_free, .ctx_cleanup = appx_ctx_cleanup, @@ -348,9 +351,6 @@ static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *ou if (zipGetCDEntryByName(zip, APPXBUNDLE_MANIFEST_FILENAME)) { ctx->appx_ctx->isBundle = 1; } - if (options->nest) - /* I've not tried using set_nested_signature as signtool won't do this */ - printf("Warning: APPX files do not support nesting (multiple signature)\n"); if (options->cmd == CMD_SIGN || options->cmd==CMD_ATTACH || options->cmd==CMD_ADD || options->cmd == CMD_EXTRACT_DATA) { printf("Warning: Ignore -h option, use the hash algorithm specified in AppxBlockMap.xml\n"); @@ -591,83 +591,78 @@ static int appx_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) } /* - * Obtain an existing signature or create a new one. - * APPX files do not support nesting. + * Modify specific type data. * [in, out] ctx: structure holds input and output data * [out] hash: message digest BIO (unused) * [out] outdata: outdata file BIO (unused) - * [returns] pointer to PKCS#7 structure + * [returns] 1 on error or 0 on success */ -static PKCS7 *appx_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) +static int appx_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) { ZIP_CENTRAL_DIRECTORY_ENTRY *entry; - PKCS7 *p7 = NULL; /* squash unused parameter warnings */ (void)outdata; (void)hash; - if (ctx->options->cmd == CMD_ADD) { - /* Obtain an existing signature */ - p7 = appx_pkcs7_extract(ctx); - if (!p7) { - printf("Unable to extract existing signature\n"); - return NULL; /* FAILED */ - } - return p7; - } - /* Create and append a new signature content types entry */ entry = zipGetCDEntryByName(ctx->appx_ctx->zip, CONTENT_TYPES_FILENAME); if (!entry) { printf("Not a valid .appx file: content types file missing\n"); - return NULL; /* FAILED */ + return 1; /* FAILED */ } if (!appx_append_ct_signature_entry(ctx->appx_ctx->zip, entry)) { + return 1; /* FAILED */ + } + return 0; /* OK */ +} + +/* + * Create a new PKCS#7 signature. + * [in, out] ctx: structure holds input and output data + * [out] hash: message digest BIO (unused) + * [returns] pointer to PKCS#7 structure + */ +static PKCS7 *appx_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash) +{ + ASN1_OCTET_STRING *content; + PKCS7 *p7 = NULL; + BIO *hashes; + + /* squash unused parameter warnings */ + (void)hash; + + /* Create hash blob from concatenated APPX hashes */ + hashes = appx_calculate_hashes(ctx); + if (!hashes) { return NULL; /* FAILED */ } - if (ctx->options->cmd == CMD_ATTACH) { - /* Obtain an existing PKCS#7 signature from a "sigin" file */ - p7 = pkcs7_get_sigfile(ctx); - if (!p7) { - printf("Unable to extract valid signature\n"); - return NULL; /* FAILED */ - } - } else if (ctx->options->cmd == CMD_SIGN) { - ASN1_OCTET_STRING *content; - /* Create hash blob from concatenated APPX hashes */ - BIO *hashes = appx_calculate_hashes(ctx); - if (!hashes) { - return NULL; /* FAILED */ - } - /* Create a new PKCS#7 signature */ - p7 = pkcs7_create(ctx); - if (!p7) { - printf("Creating a new signature failed\n"); - BIO_free_all(hashes); - return NULL; /* FAILED */ - } - if (!add_indirect_data_object(p7)) { - printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); - PKCS7_free(p7); - BIO_free_all(hashes); - return NULL; /* FAILED */ - } - content = spc_indirect_data_content_get(hashes, ctx); + p7 = pkcs7_create(ctx); + if (!p7) { + printf("Creating a new signature failed\n"); BIO_free_all(hashes); - if (!content) { - printf("Failed to get spcIndirectDataContent\n"); - PKCS7_free(p7); - return NULL; /* FAILED */ - } - if (!sign_spc_indirect_data_content(p7, content)) { - printf("Failed to set signed content\n"); - PKCS7_free(p7); - ASN1_OCTET_STRING_free(content); - return NULL; /* FAILED */ - } + return NULL; /* FAILED */ + } + if (!add_indirect_data_object(p7)) { + printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); + PKCS7_free(p7); + BIO_free_all(hashes); + return NULL; /* FAILED */ + } + content = spc_indirect_data_content_get(hashes, ctx); + BIO_free_all(hashes); + if (!content) { + printf("Failed to get spcIndirectDataContent\n"); + PKCS7_free(p7); + return NULL; /* FAILED */ + } + if (!sign_spc_indirect_data_content(p7, content)) { + printf("Failed to set signed content\n"); + PKCS7_free(p7); ASN1_OCTET_STRING_free(content); + return NULL; /* FAILED */ } + ASN1_OCTET_STRING_free(content); return p7; /* OK */ } diff --git a/cab.c b/cab.c index d9a2962f..5792fc73 100644 --- a/cab.c +++ b/cab.c @@ -49,8 +49,10 @@ static int cab_check_file(FILE_FORMAT_CTX *ctx, int detached); static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md); static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx); +static PKCS7 *cab_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx); static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); -static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); +static int cab_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); +static PKCS7 *cab_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash); static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static BIO *cab_bio_free(BIO *hash, BIO *outdata); @@ -65,8 +67,10 @@ FILE_FORMAT file_format_cab = { .digest_calc = cab_digest_calc, .verify_digests = cab_verify_digests, .pkcs7_extract = cab_pkcs7_extract, + .pkcs7_extract_to_nest = cab_pkcs7_extract_to_nest, .remove_pkcs7 = cab_remove_pkcs7, - .pkcs7_prepare = cab_pkcs7_prepare, + .process_data = cab_process_data, + .pkcs7_signature_new = cab_pkcs7_signature_new, .append_pkcs7 = cab_append_pkcs7, .update_data_size = cab_update_data_size, .bio_free = cab_bio_free, @@ -401,6 +405,16 @@ static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx) return d2i_PKCS7(NULL, &blob, ctx->cab_ctx->siglen); } +/* + * Extract existing signature in DER format. + * [in] ctx: structure holds input and output data + * pointer to PKCS#7 structure + */ +static PKCS7 *cab_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx) +{ + return cab_pkcs7_extract(ctx); +} + /* * Remove existing signature. * [in, out] ctx: structure holds input and output data @@ -479,83 +493,62 @@ static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) } /* - * Obtain an existing signature or create a new one. + * Modify specific type data and calculate a hash (message digest) of data. * [in, out] ctx: structure holds input and output data * [out] hash: message digest BIO * [out] outdata: outdata file BIO - * [returns] pointer to PKCS#7 structure + * [returns] 1 on error or 0 on success */ -static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) +static int cab_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) { - PKCS7 *cursig = NULL, *p7 = NULL; - /* Strip current signature and modify header */ if (ctx->cab_ctx->header_size == 20) { if (!cab_modify_header(ctx, hash, outdata)) - return NULL; /* FAILED */ + return 1; /* FAILED */ } else { if (!cab_add_header(ctx, hash, outdata)) - return NULL; /* FAILED */ + return 1; /* FAILED */ } - /* Obtain a current signature from previously-signed file */ - if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest) - || (ctx->options->cmd == CMD_ATTACH && ctx->options->nest) - || ctx->options->cmd == CMD_ADD) { - cursig = cab_pkcs7_extract(ctx); - if (!cursig) { - printf("Unable to extract existing signature\n"); - return NULL; /* FAILED */ - } - ctx->options->nested_number = nested_signatures_number_get(cursig); - if (ctx->options->nested_number < 0) { - printf("Unable to get number of nested signatures\n"); - PKCS7_free(cursig); - return NULL; /* FAILED */ - } - if (ctx->options->cmd == CMD_ADD) - p7 = cursig; - } - if (ctx->options->cmd == CMD_ATTACH) { - /* Obtain an existing PKCS#7 signature */ - p7 = pkcs7_get_sigfile(ctx); - if (!p7) { - printf("Unable to extract valid signature\n"); - PKCS7_free(cursig); - return NULL; /* FAILED */ - } - } else if (ctx->options->cmd == CMD_SIGN) { - ASN1_OCTET_STRING *content; - /* Create a new PKCS#7 signature */ - p7 = pkcs7_create(ctx); - if (!p7) { - printf("Creating a new signature failed\n"); - return NULL; /* FAILED */ - } - if (ctx->options->jp >= 0 && !cab_add_jp_attribute(p7, ctx->options->jp)) { - printf("Adding jp attribute failed\n"); - PKCS7_free(p7); - return NULL; /* FAILED */ - } - if (!add_indirect_data_object(p7)) { - printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); - PKCS7_free(p7); - return NULL; /* FAILED */ - } - content = spc_indirect_data_content_get(hash, ctx); - if (!content) { - printf("Failed to get spcIndirectDataContent\n"); - return NULL; /* FAILED */ - } - if (!sign_spc_indirect_data_content(p7, content)) { - printf("Failed to set signed content\n"); - PKCS7_free(p7); - ASN1_OCTET_STRING_free(content); - return NULL; /* FAILED */ - } + return 0; /* OK */ +} + +/* + * Create a new PKCS#7 signature. + * [in, out] ctx: structure holds input and output data + * [out] hash: message digest BIO + * [returns] pointer to PKCS#7 structure + */ +static PKCS7 *cab_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash) +{ + ASN1_OCTET_STRING *content; + PKCS7 *p7 = pkcs7_create(ctx); + + if (!p7) { + printf("Creating a new signature failed\n"); + return NULL; /* FAILED */ + } + if (ctx->options->jp >= 0 && !cab_add_jp_attribute(p7, ctx->options->jp)) { + printf("Adding jp attribute failed\n"); + PKCS7_free(p7); + return NULL; /* FAILED */ + } + if (!add_indirect_data_object(p7)) { + printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); + PKCS7_free(p7); + return NULL; /* FAILED */ + } + content = spc_indirect_data_content_get(hash, ctx); + if (!content) { + printf("Failed to get spcIndirectDataContent\n"); + return NULL; /* FAILED */ + } + if (!sign_spc_indirect_data_content(p7, content)) { + printf("Failed to set signed content\n"); + PKCS7_free(p7); ASN1_OCTET_STRING_free(content); + return NULL; /* FAILED */ } - if (ctx->options->nest) - ctx->options->prevsig = cursig; + ASN1_OCTET_STRING_free(content); return p7; } diff --git a/cat.c b/cat.c index 160492cd..32b3a82d 100644 --- a/cat.c +++ b/cat.c @@ -5,6 +5,7 @@ * Author: Małgorzata Olszówka * * Catalog files are a bit odd, in that they are only a PKCS7 blob. + * CAT files do not support nesting (multiple signature) */ #include "osslsigncode.h" @@ -38,7 +39,7 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out static int cat_check_file(FILE_FORMAT_CTX *ctx, int detached); static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx); -static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); +static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash); static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static BIO *cat_bio_free(BIO *hash, BIO *outdata); static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); @@ -48,7 +49,7 @@ FILE_FORMAT file_format_cat = { .check_file = cat_check_file, .verify_digests = cat_verify_digests, .pkcs7_extract = cat_pkcs7_extract, - .pkcs7_prepare = cat_pkcs7_prepare, + .pkcs7_signature_new = cat_pkcs7_signature_new, .append_pkcs7 = cat_append_pkcs7, .bio_free = cat_bio_free, .ctx_cleanup = cat_ctx_cleanup, @@ -108,9 +109,6 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out if (options->cmd == CMD_VERIFY) printf("Warning: Use -catalog option to verify that a file, listed in catalog file, is signed\n"); - if (options->nest) - /* I've not tried using set_nested_signature as signtool won't do this */ - printf("Warning: CAT files do not support nesting (multiple signature)\n"); if (options->jp >= 0) printf("Warning: -jp option is only valid for CAB files\n"); if (options->pagehash == 1) @@ -173,41 +171,33 @@ static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx) } /* - * Obtain an existing signature or create a new one. + * Create a new PKCS#7 signature. * [in, out] ctx: structure holds input and output data * [out] hash: message digest BIO (unused) - * [out] outdata: outdata file BIO (unused) * [returns] pointer to PKCS#7 structure */ -static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) +static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash) { PKCS7 *p7 = NULL; /* squash unused parameter warnings */ - (void)outdata; (void)hash; - /* Obtain an existing signature */ - if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) { - p7 = cat_pkcs7_extract(ctx); - } else if (ctx->options->cmd == CMD_SIGN) { - /* Create a new signature */ - p7 = pkcs7_create(ctx); - if (!p7) { - printf("Creating a new signature failed\n"); - return NULL; /* FAILED */ - } - if (!cat_add_ms_ctl_object(p7)) { - printf("Adding MS_CTL_OBJID failed\n"); - PKCS7_free(p7); - return NULL; /* FAILED */ - } - if (!cat_sign_ms_ctl_content(p7, ctx->cat_ctx->p7->d.sign->contents)) { - printf("Failed to set signed content\n"); - PKCS7_free(p7); - return 0; /* FAILED */ - } - } + p7 = pkcs7_create(ctx); + if (!p7) { + printf("Creating a new signature failed\n"); + return NULL; /* FAILED */ + } + if (!cat_add_ms_ctl_object(p7)) { + printf("Adding MS_CTL_OBJID failed\n"); + PKCS7_free(p7); + return NULL; /* FAILED */ + } + if (!cat_sign_ms_ctl_content(p7, ctx->cat_ctx->p7->d.sign->contents)) { + printf("Failed to set signed content\n"); + PKCS7_free(p7); + return 0; /* FAILED */ + } return p7; /* OK */ } diff --git a/helpers.c b/helpers.c index ec6fcc94..d4d3123f 100644 --- a/helpers.c +++ b/helpers.c @@ -110,33 +110,6 @@ void unmap_file(char *indata, const size_t size) #endif /* WIN32 */ } -/* - * Retrieve a decoded PKCS#7 structure corresponding to the signature - * stored in the "sigin" file - * CMD_ATTACH command specific - * [in] ctx: structure holds input and output data - * [returns] pointer to PKCS#7 structure - */ -PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx) -{ - PKCS7 *p7 = NULL; - uint32_t filesize; - char *indata; - - filesize = get_file_size(ctx->options->sigfile); - if (!filesize) { - return NULL; /* FAILED */ - } - indata = map_file(ctx->options->sigfile, filesize); - if (!indata) { - printf("Failed to open file: %s\n", ctx->options->sigfile); - return NULL; /* FAILED */ - } - p7 = pkcs7_read_data(indata, filesize); - unmap_file(indata, filesize); - return p7; -} - /* * Retrieve a decoded PKCS#7 structure * [in] data: encoded PEM or DER data @@ -818,37 +791,6 @@ static int X509_compare(const X509 *const *a, const X509 *const *b) return ret; } -/* - * Return the number of objects in SPC_NESTED_SIGNATURE_OBJID attribute - * [in] p7: existing PKCS#7 signature (Primary Signature) - * [returns] -1 on error or the number of nested signatures - */ -int nested_signatures_number_get(PKCS7 *p7) -{ - int i; - STACK_OF(X509_ATTRIBUTE) *unauth_attr; - PKCS7_SIGNER_INFO *si; - STACK_OF(PKCS7_SIGNER_INFO) *signer_info = PKCS7_get_signer_info(p7); - - if (!signer_info) - return -1; /* FAILED */ - si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0); - if (!si) - return -1; /* FAILED */ - unauth_attr = PKCS7_get_attributes(si); /* cont[1] */ - if (!unauth_attr) - return 0; /* OK, no unauthenticated attributes */ - for (i=0; imsi_ctx->dirent, NULL); + if (!ds) { + printf("MSI file has no signature\n"); return NULL; /* FAILED */ } - len = GET_UINT32_LE(ds->size); - if (len == 0 || len >= MAXREGSECT) { - printf("Corrupted DigitalSignature stream length 0x%08X\n", len); + p7 = msi_pkcs7_get_digital_signature(ctx, ds); + if (!p7) { + printf("Unable to extract existing signature\n"); + return NULL; /* FAILED */ + } + return p7; +} + +/* + * Extract existing signature in DER format. + * Perform a sanity check for the MsiDigitalSignatureEx section. + * [in] ctx: structure holds input and output data + * [returns] pointer to PKCS#7 structure + */ +static PKCS7 *msi_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx) +{ + PKCS7 *p7; + MSI_ENTRY *ds, *dse = NULL; + + ds = msi_signatures_get(ctx->msi_ctx->dirent, &dse); + if (!ds) { + printf("MSI file has no signature\n"); + return NULL; /* FAILED */ + } + p7 = msi_pkcs7_get_digital_signature(ctx, ds); + if (!p7) { + printf("Unable to extract existing signature\n"); + return NULL; /* FAILED */ + } + /* perform a sanity check for the MsiDigitalSignatureEx section */ + if (!msi_check_MsiDigitalSignatureEx(ctx, dse, p7)) { + PKCS7_free(p7); return NULL; /* FAILED */ } - p = OPENSSL_malloc((size_t)len); - p7 = msi_pkcs7_get_digital_signature(ctx, ds, &p, len); - OPENSSL_free(p); return p7; } @@ -630,97 +658,56 @@ static int msi_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) } /* - * Obtain an existing signature or create a new one. + * Calculate a hash (message digest) of data. * [in, out] ctx: structure holds input and output data * [out] hash: message digest BIO * [out] outdata: outdata file BIO (unused) - * [returns] pointer to PKCS#7 structure + * [returns] 1 on error or 0 on success */ -static PKCS7 *msi_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) +static int msi_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) { - PKCS7 *cursig = NULL, *p7 = NULL; - uint32_t len; - char *p; - /* squash the unused parameter warning */ (void)outdata; hash = msi_digest_calc_bio(ctx, hash); if (!hash) { + return 1; /* FAILED */ + } + return 0; /* OK */ +} + +/* + * Create a new PKCS#7 signature. + * [in, out] ctx: structure holds input and output data + * [out] hash: message digest BIO + * [returns] pointer to PKCS#7 structure + */ +static PKCS7 *msi_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash) +{ + ASN1_OCTET_STRING *content; + PKCS7 *p7 = pkcs7_create(ctx); + + if (!p7) { + printf("Creating a new signature failed\n"); return NULL; /* FAILED */ } - /* Obtain a current signature from previously-signed file */ - if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest) - || (ctx->options->cmd == CMD_ATTACH && ctx->options->nest) - || ctx->options->cmd == CMD_ADD) { - MSI_ENTRY *dse = NULL; - MSI_ENTRY *ds = msi_signatures_get(ctx->msi_ctx->dirent, &dse); - if (!ds) { - printf("MSI file has no signature\n\n"); - return NULL; /* FAILED */ - } - len = GET_UINT32_LE(ds->size); - if (len == 0 || len >= MAXREGSECT) { - printf("Corrupted DigitalSignature stream length 0x%08X\n", len); - return NULL; /* FAILED */ - } - p = OPENSSL_malloc((size_t)len); - /* get current signature */ - cursig = msi_pkcs7_get_digital_signature(ctx, ds, &p, len); - OPENSSL_free(p); - if (!cursig) { - printf("Unable to extract existing signature\n"); - return NULL; /* FAILED */ - } - if (!msi_check_MsiDigitalSignatureEx(ctx, dse, cursig)) { - PKCS7_free(cursig); - return NULL; /* FAILED */ - } - ctx->options->nested_number = nested_signatures_number_get(cursig); - if (ctx->options->nested_number < 0) { - printf("Unable to get number of nested signatures\n"); - PKCS7_free(cursig); - return NULL; /* FAILED */ - } - if (ctx->options->cmd == CMD_ADD) - p7 = cursig; - } - if (ctx->options->cmd == CMD_ATTACH) { - /* Obtain an existing PKCS#7 signature */ - p7 = pkcs7_get_sigfile(ctx); - if (!p7) { - printf("Unable to extract valid signature\n"); - PKCS7_free(cursig); - return NULL; /* FAILED */ - } - } else if (ctx->options->cmd == CMD_SIGN) { - ASN1_OCTET_STRING *content; - /* Create a new PKCS#7 signature */ - p7 = pkcs7_create(ctx); - if (!p7) { - printf("Creating a new signature failed\n"); - return NULL; /* FAILED */ - } - if (!add_indirect_data_object(p7)) { - printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); - PKCS7_free(p7); - return NULL; /* FAILED */ - } - content = spc_indirect_data_content_get(hash, ctx); - if (!content) { - printf("Failed to get spcIndirectDataContent\n"); - return NULL; /* FAILED */ - } - if (!sign_spc_indirect_data_content(p7, content)) { - printf("Failed to set signed content\n"); - PKCS7_free(p7); - ASN1_OCTET_STRING_free(content); - return NULL; /* FAILED */ - } + if (!add_indirect_data_object(p7)) { + printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); + PKCS7_free(p7); + return NULL; /* FAILED */ + } + content = spc_indirect_data_content_get(hash, ctx); + if (!content) { + printf("Failed to get spcIndirectDataContent\n"); + return NULL; /* FAILED */ + } + if (!sign_spc_indirect_data_content(p7, content)) { + printf("Failed to set signed content\n"); + PKCS7_free(p7); ASN1_OCTET_STRING_free(content); - } - if (ctx->options->nest) - ctx->options->prevsig = cursig; + return NULL; /* FAILED */ + } + ASN1_OCTET_STRING_free(content); return p7; } @@ -829,18 +816,25 @@ static MSI_CTX *msi_ctx_get(char *indata, uint32_t filesize) return msi_ctx; /* OK */ } -static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds, - char **p, uint32_t len) +static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds) { PKCS7 *p7 = NULL; const u_char *blob; + char *p; + uint32_t len = GET_UINT32_LE(ds->size); - if (!msi_file_read(ctx->msi_ctx->msi, ds, 0, *p, len)) { + if (len == 0 || len >= MAXREGSECT) { + printf("Corrupted DigitalSignature stream length 0x%08X\n", len); + return NULL; /* FAILED */ + } + p = OPENSSL_malloc((size_t)len); + if (!msi_file_read(ctx->msi_ctx->msi, ds, 0, p, len)) { printf("DigitalSignature stream data error\n"); return NULL; } - blob = (u_char *)*p; + blob = (u_char *)p; p7 = d2i_PKCS7(NULL, &blob, len); + OPENSSL_free(p); if (!p7) { printf("Failed to extract PKCS7 data\n"); return NULL; diff --git a/osslsigncode.c b/osslsigncode.c index 0aa693bf..8a067b36 100644 --- a/osslsigncode.c +++ b/osslsigncode.c @@ -204,10 +204,12 @@ static time_t time_t_get_cms_time(CMS_ContentInfo *cms); static CMS_ContentInfo *cms_get_timestamp(PKCS7_SIGNED *p7_signed, PKCS7_SIGNER_INFO *countersignature); static int cursig_set_nested(PKCS7 *cursig, PKCS7 *p7); +static int nested_signatures_number_get(PKCS7 *p7); static int X509_attribute_chain_append_object(STACK_OF(X509_ATTRIBUTE) **unauth_attr, u_char *p, int len, const char *oid); static STACK_OF(PKCS7) *signature_list_create(PKCS7 *p7); static int PKCS7_compare(const PKCS7 *const *a, const PKCS7 *const *b); +static PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx); #ifdef ENABLE_CURL @@ -1120,6 +1122,37 @@ static int cursig_set_nested(PKCS7 *cursig, PKCS7 *p7) return 1; /* OK */ } +/* + * Return the number of objects in SPC_NESTED_SIGNATURE_OBJID attribute + * [in] p7: existing PKCS#7 signature (Primary Signature) + * [returns] -1 on error or the number of nested signatures + */ +static int nested_signatures_number_get(PKCS7 *p7) +{ + int i; + STACK_OF(X509_ATTRIBUTE) *unauth_attr; + PKCS7_SIGNER_INFO *si; + STACK_OF(PKCS7_SIGNER_INFO) *signer_info = PKCS7_get_signer_info(p7); + + if (!signer_info) + return -1; /* FAILED */ + si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0); + if (!si) + return -1; /* FAILED */ + unauth_attr = PKCS7_get_attributes(si); /* cont[1] */ + if (!unauth_attr) + return 0; /* OK, no unauthenticated attributes */ + for (i=0; ioptions->sigfile); + if (!filesize) { + return NULL; /* FAILED */ + } + indata = map_file(ctx->options->sigfile, filesize); + if (!indata) { + printf("Failed to open file: %s\n", ctx->options->sigfile); + return NULL; /* FAILED */ + } + p7 = pkcs7_read_data(indata, filesize); + unmap_file(indata, filesize); + return p7; +} + /* * [in] options: structure holds the input data * [returns] 1 on error or 0 on success @@ -2826,9 +2886,6 @@ static void free_options(GLOBAL_OPTIONS *options) /* If X509 structure is NULL nothing is done */ X509_free(options->cert); options->cert = NULL; - /* If PKCS7 structure is NULL nothing is done */ - PKCS7_free(options->prevsig); - options->prevsig = NULL; /* Free up all elements of sk structure and sk itself */ sk_X509_pop_free(options->certs, X509_free); options->certs = NULL; @@ -4208,7 +4265,7 @@ int main(int argc, char **argv) { FILE_FORMAT_CTX *ctx = NULL; GLOBAL_OPTIONS options; - PKCS7 *p7 = NULL; + PKCS7 *p7 = NULL, *cursig = NULL; BIO *outdata = NULL; BIO *hash = NULL; int ret = -1; @@ -4313,10 +4370,70 @@ int main(int argc, char **argv) ctx->format->update_data_size(ctx, outdata, NULL); } goto skip_signing; - } else if (ctx->format->pkcs7_prepare) { - p7 = ctx->format->pkcs7_prepare(ctx, hash, outdata); + } else if (options.cmd == CMD_ADD) { + if (!ctx->format->pkcs7_extract) { + DO_EXIT_0("Unsupported command: add\n"); + } + /* Obtain a current signature from previously-signed file */ + p7 = ctx->format->pkcs7_extract(ctx); if (!p7) { - DO_EXIT_0("Unable to prepare new signature\n"); + DO_EXIT_0("Unable to extract existing signature\n"); + } + if (ctx->format->process_data) { + ctx->format->process_data(ctx, hash, outdata); + } + } else if (options.cmd == CMD_ATTACH) { + if (options.nest) { + if (!ctx->format->pkcs7_extract_to_nest) { + printf("Warning: Unsupported nesting (multiple signature)\n"); + } else { + /* Obtain a current signature from previously-signed file */ + cursig = ctx->format->pkcs7_extract_to_nest(ctx); + if (!cursig) { + DO_EXIT_0("Unable to extract existing signature\n"); + } + options.nested_number = nested_signatures_number_get(cursig); + if (options.nested_number < 0) { + PKCS7_free(cursig); + DO_EXIT_0("Unable to get number of nested signatures\n"); + } + } + } + /* Obtain an existing PKCS#7 signature from a "sigin" file */ + p7 = pkcs7_get_sigfile(ctx); + if (!p7) { + printf("Unable to extract valid signature\n"); + PKCS7_free(cursig); + } + if (ctx->format->process_data) { + ctx->format->process_data(ctx, hash, outdata); + } + } else if (options.cmd == CMD_SIGN) { + if (options.nest) { + if (!ctx->format->pkcs7_extract_to_nest) { + printf("Warning: Unsupported nesting (multiple signature)\n"); + } else { + /* Obtain a current signature from previously-signed file */ + cursig = ctx->format->pkcs7_extract_to_nest(ctx); + if (!cursig) { + DO_EXIT_0("Unable to extract existing signature\n"); + } + options.nested_number = nested_signatures_number_get(cursig); + if (options.nested_number < 0) { + PKCS7_free(cursig); + DO_EXIT_0("Unable to get number of nested signatures\n"); + } + } + } + if (ctx->format->process_data) { + ctx->format->process_data(ctx, hash, outdata); + } + if (ctx->format->pkcs7_signature_new) { + /* Create a new PKCS#7 signature */ + p7 = ctx->format->pkcs7_signature_new(ctx, hash); + if (!p7) { + DO_EXIT_0("Unable to prepare new signature\n"); + } } } else { DO_EXIT_0("Unsupported command\n"); @@ -4331,13 +4448,13 @@ int main(int argc, char **argv) PKCS7_free(p7); DO_EXIT_0("Unable to set unauthenticated attributes\n"); } - if (options.prevsig) { + if (cursig) { /* CMD_SIGN or CMD_ATTACH */ - if (!cursig_set_nested(options.prevsig, p7)) + if (!cursig_set_nested(cursig, p7)) DO_EXIT_0("Unable to append the nested signature to the current signature\n"); PKCS7_free(p7); - p7 = options.prevsig; - options.prevsig = NULL; + p7 = cursig; + cursig = NULL; } if (ctx->format->append_pkcs7) { ret = ctx->format->append_pkcs7(ctx, outdata, p7); diff --git a/osslsigncode.h b/osslsigncode.h index ec283557..d5ff9849 100644 --- a/osslsigncode.h +++ b/osslsigncode.h @@ -288,7 +288,6 @@ typedef struct { STACK_OF(X509_CRL) *crls; cmd_type_t cmd; char *indata; - PKCS7 *prevsig; char *tsa_certfile; char *tsa_keyfile; time_t tsa_time; @@ -504,8 +503,10 @@ struct file_format_st { int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7); int (*verify_indirect_data) (FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj); PKCS7 *(*pkcs7_extract) (FILE_FORMAT_CTX *ctx); + PKCS7 *(*pkcs7_extract_to_nest) (FILE_FORMAT_CTX *ctx); int (*remove_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); - PKCS7 *(*pkcs7_prepare) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); + int (*process_data) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); + PKCS7 *(*pkcs7_signature_new) (FILE_FORMAT_CTX *ctx, BIO *hash); int (*append_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); void (*update_data_size) (FILE_FORMAT_CTX *data, BIO *outdata, PKCS7 *p7); BIO *(*bio_free) (BIO *hash, BIO *outdata); diff --git a/pe.c b/pe.c index e883205d..9fcea547 100644 --- a/pe.c +++ b/pe.c @@ -51,8 +51,10 @@ static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md); static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj); static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx); +static PKCS7 *pe_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx); static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); -static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); +static int pe_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); +static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash); static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static BIO *pe_bio_free(BIO *hash, BIO *outdata); @@ -68,8 +70,10 @@ FILE_FORMAT file_format_pe = { .verify_digests = pe_verify_digests, .verify_indirect_data = pe_verify_indirect_data, .pkcs7_extract = pe_pkcs7_extract, + .pkcs7_extract_to_nest = pe_pkcs7_extract_to_nest, .remove_pkcs7 = pe_remove_pkcs7, - .pkcs7_prepare = pe_pkcs7_prepare, + .process_data = pe_process_data, + .pkcs7_signature_new = pe_pkcs7_signature_new, .append_pkcs7 = pe_append_pkcs7, .update_data_size = pe_update_data_size, .bio_free = pe_bio_free, @@ -381,6 +385,16 @@ static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx) return pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx); } +/* + * Extract existing signature in DER format. + * [in] ctx: structure holds input and output data + * [returns] pointer to PKCS#7 structure + */ +static PKCS7 *pe_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx) +{ + return pe_pkcs7_extract(ctx); +} + /* * Remove existing signature. * [in, out] ctx: structure holds input and output data @@ -404,78 +418,57 @@ static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) } /* - * Obtain an existing signature or create a new one. + * Modify specific type data and calculate a hash (message digest) of data. * [in, out] ctx: structure holds input and output data * [out] hash: message digest BIO * [out] outdata: outdata file BIO - * [returns] pointer to PKCS#7 structure + * [returns] 1 on error or 0 on success */ -static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) +static int pe_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) { - PKCS7 *cursig = NULL, *p7 = NULL; - - /* Obtain a current signature from previously-signed file */ - if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest) - || (ctx->options->cmd == CMD_ATTACH && ctx->options->nest) - || ctx->options->cmd == CMD_ADD) { - cursig = pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx); - if (!cursig) { - printf("Unable to extract existing signature\n"); - return NULL; /* FAILED */ - } - ctx->options->nested_number = nested_signatures_number_get(cursig); - if (ctx->options->nested_number < 0) { - printf("Unable to get number of nested signatures\n"); - PKCS7_free(cursig); - return NULL; /* FAILED */ - } - if (ctx->options->cmd == CMD_ADD) - p7 = cursig; - } if (ctx->pe_ctx->sigpos > 0) { /* Strip current signature */ ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos; } if (!pe_modify_header(ctx, hash, outdata)) { printf("Unable to modify file header\n"); + return 1; /* FAILED */ + } + return 0; /* OK */ +} + +/* + * Create a new PKCS#7 signature. + * [in, out] ctx: structure holds input and output data + * [out] hash: message digest BIO + * [returns] pointer to PKCS#7 structure + */ +static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash) +{ + ASN1_OCTET_STRING *content; + PKCS7 *p7 = pkcs7_create(ctx); + + if (!p7) { + printf("Creating a new signature failed\n"); return NULL; /* FAILED */ } - if (ctx->options->cmd == CMD_ATTACH) { - /* Obtain an existing PKCS#7 signature */ - p7 = pkcs7_get_sigfile(ctx); - if (!p7) { - printf("Unable to extract valid signature\n"); - PKCS7_free(cursig); - return NULL; /* FAILED */ - } - } else if (ctx->options->cmd == CMD_SIGN) { - ASN1_OCTET_STRING *content; - /* Create a new PKCS#7 signature */ - p7 = pkcs7_create(ctx); - if (!p7) { - printf("Creating a new signature failed\n"); - return NULL; /* FAILED */ - } - if (!add_indirect_data_object(p7)) { - printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); - PKCS7_free(p7); - return NULL; /* FAILED */ - } - content = spc_indirect_data_content_get(hash, ctx); - if (!content) { - printf("Failed to get spcIndirectDataContent\n"); - return NULL; /* FAILED */ - } - if (!sign_spc_indirect_data_content(p7, content)) { - printf("Failed to set signed content\n"); - PKCS7_free(p7); - ASN1_OCTET_STRING_free(content); - return NULL; /* FAILED */ - } + if (!add_indirect_data_object(p7)) { + printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); + PKCS7_free(p7); + return NULL; /* FAILED */ + } + content = spc_indirect_data_content_get(hash, ctx); + if (!content) { + printf("Failed to get spcIndirectDataContent\n"); + return NULL; /* FAILED */ + } + if (!sign_spc_indirect_data_content(p7, content)) { + printf("Failed to set signed content\n"); + PKCS7_free(p7); ASN1_OCTET_STRING_free(content); + return NULL; /* FAILED */ } - if (ctx->options->nest) - ctx->options->prevsig = cursig; + ASN1_OCTET_STRING_free(content); return p7; }