diff --git a/appx.c b/appx.c index f043d35..2af4f7a 100644 --- a/appx.c +++ b/appx.c @@ -233,6 +233,7 @@ struct appx_ctx_st { /* FILE_FORMAT method prototypes */ static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); +static const EVP_MD *appx_md_get(FILE_FORMAT_CTX *ctx); static ASN1_OBJECT *appx_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx); static int appx_hash_length_get(FILE_FORMAT_CTX *ctx); static int appx_check_file(FILE_FORMAT_CTX *ctx, int detached); @@ -246,6 +247,7 @@ static void appx_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); FILE_FORMAT file_format_appx = { .ctx_new = appx_ctx_new, + .md_get = appx_md_get, .data_blob_get = appx_spc_sip_info_get, .hash_length_get = appx_hash_length_get, .check_file = appx_check_file, @@ -359,6 +361,16 @@ static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *ou return ctx; } +/* + * Return a hash algorithm specified in the AppxBlockMap.xml file. + * [in] ctx: structure holds input and output data + * [returns] hash algorithm + */ +static const EVP_MD *appx_md_get(FILE_FORMAT_CTX *ctx) +{ + return ctx->appx_ctx->md; +} + /* * Allocate and return SpcSipInfo object. * [out] p: SpcSipInfo data @@ -542,6 +554,7 @@ 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. * [in, out] ctx: structure holds input and output data * [out] hash: message digest BIO (unused) * [out] outdata: outdata file BIO (unused) @@ -549,35 +562,42 @@ 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) { - PKCS7 *cursig = NULL, *p7 = NULL; + ZIP_CENTRAL_DIRECTORY_ENTRY *entry; + PKCS7 *p7 = NULL; /* squash unused parameter warnings */ (void)outdata; (void)hash; - if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) { + if (ctx->options->cmd == CMD_ADD) { /* Obtain an existing signature */ - cursig = appx_pkcs7_extract(ctx); - if (!cursig) { + p7 = appx_pkcs7_extract(ctx); + if (!p7) { printf("Unable to extract existing signature\n"); return NULL; /* FAILED */ } - return cursig; - } else if (ctx->options->cmd == CMD_SIGN) { - BIO *hashes; - ZIP_CENTRAL_DIRECTORY_ENTRY *entry; + return p7; + } - /* Create a new signature */ - entry = zipGetCDEntryByName(ctx->appx_ctx->zip, CONTENT_TYPES_FILENAME); - if (!entry) { - printf("Not a valid .appx file: content types file missing\n"); + /* 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 */ + } + if (!appx_append_ct_signature_entry(ctx->appx_ctx->zip, entry)) { + 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 */ } - if (!appx_append_ct_signature_entry(ctx->appx_ctx->zip, entry)) { - return NULL; /* FAILED */ - } - /* create hash blob from concatenated APPX hashes */ - hashes = appx_calculate_hashes(ctx); + } else if (ctx->options->cmd == CMD_SIGN) { + /* Create hash blob from concatenated APPX hashes */ + BIO *hashes = appx_calculate_hashes(ctx); if (!hashes) { return NULL; /* FAILED */ } diff --git a/helpers.c b/helpers.c index c641686..2cc45e5 100644 --- a/helpers.c +++ b/helpers.c @@ -542,11 +542,16 @@ static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx) static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx) { u_char *p = NULL; - int hashlen, l = 0; - int mdtype = EVP_MD_nid(ctx->options->md); + int mdtype, hashlen, l = 0; void *hash; SpcIndirectDataContent *idc = SpcIndirectDataContent_new(); + if (ctx->format->md_get) { + /* APPX file specific - use a hash algorithm specified in the AppxBlockMap.xml file */ + mdtype = EVP_MD_nid(ctx->format->md_get(ctx)); + } else { + mdtype = EVP_MD_nid(ctx->options->md); + } idc->data->value = ASN1_TYPE_new(); idc->data->value->type = V_ASN1_SEQUENCE; idc->data->value->value.sequence = ASN1_STRING_new(); diff --git a/osslsigncode.h b/osslsigncode.h index 968c364..e85e3fa 100644 --- a/osslsigncode.h +++ b/osslsigncode.h @@ -491,6 +491,7 @@ extern FILE_FORMAT file_format_appx; struct file_format_st { FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata); + const EVP_MD *(*md_get) (FILE_FORMAT_CTX *ctx); ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx); int (*hash_length_get) (FILE_FORMAT_CTX *ctx); int (*check_file) (FILE_FORMAT_CTX *ctx, int detached);