mirror of
https://github.com/mtrojnar/osslsigncode.git
synced 2025-04-04 17:00:11 -05:00
Add a new command extract-data to extract a PKCS#7 data content to be signed
This commit is contained in:
parent
46bcaa9d88
commit
64e1bba96b
1
NEWS.md
1
NEWS.md
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
- added CAT file verification and listing each member of the CAT file
|
- added CAT file verification and listing each member of the CAT file
|
||||||
by using the "-verbose" option
|
by using the "-verbose" option
|
||||||
|
- added new command "extract-data" to extract a PKCS#7 data content to be signed
|
||||||
|
|
||||||
### 2.7 (2023.09.19)
|
### 2.7 (2023.09.19)
|
||||||
|
|
||||||
|
55
appx.c
55
appx.c
@ -235,6 +235,7 @@ struct appx_ctx_st {
|
|||||||
static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
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 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 ASN1_OBJECT *appx_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *appx_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
static int appx_hash_length_get(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);
|
static int appx_check_file(FILE_FORMAT_CTX *ctx, int detached);
|
||||||
static int appx_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
static int appx_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
||||||
@ -249,6 +250,7 @@ FILE_FORMAT file_format_appx = {
|
|||||||
.ctx_new = appx_ctx_new,
|
.ctx_new = appx_ctx_new,
|
||||||
.md_get = appx_md_get,
|
.md_get = appx_md_get,
|
||||||
.data_blob_get = appx_spc_sip_info_get,
|
.data_blob_get = appx_spc_sip_info_get,
|
||||||
|
.pkcs7_contents_get = appx_pkcs7_contents_get,
|
||||||
.hash_length_get = appx_hash_length_get,
|
.hash_length_get = appx_hash_length_get,
|
||||||
.check_file = appx_check_file,
|
.check_file = appx_check_file,
|
||||||
.verify_digests = appx_verify_digests,
|
.verify_digests = appx_verify_digests,
|
||||||
@ -349,7 +351,8 @@ static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *ou
|
|||||||
if (options->nest)
|
if (options->nest)
|
||||||
/* I've not tried using set_nested_signature as signtool won't do this */
|
/* 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");
|
printf("Warning: APPX files do not support nesting (multiple signature)\n");
|
||||||
if (options->cmd == CMD_SIGN || options->cmd==CMD_ATTACH || options->cmd==CMD_ADD) {
|
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");
|
printf("Warning: Ignore -h option, use the hash algorithm specified in AppxBlockMap.xml\n");
|
||||||
}
|
}
|
||||||
if (options->pagehash == 1)
|
if (options->pagehash == 1)
|
||||||
@ -406,6 +409,41 @@ static ASN1_OBJECT *appx_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX
|
|||||||
return dtype; /* OK */
|
return dtype; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a data content to be signed.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] data content
|
||||||
|
*/
|
||||||
|
static PKCS7 *appx_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
ZIP_CENTRAL_DIRECTORY_ENTRY *entry;
|
||||||
|
BIO *bhash;
|
||||||
|
|
||||||
|
/* squash unused parameter warnings */
|
||||||
|
(void)md;
|
||||||
|
(void)hash;
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
}
|
||||||
|
bhash = appx_calculate_hashes(ctx);
|
||||||
|
if (!bhash) {
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(bhash, ctx);
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return pkcs7_set_content(content);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get concatenated hashes length.
|
* Get concatenated hashes length.
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
@ -596,6 +634,7 @@ static PKCS7 *appx_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
} else if (ctx->options->cmd == CMD_SIGN) {
|
} else if (ctx->options->cmd == CMD_SIGN) {
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
/* Create hash blob from concatenated APPX hashes */
|
/* Create hash blob from concatenated APPX hashes */
|
||||||
BIO *hashes = appx_calculate_hashes(ctx);
|
BIO *hashes = appx_calculate_hashes(ctx);
|
||||||
if (!hashes) {
|
if (!hashes) {
|
||||||
@ -605,19 +644,29 @@ static PKCS7 *appx_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
p7 = pkcs7_create(ctx);
|
p7 = pkcs7_create(ctx);
|
||||||
if (!p7) {
|
if (!p7) {
|
||||||
printf("Creating a new signature failed\n");
|
printf("Creating a new signature failed\n");
|
||||||
|
BIO_free_all(hashes);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!add_indirect_data_object(p7)) {
|
if (!add_indirect_data_object(p7)) {
|
||||||
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
||||||
|
PKCS7_free(p7);
|
||||||
BIO_free_all(hashes);
|
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);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!sign_spc_indirect_data_content(p7, hashes, ctx)) {
|
if (!sign_spc_indirect_data_content(p7, content)) {
|
||||||
printf("Failed to set signed content\n");
|
printf("Failed to set signed content\n");
|
||||||
|
PKCS7_free(p7);
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
BIO_free_all(hashes);
|
ASN1_OCTET_STRING_free(content);
|
||||||
}
|
}
|
||||||
return p7; /* OK */
|
return p7; /* OK */
|
||||||
}
|
}
|
||||||
|
48
cab.c
48
cab.c
@ -43,6 +43,7 @@ struct cab_ctx_st {
|
|||||||
/* FILE_FORMAT method prototypes */
|
/* FILE_FORMAT method prototypes */
|
||||||
static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
||||||
static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *cab_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
static int cab_hash_length_get(FILE_FORMAT_CTX *ctx);
|
static int cab_hash_length_get(FILE_FORMAT_CTX *ctx);
|
||||||
static int cab_check_file(FILE_FORMAT_CTX *ctx, int detached);
|
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 u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
@ -58,6 +59,7 @@ static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
|||||||
FILE_FORMAT file_format_cab = {
|
FILE_FORMAT file_format_cab = {
|
||||||
.ctx_new = cab_ctx_new,
|
.ctx_new = cab_ctx_new,
|
||||||
.data_blob_get = cab_obsolete_link_get,
|
.data_blob_get = cab_obsolete_link_get,
|
||||||
|
.pkcs7_contents_get = cab_pkcs7_contents_get,
|
||||||
.hash_length_get = cab_hash_length_get,
|
.hash_length_get = cab_hash_length_get,
|
||||||
.check_file = cab_check_file,
|
.check_file = cab_check_file,
|
||||||
.digest_calc = cab_digest_calc,
|
.digest_calc = cab_digest_calc,
|
||||||
@ -151,6 +153,32 @@ static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX
|
|||||||
return dtype; /* OK */
|
return dtype; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a data content to be signed.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] data content
|
||||||
|
*/
|
||||||
|
static PKCS7 *cab_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
|
||||||
|
/* squash the unused parameter warning, use initialized message digest BIO */
|
||||||
|
(void)md;
|
||||||
|
|
||||||
|
/* Strip current signature and modify header */
|
||||||
|
if (ctx->cab_ctx->header_size == 20) {
|
||||||
|
if (!cab_modify_header(ctx, hash, NULL))
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
} else {
|
||||||
|
if (!cab_add_header(ctx, hash, NULL))
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
|
return pkcs7_set_content(content);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
||||||
@ -363,11 +391,14 @@ 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(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
|
const u_char *blob;
|
||||||
|
|
||||||
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|
||||||
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
|
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
return pkcs7_get(ctx->options->indata, ctx->cab_ctx->sigpos, ctx->cab_ctx->siglen);
|
blob = (u_char *)ctx->options->indata + ctx->cab_ctx->sigpos;
|
||||||
|
return d2i_PKCS7(NULL, &blob, ctx->cab_ctx->siglen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -470,7 +501,7 @@ static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest)
|
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest)
|
||||||
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest)
|
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest)
|
||||||
|| ctx->options->cmd == CMD_ADD) {
|
|| ctx->options->cmd == CMD_ADD) {
|
||||||
cursig = pkcs7_get(ctx->options->indata, ctx->cab_ctx->sigpos, ctx->cab_ctx->siglen);
|
cursig = cab_pkcs7_extract(ctx);
|
||||||
if (!cursig) {
|
if (!cursig) {
|
||||||
printf("Unable to extract existing signature\n");
|
printf("Unable to extract existing signature\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
@ -487,6 +518,7 @@ static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
} else if (ctx->options->cmd == CMD_SIGN) {
|
} else if (ctx->options->cmd == CMD_SIGN) {
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
/* Create a new PKCS#7 signature */
|
/* Create a new PKCS#7 signature */
|
||||||
p7 = pkcs7_create(ctx);
|
p7 = pkcs7_create(ctx);
|
||||||
if (!p7) {
|
if (!p7) {
|
||||||
@ -503,10 +535,18 @@ static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
PKCS7_free(p7);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!sign_spc_indirect_data_content(p7, hash, ctx)) {
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
printf("Failed to set signed content\n");
|
if (!content) {
|
||||||
|
printf("Failed to get spcIndirectDataContent\n");
|
||||||
return NULL; /* FAILED */
|
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);
|
||||||
}
|
}
|
||||||
if (ctx->options->nest)
|
if (ctx->options->nest)
|
||||||
ctx->options->prevsig = cursig;
|
ctx->options->prevsig = cursig;
|
||||||
|
47
cat.c
47
cat.c
@ -10,11 +10,6 @@
|
|||||||
#include "osslsigncode.h"
|
#include "osslsigncode.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
const u_char pkcs7_signed_data[] = {
|
|
||||||
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
|
||||||
0x01, 0x07, 0x02,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ASN1_BMPSTRING *tag;
|
ASN1_BMPSTRING *tag;
|
||||||
ASN1_INTEGER *flags;
|
ASN1_INTEGER *flags;
|
||||||
@ -86,7 +81,7 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
CAT_CTX *cat_ctx;
|
CAT_CTX *cat_ctx;
|
||||||
uint32_t filesize;
|
uint32_t filesize;
|
||||||
|
|
||||||
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH) {
|
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH || options->cmd == CMD_EXTRACT_DATA) {
|
||||||
printf("Unsupported command\n");
|
printf("Unsupported command\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -98,12 +93,6 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
if (!options->indata) {
|
if (!options->indata) {
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* the maximum size of a supported cat file is (2^24 -1) bytes */
|
|
||||||
if (memcmp(options->indata + ((GET_UINT8_LE(options->indata+1) == 0x82) ? 4 : 5),
|
|
||||||
pkcs7_signed_data, sizeof pkcs7_signed_data)) {
|
|
||||||
unmap_file(options->indata, filesize);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
cat_ctx = cat_ctx_get(options->indata, filesize);
|
cat_ctx = cat_ctx_get(options->indata, filesize);
|
||||||
if (!cat_ctx) {
|
if (!cat_ctx) {
|
||||||
unmap_file(options->indata, filesize);
|
unmap_file(options->indata, filesize);
|
||||||
@ -200,7 +189,7 @@ static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
|
|
||||||
/* Obtain an existing signature */
|
/* Obtain an existing signature */
|
||||||
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) {
|
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) {
|
||||||
p7 = PKCS7_dup(ctx->cat_ctx->p7);
|
p7 = cat_pkcs7_extract(ctx);
|
||||||
} else if (ctx->options->cmd == CMD_SIGN) {
|
} else if (ctx->options->cmd == CMD_SIGN) {
|
||||||
/* Create a new signature */
|
/* Create a new signature */
|
||||||
p7 = pkcs7_create(ctx);
|
p7 = pkcs7_create(ctx);
|
||||||
@ -224,29 +213,14 @@ static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Append signature to the outfile.
|
* Append signature to the outfile.
|
||||||
* [in, out] ctx: structure holds input and output data (unused)
|
* [in, out] ctx: structure holds input and output data
|
||||||
* [out] outdata: outdata file BIO
|
* [out] outdata: outdata file BIO
|
||||||
* [in] p7: PKCS#7 signature
|
* [in] p7: PKCS#7 signature
|
||||||
* [returns] 1 on error or 0 on success
|
* [returns] 1 on error or 0 on success
|
||||||
*/
|
*/
|
||||||
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||||
{
|
{
|
||||||
u_char *p = NULL;
|
return data_write_pkcs7(ctx, outdata, p7);
|
||||||
int len; /* signature length */
|
|
||||||
|
|
||||||
/* squash the unused parameter warning */
|
|
||||||
(void)ctx;
|
|
||||||
|
|
||||||
if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|
|
||||||
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
|
||||||
printf("i2d_PKCS memory allocation failed: %d\n", len);
|
|
||||||
return 1; /* FAILED */
|
|
||||||
}
|
|
||||||
i2d_PKCS7(p7, &p);
|
|
||||||
p -= len;
|
|
||||||
i2d_PKCS7_bio(outdata, p7);
|
|
||||||
OPENSSL_free(p);
|
|
||||||
return 0; /* OK */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -288,18 +262,23 @@ static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify mapped CAT file and create CAT format specific structure.
|
* Verify mapped PKCS#7 (CAT) file and create CAT format specific structure.
|
||||||
* [in] indata: mapped CAT file (unused)
|
* [in] indata: mapped file
|
||||||
* [in] filesize: size of CAT file
|
* [in] filesize: size of file
|
||||||
* [returns] pointer to CAT format specific structure
|
* [returns] pointer to CAT format specific structure
|
||||||
*/
|
*/
|
||||||
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
|
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
|
||||||
{
|
{
|
||||||
CAT_CTX *cat_ctx;
|
CAT_CTX *cat_ctx;
|
||||||
PKCS7 *p7 = pkcs7_get(indata, 0, filesize);
|
PKCS7 *p7;
|
||||||
|
|
||||||
|
p7 = pkcs7_read_data(indata, filesize);
|
||||||
if (!p7)
|
if (!p7)
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
|
if (!PKCS7_type_is_signed(p7)) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
|
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
|
||||||
cat_ctx->p7 = p7;
|
cat_ctx->p7 = p7;
|
||||||
cat_ctx->sigpos = 0;
|
cat_ctx->sigpos = 0;
|
||||||
|
191
helpers.c
191
helpers.c
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx);
|
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);
|
static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx);
|
||||||
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
||||||
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
||||||
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer);
|
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer);
|
||||||
@ -138,8 +138,6 @@ PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx)
|
|||||||
PKCS7 *p7 = NULL;
|
PKCS7 *p7 = NULL;
|
||||||
uint32_t filesize;
|
uint32_t filesize;
|
||||||
char *indata;
|
char *indata;
|
||||||
BIO *bio;
|
|
||||||
const char pemhdr[] = "-----BEGIN PKCS7-----";
|
|
||||||
|
|
||||||
filesize = get_file_size(ctx->options->sigfile);
|
filesize = get_file_size(ctx->options->sigfile);
|
||||||
if (!filesize) {
|
if (!filesize) {
|
||||||
@ -150,18 +148,58 @@ PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx)
|
|||||||
printf("Failed to open file: %s\n", ctx->options->sigfile);
|
printf("Failed to open file: %s\n", ctx->options->sigfile);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
bio = BIO_new_mem_buf(indata, (int)filesize);
|
p7 = pkcs7_read_data(indata, filesize);
|
||||||
if (filesize >= sizeof pemhdr && !memcmp(indata, pemhdr, sizeof pemhdr - 1)) {
|
unmap_file(indata, filesize);
|
||||||
|
return p7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve a decoded PKCS#7 structure
|
||||||
|
* [in] data: encoded PEM or DER data
|
||||||
|
* [in] size: data size
|
||||||
|
* [returns] pointer to PKCS#7 structure
|
||||||
|
*/
|
||||||
|
PKCS7 *pkcs7_read_data(char *data, uint32_t size)
|
||||||
|
{
|
||||||
|
PKCS7 *p7 = NULL;
|
||||||
|
BIO *bio;
|
||||||
|
const char pemhdr[] = "-----BEGIN PKCS7-----";
|
||||||
|
|
||||||
|
bio = BIO_new_mem_buf(data, (int)size);
|
||||||
|
if (size >= sizeof pemhdr && !memcmp(data, pemhdr, sizeof pemhdr - 1)) {
|
||||||
/* PEM format */
|
/* PEM format */
|
||||||
p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
|
p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
|
||||||
} else { /* DER format */
|
} else { /* DER format */
|
||||||
p7 = d2i_PKCS7_bio(bio, NULL);
|
p7 = d2i_PKCS7_bio(bio, NULL);
|
||||||
}
|
}
|
||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
unmap_file(indata, filesize);
|
|
||||||
return p7;
|
return p7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [out] outdata: BIO outdata file
|
||||||
|
* [in] p7: PKCS#7 signature
|
||||||
|
* [returns] 1 on error or 0 on success
|
||||||
|
*/
|
||||||
|
int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
(void)BIO_reset(outdata);
|
||||||
|
if (ctx->options->output_pkcs7) {
|
||||||
|
/* PEM format */
|
||||||
|
ret = !PEM_write_bio_PKCS7(outdata, p7);
|
||||||
|
} else {
|
||||||
|
/* default DER format */
|
||||||
|
ret = !i2d_PKCS7_bio(outdata, p7);
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
printf("Unable to write pkcs7 object\n");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate, set type, add content and return a new PKCS#7 signature
|
* Allocate, set type, add content and return a new PKCS#7 signature
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
@ -262,47 +300,32 @@ int add_indirect_data_object(PKCS7 *p7)
|
|||||||
* The spcIndirectDataContent structure is used in Authenticode signatures
|
* The spcIndirectDataContent structure is used in Authenticode signatures
|
||||||
* to store the digest and other attributes of the signed file.
|
* to store the digest and other attributes of the signed file.
|
||||||
* [in, out] p7: new PKCS#7 signature
|
* [in, out] p7: new PKCS#7 signature
|
||||||
* [in] hash: message digest BIO
|
* [in] content: spcIndirectDataContent
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [returns] 0 on error or 1 on success
|
* [returns] 0 on error or 1 on success
|
||||||
*/
|
*/
|
||||||
int sign_spc_indirect_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
int sign_spc_indirect_data_content(PKCS7 *p7, ASN1_OCTET_STRING *content)
|
||||||
{
|
{
|
||||||
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
|
int len, hdrlen;
|
||||||
int mdlen, seqhdrlen, hashlen;
|
const u_char *data;
|
||||||
PKCS7 *td7;
|
PKCS7 *td7;
|
||||||
u_char *p = NULL;
|
|
||||||
int len = 0;
|
|
||||||
u_char *buf;
|
|
||||||
|
|
||||||
hashlen = ctx->format->hash_length_get(ctx);
|
data = ASN1_STRING_get0_data(content);
|
||||||
if (hashlen > EVP_MAX_MD_SIZE) {
|
len = ASN1_STRING_length(content);
|
||||||
/* APPX format specific */
|
hdrlen = ASN1_object_size(0, len, V_ASN1_SEQUENCE) - len;
|
||||||
mdlen = BIO_read(hash, (char*)mdbuf, hashlen);
|
|
||||||
} else {
|
|
||||||
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE);
|
|
||||||
}
|
|
||||||
if (!spc_indirect_data_content_get(&p, &len, ctx))
|
|
||||||
return 0; /* FAILED */
|
|
||||||
|
|
||||||
buf = OPENSSL_malloc(SIZE_64K);
|
if (!pkcs7_sign_content(p7, data + hdrlen, len - hdrlen)) {
|
||||||
memcpy(buf, p, (size_t)len);
|
printf("Failed to sign spcIndirectDataContent\n");
|
||||||
OPENSSL_free(p);
|
|
||||||
memcpy(buf + len, mdbuf, (size_t)mdlen);
|
|
||||||
seqhdrlen = asn1_simple_hdr_len(buf, len);
|
|
||||||
|
|
||||||
if (!pkcs7_sign_content(p7, buf + seqhdrlen, len - seqhdrlen + mdlen)) {
|
|
||||||
printf("Failed to sign content\n");
|
|
||||||
OPENSSL_free(buf);
|
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
td7 = PKCS7_new();
|
td7 = PKCS7_new();
|
||||||
|
if (!td7) {
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
|
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
|
||||||
td7->d.other = ASN1_TYPE_new();
|
td7->d.other = ASN1_TYPE_new();
|
||||||
td7->d.other->type = V_ASN1_SEQUENCE;
|
td7->d.other->type = V_ASN1_SEQUENCE;
|
||||||
td7->d.other->value.sequence = ASN1_STRING_new();
|
td7->d.other->value.sequence = ASN1_STRING_new();
|
||||||
ASN1_STRING_set(td7->d.other->value.sequence, buf, len + mdlen);
|
ASN1_STRING_set(td7->d.other->value.sequence, data, len);
|
||||||
OPENSSL_free(buf);
|
|
||||||
if (!PKCS7_set_content(p7, td7)) {
|
if (!PKCS7_set_content(p7, td7)) {
|
||||||
printf("PKCS7_set_content failed\n");
|
printf("PKCS7_set_content failed\n");
|
||||||
PKCS7_free(td7);
|
PKCS7_free(td7);
|
||||||
@ -311,13 +334,92 @@ int sign_spc_indirect_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
|||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add encapsulated content to signed PKCS7 structure.
|
||||||
|
* [in] content: spcIndirectDataContent
|
||||||
|
* [returns] new PKCS#7 signature with encapsulated content
|
||||||
|
*/
|
||||||
|
PKCS7 *pkcs7_set_content(ASN1_OCTET_STRING *content)
|
||||||
|
{
|
||||||
|
PKCS7 *p7, *td7;
|
||||||
|
|
||||||
|
p7 = PKCS7_new();
|
||||||
|
if (!p7) {
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!PKCS7_set_type(p7, NID_pkcs7_signed)) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!PKCS7_content_new(p7, NID_pkcs7_data)) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
td7 = PKCS7_new();
|
||||||
|
if (!td7) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
|
||||||
|
td7->d.other = ASN1_TYPE_new();
|
||||||
|
td7->d.other->type = V_ASN1_SEQUENCE;
|
||||||
|
td7->d.other->value.sequence = content;
|
||||||
|
if (!PKCS7_set_content(p7, td7)) {
|
||||||
|
PKCS7_free(td7);
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
return p7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return spcIndirectDataContent.
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] content
|
||||||
|
*/
|
||||||
|
ASN1_OCTET_STRING *spc_indirect_data_content_get(BIO *hash, FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
|
||||||
|
int mdlen, hashlen, len = 0;
|
||||||
|
u_char *data, *p = NULL;
|
||||||
|
|
||||||
|
content = ASN1_OCTET_STRING_new();
|
||||||
|
if (!content) {
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!spc_indirect_data_content_create(&p, &len, ctx)) {
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
hashlen = ctx->format->hash_length_get(ctx);
|
||||||
|
if (hashlen > EVP_MAX_MD_SIZE) {
|
||||||
|
/* APPX format specific */
|
||||||
|
mdlen = BIO_read(hash, (char*)mdbuf, hashlen);
|
||||||
|
} else {
|
||||||
|
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE);
|
||||||
|
}
|
||||||
|
data = OPENSSL_malloc((size_t)(len + mdlen));
|
||||||
|
memcpy(data, p, (size_t)len);
|
||||||
|
OPENSSL_free(p);
|
||||||
|
memcpy(data + len, mdbuf, (size_t)mdlen);
|
||||||
|
if (!ASN1_OCTET_STRING_set(content, data, len + mdlen)) {
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
|
OPENSSL_free(data);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
OPENSSL_free(data);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signs the data and place the signature in p7
|
* Signs the data and place the signature in p7
|
||||||
* [in, out] p7: new PKCS#7 signature
|
* [in, out] p7: new PKCS#7 signature
|
||||||
* [in] data: content data
|
* [in] data: content data
|
||||||
* [in] len: content length
|
* [in] len: content length
|
||||||
*/
|
*/
|
||||||
int pkcs7_sign_content(PKCS7 *p7, u_char *data, int len)
|
int pkcs7_sign_content(PKCS7 *p7, const u_char *data, int len)
|
||||||
{
|
{
|
||||||
BIO *p7bio;
|
BIO *p7bio;
|
||||||
|
|
||||||
@ -472,23 +574,6 @@ SpcLink *spc_link_obsolete_get(void)
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Retrieve a decoded PKCS#7 structure
|
|
||||||
* [in] indata: mapped file
|
|
||||||
* [in] sigpos: signature data offset
|
|
||||||
* [in] siglen: signature data size
|
|
||||||
* [returns] pointer to PKCS#7 structure
|
|
||||||
*/
|
|
||||||
PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen)
|
|
||||||
{
|
|
||||||
PKCS7 *p7 = NULL;
|
|
||||||
const u_char *blob;
|
|
||||||
|
|
||||||
blob = (u_char *)indata + sigpos;
|
|
||||||
p7 = d2i_PKCS7(NULL, &blob, siglen);
|
|
||||||
return p7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] mdbuf, cmdbuf: message digests
|
* [in] mdbuf, cmdbuf: message digests
|
||||||
* [in] mdtype: message digest algorithm type
|
* [in] mdtype: message digest algorithm type
|
||||||
@ -539,7 +624,7 @@ static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx)
|
|||||||
* [in] ctx: FILE_FORMAT_CTX structure
|
* [in] ctx: FILE_FORMAT_CTX structure
|
||||||
* [returns] 0 on error or 1 on success
|
* [returns] 0 on error or 1 on success
|
||||||
*/
|
*/
|
||||||
static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx)
|
static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
u_char *p = NULL;
|
u_char *p = NULL;
|
||||||
int mdtype, hashlen, l = 0;
|
int mdtype, hashlen, l = 0;
|
||||||
|
@ -11,10 +11,14 @@ char *map_file(const char *infile, const size_t size);
|
|||||||
void unmap_file(char *indata, const size_t size);
|
void unmap_file(char *indata, const size_t size);
|
||||||
int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
||||||
PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx);
|
PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx);
|
||||||
|
PKCS7 *pkcs7_read_data(char *indata, uint32_t size);
|
||||||
|
int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx);
|
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx);
|
||||||
int add_indirect_data_object(PKCS7 *p7);
|
int add_indirect_data_object(PKCS7 *p7);
|
||||||
int sign_spc_indirect_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx);
|
int sign_spc_indirect_data_content(PKCS7 *p7, ASN1_OCTET_STRING *content);
|
||||||
int pkcs7_sign_content(PKCS7 *p7, u_char *data, int len);
|
PKCS7 *pkcs7_set_content(ASN1_OCTET_STRING *content);
|
||||||
|
ASN1_OCTET_STRING *spc_indirect_data_content_get(BIO *hash, FILE_FORMAT_CTX *ctx);
|
||||||
|
int pkcs7_sign_content(PKCS7 *p7, const u_char *data, int len);
|
||||||
int asn1_simple_hdr_len(const u_char *p, int len);
|
int asn1_simple_hdr_len(const u_char *p, int len);
|
||||||
int bio_hash_data(BIO *hash, char *indata, size_t idx, size_t fileend);
|
int bio_hash_data(BIO *hash, char *indata, size_t idx, size_t fileend);
|
||||||
void print_hash(const char *descript1, const char *descript2, const u_char *hashbuf, int length);
|
void print_hash(const char *descript1, const char *descript2, const u_char *hashbuf, int length);
|
||||||
@ -22,7 +26,6 @@ int is_content_type(PKCS7 *p7, const char *objid);
|
|||||||
MsCtlContent *ms_ctl_content_get(PKCS7 *p7);
|
MsCtlContent *ms_ctl_content_get(PKCS7 *p7);
|
||||||
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute);
|
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute);
|
||||||
SpcLink *spc_link_obsolete_get(void);
|
SpcLink *spc_link_obsolete_get(void);
|
||||||
PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen);
|
|
||||||
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
|
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
69
msi.c
69
msi.c
@ -215,6 +215,7 @@ struct msi_ctx_st {
|
|||||||
/* FILE_FORMAT method prototypes */
|
/* FILE_FORMAT method prototypes */
|
||||||
static FILE_FORMAT_CTX *msi_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
static FILE_FORMAT_CTX *msi_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
||||||
static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *msi_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
static int msi_hash_length_get(FILE_FORMAT_CTX *ctx);
|
static int msi_hash_length_get(FILE_FORMAT_CTX *ctx);
|
||||||
static int msi_check_file(FILE_FORMAT_CTX *ctx, int detached);
|
static int msi_check_file(FILE_FORMAT_CTX *ctx, int detached);
|
||||||
static u_char *msi_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
static u_char *msi_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
@ -229,6 +230,7 @@ static void msi_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
|||||||
FILE_FORMAT file_format_msi = {
|
FILE_FORMAT file_format_msi = {
|
||||||
.ctx_new = msi_ctx_new,
|
.ctx_new = msi_ctx_new,
|
||||||
.data_blob_get = msi_spc_sip_info_get,
|
.data_blob_get = msi_spc_sip_info_get,
|
||||||
|
.pkcs7_contents_get = msi_pkcs7_contents_get,
|
||||||
.hash_length_get = msi_hash_length_get,
|
.hash_length_get = msi_hash_length_get,
|
||||||
.check_file = msi_check_file,
|
.check_file = msi_check_file,
|
||||||
.digest_calc = msi_digest_calc,
|
.digest_calc = msi_digest_calc,
|
||||||
@ -251,6 +253,7 @@ static int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p_msi, uint
|
|||||||
static MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse);
|
static MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse);
|
||||||
static int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len);
|
static int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len);
|
||||||
static int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen);
|
static int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen);
|
||||||
|
static BIO *msi_digest_calc_bio(FILE_FORMAT_CTX *ctx, BIO *hash);
|
||||||
static int msi_calc_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, BIO *hash);
|
static int msi_calc_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, BIO *hash);
|
||||||
static int msi_check_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, MSI_ENTRY *dse, PKCS7 *p7);
|
static int msi_check_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, MSI_ENTRY *dse, PKCS7 *p7);
|
||||||
static int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root);
|
static int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root);
|
||||||
@ -348,6 +351,32 @@ static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX
|
|||||||
return dtype; /* OK */
|
return dtype; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a data content to be signed.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] data content
|
||||||
|
*/
|
||||||
|
static PKCS7 *msi_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
|
||||||
|
/* squash the unused parameter warning, use initialized message digest BIO */
|
||||||
|
(void)md;
|
||||||
|
|
||||||
|
if (ctx->options->add_msi_dse && !msi_calc_MsiDigitalSignatureEx(ctx, hash)) {
|
||||||
|
printf("Unable to calc MsiDigitalSignatureEx\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!msi_hash_dir(ctx->msi_ctx->msi, ctx->msi_ctx->dirent, hash, 1)) {
|
||||||
|
printf("Unable to msi_handle_dir()\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
|
return pkcs7_set_content(content);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
||||||
@ -616,12 +645,8 @@ static PKCS7 *msi_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
/* squash the unused parameter warning */
|
/* squash the unused parameter warning */
|
||||||
(void)outdata;
|
(void)outdata;
|
||||||
|
|
||||||
if (ctx->options->add_msi_dse && !msi_calc_MsiDigitalSignatureEx(ctx, hash)) {
|
hash = msi_digest_calc_bio(ctx, hash);
|
||||||
printf("Unable to calc MsiDigitalSignatureEx\n");
|
if (!hash) {
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
if (!msi_hash_dir(ctx->msi_ctx->msi, ctx->msi_ctx->dirent, hash, 1)) {
|
|
||||||
printf("Unable to msi_handle_dir()\n");
|
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* Obtain a current signature from previously-signed file */
|
/* Obtain a current signature from previously-signed file */
|
||||||
@ -663,6 +688,7 @@ static PKCS7 *msi_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
} else if (ctx->options->cmd == CMD_SIGN) {
|
} else if (ctx->options->cmd == CMD_SIGN) {
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
/* Create a new PKCS#7 signature */
|
/* Create a new PKCS#7 signature */
|
||||||
p7 = pkcs7_create(ctx);
|
p7 = pkcs7_create(ctx);
|
||||||
if (!p7) {
|
if (!p7) {
|
||||||
@ -674,10 +700,18 @@ static PKCS7 *msi_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
PKCS7_free(p7);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!sign_spc_indirect_data_content(p7, hash, ctx)) {
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
printf("Failed to set signed content\n");
|
if (!content) {
|
||||||
|
printf("Failed to get spcIndirectDataContent\n");
|
||||||
return NULL; /* FAILED */
|
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);
|
||||||
}
|
}
|
||||||
if (ctx->options->nest)
|
if (ctx->options->nest)
|
||||||
ctx->options->prevsig = cursig;
|
ctx->options->prevsig = cursig;
|
||||||
@ -2176,6 +2210,25 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute a message digest value of a signed or unsigned MSI file.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] calculated message digest BIO
|
||||||
|
*/
|
||||||
|
static BIO *msi_digest_calc_bio(FILE_FORMAT_CTX *ctx, BIO *hash)
|
||||||
|
{
|
||||||
|
if (ctx->options->add_msi_dse && !msi_calc_MsiDigitalSignatureEx(ctx, hash)) {
|
||||||
|
printf("Unable to calc MsiDigitalSignatureEx\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!msi_hash_dir(ctx->msi_ctx->msi, ctx->msi_ctx->dirent, hash, 1)) {
|
||||||
|
printf("Unable to msi_handle_dir()\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MsiDigitalSignatureEx is an enhanced signature type that
|
* MsiDigitalSignatureEx is an enhanced signature type that
|
||||||
* can be used when signing MSI files. In addition to
|
* can be used when signing MSI files. In addition to
|
||||||
|
@ -2597,30 +2597,6 @@ static int verify_signed_file(FILE_FORMAT_CTX *ctx, GLOBAL_OPTIONS *options)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* [in, out] ctx: structure holds input and output data
|
|
||||||
* [out] outdata: BIO outdata file
|
|
||||||
* [in] p7: PKCS#7 signature
|
|
||||||
* [returns] 1 on error or 0 on success
|
|
||||||
*/
|
|
||||||
static int save_extracted_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
(void)BIO_reset(outdata);
|
|
||||||
if (ctx->options->output_pkcs7) {
|
|
||||||
/* PEM format */
|
|
||||||
ret = !PEM_write_bio_PKCS7(outdata, p7);
|
|
||||||
} else {
|
|
||||||
/* default DER format */
|
|
||||||
ret = !i2d_PKCS7_bio(outdata, p7);
|
|
||||||
}
|
|
||||||
if (ret) {
|
|
||||||
printf("Unable to write pkcs7 object\n");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] options: structure holds the input data
|
* [in] options: structure holds the input data
|
||||||
* [returns] 1 on error or 0 on success
|
* [returns] 1 on error or 0 on success
|
||||||
@ -2700,6 +2676,7 @@ static void usage(const char *argv0, const char *cmd)
|
|||||||
{
|
{
|
||||||
const char *cmds_all[] = {"all", NULL};
|
const char *cmds_all[] = {"all", NULL};
|
||||||
const char *cmds_sign[] = {"all", "sign", NULL};
|
const char *cmds_sign[] = {"all", "sign", NULL};
|
||||||
|
const char *cmds_extract_data[] = {"all", "extract-data", NULL};
|
||||||
const char *cmds_add[] = {"all", "add", NULL};
|
const char *cmds_add[] = {"all", "add", NULL};
|
||||||
const char *cmds_attach[] = {"all", "attach-signature", NULL};
|
const char *cmds_attach[] = {"all", "attach-signature", NULL};
|
||||||
const char *cmds_extract[] = {"all", "extract-signature", NULL};
|
const char *cmds_extract[] = {"all", "extract-signature", NULL};
|
||||||
@ -2738,8 +2715,16 @@ static void usage(const char *argv0, const char *cmd)
|
|||||||
printf("%12s[ -nest ]\n", "");
|
printf("%12s[ -nest ]\n", "");
|
||||||
printf("%12s[ -verbose ]\n", "");
|
printf("%12s[ -verbose ]\n", "");
|
||||||
printf("%12s[ -add-msi-dse ]\n", "");
|
printf("%12s[ -add-msi-dse ]\n", "");
|
||||||
|
printf("%12s[ -pem ]\n", "");
|
||||||
printf("%12s[ -in ] <infile> [-out ] <outfile>\n\n", "");
|
printf("%12s[ -in ] <infile> [-out ] <outfile>\n\n", "");
|
||||||
}
|
}
|
||||||
|
if (on_list(cmd, cmds_extract_data)) {
|
||||||
|
printf("%1sextract-data [ -pem ]\n", "");
|
||||||
|
printf("%12s[ -h {md5,sha1,sha2(56),sha384,sha512} ]\n", "");
|
||||||
|
printf("%12s[ -ph ]\n", "");
|
||||||
|
printf("%12s[ -add-msi-dse ]\n", "");
|
||||||
|
printf("%12s[ -in ] <infile> [ -out ] <datafile>\n\n", "");
|
||||||
|
}
|
||||||
if (on_list(cmd, cmds_add)) {
|
if (on_list(cmd, cmds_add)) {
|
||||||
printf("%1sadd [-addUnauthenticatedBlob]\n", "");
|
printf("%1sadd [-addUnauthenticatedBlob]\n", "");
|
||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
@ -2798,9 +2783,10 @@ static void help_for(const char *argv0, const char *cmd)
|
|||||||
const char *cmds_extract[] = {"extract-signature", NULL};
|
const char *cmds_extract[] = {"extract-signature", NULL};
|
||||||
const char *cmds_remove[] = {"remove-signature", NULL};
|
const char *cmds_remove[] = {"remove-signature", NULL};
|
||||||
const char *cmds_sign[] = {"sign", NULL};
|
const char *cmds_sign[] = {"sign", NULL};
|
||||||
|
const char *cmds_extract_data[] = {"extract-data", NULL};
|
||||||
const char *cmds_verify[] = {"verify", NULL};
|
const char *cmds_verify[] = {"verify", NULL};
|
||||||
const char *cmds_ac[] = {"sign", NULL};
|
const char *cmds_ac[] = {"sign", NULL};
|
||||||
const char *cmds_add_msi_dse[] = {"add", "attach-signature", "sign", NULL};
|
const char *cmds_add_msi_dse[] = {"add", "attach-signature", "sign", "extract-data", NULL};
|
||||||
const char *cmds_addUnauthenticatedBlob[] = {"sign", "add", NULL};
|
const char *cmds_addUnauthenticatedBlob[] = {"sign", "add", NULL};
|
||||||
#ifdef PROVIDE_ASKPASS
|
#ifdef PROVIDE_ASKPASS
|
||||||
const char *cmds_askpass[] = {"sign", NULL};
|
const char *cmds_askpass[] = {"sign", NULL};
|
||||||
@ -2811,9 +2797,10 @@ static void help_for(const char *argv0, const char *cmd)
|
|||||||
const char *cmds_comm[] = {"sign", NULL};
|
const char *cmds_comm[] = {"sign", NULL};
|
||||||
const char *cmds_CRLfile[] = {"attach-signature", "verify", NULL};
|
const char *cmds_CRLfile[] = {"attach-signature", "verify", NULL};
|
||||||
const char *cmds_CRLfileTSA[] = {"attach-signature", "verify", NULL};
|
const char *cmds_CRLfileTSA[] = {"attach-signature", "verify", NULL};
|
||||||
const char *cmds_h[] = {"add", "attach-signature", "sign", NULL};
|
const char *cmds_h[] = {"add", "attach-signature", "sign", "extract-data", NULL};
|
||||||
const char *cmds_i[] = {"sign", NULL};
|
const char *cmds_i[] = {"sign", NULL};
|
||||||
const char *cmds_in[] = {"add", "attach-signature", "extract-signature", "remove-signature", "sign", "verify", NULL};
|
const char *cmds_in[] = {"add", "attach-signature", "extract-signature",
|
||||||
|
"remove-signature", "sign", "extract-data", "verify", NULL};
|
||||||
const char *cmds_jp[] = {"sign", NULL};
|
const char *cmds_jp[] = {"sign", NULL};
|
||||||
const char *cmds_key[] = {"sign", NULL};
|
const char *cmds_key[] = {"sign", NULL};
|
||||||
#if OPENSSL_VERSION_NUMBER>=0x30000000L
|
#if OPENSSL_VERSION_NUMBER>=0x30000000L
|
||||||
@ -2824,13 +2811,14 @@ static void help_for(const char *argv0, const char *cmd)
|
|||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
const char *cmds_noverifypeer[] = {"add", "sign", NULL};
|
const char *cmds_noverifypeer[] = {"add", "sign", NULL};
|
||||||
#endif /* ENABLE_CURL */
|
#endif /* ENABLE_CURL */
|
||||||
const char *cmds_out[] = {"add", "attach-signature", "extract-signature", "remove-signature", "sign", NULL};
|
const char *cmds_out[] = {"add", "attach-signature", "extract-signature",
|
||||||
|
"remove-signature", "sign", "extract-data", NULL};
|
||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
const char *cmds_p[] = {"add", "sign", NULL};
|
const char *cmds_p[] = {"add", "sign", NULL};
|
||||||
#endif /* ENABLE_CURL */
|
#endif /* ENABLE_CURL */
|
||||||
const char *cmds_pass[] = {"sign", NULL};
|
const char *cmds_pass[] = {"sign", NULL};
|
||||||
const char *cmds_pem[] = {"extract-signature", NULL};
|
const char *cmds_pem[] = {"sign", "extract-data", "extract-signature", NULL};
|
||||||
const char *cmds_ph[] = {"sign", NULL};
|
const char *cmds_ph[] = {"sign", "extract-data", NULL};
|
||||||
const char *cmds_pkcs11cert[] = {"sign", NULL};
|
const char *cmds_pkcs11cert[] = {"sign", NULL};
|
||||||
const char *cmds_pkcs11engine[] = {"sign", NULL};
|
const char *cmds_pkcs11engine[] = {"sign", NULL};
|
||||||
const char *cmds_pkcs11module[] = {"sign", NULL};
|
const char *cmds_pkcs11module[] = {"sign", NULL};
|
||||||
@ -2893,6 +2881,10 @@ static void help_for(const char *argv0, const char *cmd)
|
|||||||
printf("parameters and to select the signing certificate you wish to use.\n\n");
|
printf("parameters and to select the signing certificate you wish to use.\n\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
}
|
}
|
||||||
|
if (on_list(cmd, cmds_extract_data)) {
|
||||||
|
printf("\nUse the \"extract-data\" command to extract a data content to be signed.\n\n");
|
||||||
|
printf("Options:\n");
|
||||||
|
}
|
||||||
if (on_list(cmd, cmds_verify)) {
|
if (on_list(cmd, cmds_verify)) {
|
||||||
printf("\nUse the \"verify\" command to verify embedded signatures.\n");
|
printf("\nUse the \"verify\" command to verify embedded signatures.\n");
|
||||||
printf("Verification determines if the signing certificate was issued by a trusted party,\n");
|
printf("Verification determines if the signing certificate was issued by a trusted party,\n");
|
||||||
@ -2957,7 +2949,7 @@ static void help_for(const char *argv0, const char *cmd)
|
|||||||
if (on_list(cmd, cmds_pass))
|
if (on_list(cmd, cmds_pass))
|
||||||
printf("%-24s= the private key password\n", "-pass");
|
printf("%-24s= the private key password\n", "-pass");
|
||||||
if (on_list(cmd, cmds_pem))
|
if (on_list(cmd, cmds_pem))
|
||||||
printf("%-24s= output data format PEM to use (default: DER)\n", "-pem");
|
printf("%-24s= PKCS#7 output data format PEM to use (default: DER)\n", "-pem");
|
||||||
if (on_list(cmd, cmds_ph))
|
if (on_list(cmd, cmds_ph))
|
||||||
printf("%-24s= generate page hashes for executable files\n", "-ph");
|
printf("%-24s= generate page hashes for executable files\n", "-ph");
|
||||||
if (on_list(cmd, cmds_pkcs11cert))
|
if (on_list(cmd, cmds_pkcs11cert))
|
||||||
@ -3579,6 +3571,8 @@ static cmd_type_t get_command(char **argv)
|
|||||||
return CMD_HELP;
|
return CMD_HELP;
|
||||||
} else if (!strcmp(argv[1], "sign"))
|
} else if (!strcmp(argv[1], "sign"))
|
||||||
return CMD_SIGN;
|
return CMD_SIGN;
|
||||||
|
else if (!strcmp(argv[1], "extract-data"))
|
||||||
|
return CMD_EXTRACT_DATA;
|
||||||
else if (!strcmp(argv[1], "extract-signature"))
|
else if (!strcmp(argv[1], "extract-signature"))
|
||||||
return CMD_EXTRACT;
|
return CMD_EXTRACT;
|
||||||
else if (!strcmp(argv[1], "attach-signature"))
|
else if (!strcmp(argv[1], "attach-signature"))
|
||||||
@ -3731,7 +3725,8 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options)
|
|||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
options->pkcs12file = *(++argv);
|
options->pkcs12file = *(++argv);
|
||||||
} else if ((cmd == CMD_EXTRACT) && !strcmp(*argv, "-pem")) {
|
} else if ((cmd == CMD_SIGN || cmd == CMD_EXTRACT || cmd == CMD_EXTRACT_DATA)
|
||||||
|
&& !strcmp(*argv, "-pem")) {
|
||||||
options->output_pkcs7 = 1;
|
options->output_pkcs7 = 1;
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-pkcs11cert")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-pkcs11cert")) {
|
||||||
@ -3788,7 +3783,7 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options)
|
|||||||
options->readpass = *(++argv);
|
options->readpass = *(++argv);
|
||||||
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-comm")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-comm")) {
|
||||||
options->comm = 1;
|
options->comm = 1;
|
||||||
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-ph")) {
|
} else if ((cmd == CMD_SIGN || cmd == CMD_EXTRACT_DATA) && !strcmp(*argv, "-ph")) {
|
||||||
options->pagehash = 1;
|
options->pagehash = 1;
|
||||||
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-n")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-n")) {
|
||||||
if (--argc < 1) {
|
if (--argc < 1) {
|
||||||
@ -3796,8 +3791,8 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options)
|
|||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
options->desc = *(++argv);
|
options->desc = *(++argv);
|
||||||
} else if ((cmd == CMD_SIGN|| cmd == CMD_ADD || cmd == CMD_ATTACH)
|
} else if ((cmd == CMD_SIGN || cmd == CMD_ADD || cmd == CMD_ATTACH
|
||||||
&& !strcmp(*argv, "-h")) {
|
|| cmd == CMD_EXTRACT_DATA) && !strcmp(*argv, "-h")) {
|
||||||
if (--argc < 1) {
|
if (--argc < 1) {
|
||||||
usage(argv0, "all");
|
usage(argv0, "all");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
@ -3860,7 +3855,8 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options)
|
|||||||
options->ignore_timestamp = 1;
|
options->ignore_timestamp = 1;
|
||||||
} else if ((cmd == CMD_SIGN || cmd == CMD_ADD || cmd == CMD_VERIFY) && !strcmp(*argv, "-verbose")) {
|
} else if ((cmd == CMD_SIGN || cmd == CMD_ADD || cmd == CMD_VERIFY) && !strcmp(*argv, "-verbose")) {
|
||||||
options->verbose = 1;
|
options->verbose = 1;
|
||||||
} else if ((cmd == CMD_SIGN || cmd == CMD_ADD || cmd == CMD_ATTACH) && !strcmp(*argv, "-add-msi-dse")) {
|
} else if ((cmd == CMD_SIGN || cmd == CMD_EXTRACT_DATA || cmd == CMD_ADD || cmd == CMD_ATTACH)
|
||||||
|
&& !strcmp(*argv, "-add-msi-dse")) {
|
||||||
options->add_msi_dse = 1;
|
options->add_msi_dse = 1;
|
||||||
} else if ((cmd == CMD_VERIFY) && (!strcmp(*argv, "-c") || !strcmp(*argv, "-catalog"))) {
|
} else if ((cmd == CMD_VERIFY) && (!strcmp(*argv, "-c") || !strcmp(*argv, "-catalog"))) {
|
||||||
if (--argc < 1) {
|
if (--argc < 1) {
|
||||||
@ -3938,6 +3934,10 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options)
|
|||||||
help_for(argv0, "sign");
|
help_for(argv0, "sign");
|
||||||
cmd = CMD_HELP;
|
cmd = CMD_HELP;
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
|
} else if ((cmd == CMD_EXTRACT_DATA) && !strcmp(*argv, "--help")) {
|
||||||
|
help_for(argv0, "extract-data");
|
||||||
|
cmd = CMD_HELP;
|
||||||
|
return 0; /* FAILED */
|
||||||
} else if ((cmd == CMD_VERIFY) && !strcmp(*argv, "--help")) {
|
} else if ((cmd == CMD_VERIFY) && !strcmp(*argv, "--help")) {
|
||||||
help_for(argv0, "verify");
|
help_for(argv0, "verify");
|
||||||
cmd = CMD_HELP;
|
cmd = CMD_HELP;
|
||||||
@ -4090,6 +4090,17 @@ int main(int argc, char **argv)
|
|||||||
if (options.cmd == CMD_VERIFY) {
|
if (options.cmd == CMD_VERIFY) {
|
||||||
ret = verify_signed_file(ctx, &options);
|
ret = verify_signed_file(ctx, &options);
|
||||||
goto skip_signing;
|
goto skip_signing;
|
||||||
|
} else if (options.cmd == CMD_EXTRACT_DATA) {
|
||||||
|
if (!ctx->format->pkcs7_contents_get) {
|
||||||
|
DO_EXIT_0("Unsupported command: extract-data\n");
|
||||||
|
}
|
||||||
|
p7 = ctx->format->pkcs7_contents_get(ctx, hash, options.md);
|
||||||
|
if (!p7) {
|
||||||
|
DO_EXIT_0("Unable to extract pkcs7 contents\n");
|
||||||
|
}
|
||||||
|
ret = data_write_pkcs7(ctx, outdata, p7);
|
||||||
|
PKCS7_free(p7);
|
||||||
|
goto skip_signing;
|
||||||
} else if (options.cmd == CMD_EXTRACT) {
|
} else if (options.cmd == CMD_EXTRACT) {
|
||||||
if (!ctx->format->pkcs7_extract) {
|
if (!ctx->format->pkcs7_extract) {
|
||||||
DO_EXIT_0("Unsupported command: extract-signature\n");
|
DO_EXIT_0("Unsupported command: extract-signature\n");
|
||||||
@ -4098,7 +4109,7 @@ int main(int argc, char **argv)
|
|||||||
if (!p7) {
|
if (!p7) {
|
||||||
DO_EXIT_0("Unable to extract existing signature\n");
|
DO_EXIT_0("Unable to extract existing signature\n");
|
||||||
}
|
}
|
||||||
ret = save_extracted_pkcs7(ctx, outdata, p7);
|
ret = data_write_pkcs7(ctx, outdata, p7);
|
||||||
PKCS7_free(p7);
|
PKCS7_free(p7);
|
||||||
goto skip_signing;
|
goto skip_signing;
|
||||||
} else if (options.cmd == CMD_REMOVE) {
|
} else if (options.cmd == CMD_REMOVE) {
|
||||||
|
@ -221,6 +221,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
CMD_SIGN,
|
CMD_SIGN,
|
||||||
CMD_EXTRACT,
|
CMD_EXTRACT,
|
||||||
|
CMD_EXTRACT_DATA,
|
||||||
CMD_REMOVE,
|
CMD_REMOVE,
|
||||||
CMD_VERIFY,
|
CMD_VERIFY,
|
||||||
CMD_ADD,
|
CMD_ADD,
|
||||||
@ -493,6 +494,7 @@ struct file_format_st {
|
|||||||
FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata);
|
FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata);
|
||||||
const EVP_MD *(*md_get) (FILE_FORMAT_CTX *ctx);
|
const EVP_MD *(*md_get) (FILE_FORMAT_CTX *ctx);
|
||||||
ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
PKCS7 *(*pkcs7_contents_get) (FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
int (*hash_length_get) (FILE_FORMAT_CTX *ctx);
|
int (*hash_length_get) (FILE_FORMAT_CTX *ctx);
|
||||||
int (*check_file) (FILE_FORMAT_CTX *ctx, int detached);
|
int (*check_file) (FILE_FORMAT_CTX *ctx, int detached);
|
||||||
u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
|
152
pe.c
152
pe.c
@ -44,6 +44,7 @@ struct pe_ctx_st {
|
|||||||
/* FILE_FORMAT method prototypes */
|
/* FILE_FORMAT method prototypes */
|
||||||
static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
||||||
static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *pe_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
static int pe_hash_length_get(FILE_FORMAT_CTX *ctx);
|
static int pe_hash_length_get(FILE_FORMAT_CTX *ctx);
|
||||||
static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached);
|
static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached);
|
||||||
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
@ -60,6 +61,7 @@ static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
|||||||
FILE_FORMAT file_format_pe = {
|
FILE_FORMAT file_format_pe = {
|
||||||
.ctx_new = pe_ctx_new,
|
.ctx_new = pe_ctx_new,
|
||||||
.data_blob_get = pe_spc_image_data_get,
|
.data_blob_get = pe_spc_image_data_get,
|
||||||
|
.pkcs7_contents_get = pe_pkcs7_contents_get,
|
||||||
.hash_length_get = pe_hash_length_get,
|
.hash_length_get = pe_hash_length_get,
|
||||||
.check_file = pe_check_file,
|
.check_file = pe_check_file,
|
||||||
.digest_calc = pe_digest_calc,
|
.digest_calc = pe_digest_calc,
|
||||||
@ -80,6 +82,7 @@ static PKCS7 *pe_pkcs7_get_file(char *indata, PE_CTX *pe_ctx);
|
|||||||
static uint32_t pe_calc_checksum(BIO *bio, uint32_t header_size);
|
static uint32_t pe_calc_checksum(BIO *bio, uint32_t header_size);
|
||||||
static uint32_t pe_calc_realchecksum(FILE_FORMAT_CTX *ctx);
|
static uint32_t pe_calc_realchecksum(FILE_FORMAT_CTX *ctx);
|
||||||
static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
|
static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
static int pe_page_hash_get(u_char **ph, int *phlen, int *phtype, SpcAttributeTypeAndOptionalValue *obj);
|
static int pe_page_hash_get(u_char **ph, int *phlen, int *phtype, SpcAttributeTypeAndOptionalValue *obj);
|
||||||
static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype);
|
static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype);
|
||||||
static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int phtype);
|
static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int phtype);
|
||||||
@ -170,6 +173,30 @@ static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX
|
|||||||
return dtype; /* OK */
|
return dtype; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a data content to be signed.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] data content
|
||||||
|
*/
|
||||||
|
static PKCS7 *pe_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
BIO *bhash;
|
||||||
|
|
||||||
|
/* squash the unused parameter warning */
|
||||||
|
(void)hash;
|
||||||
|
|
||||||
|
bhash = pe_digest_calc_bio(ctx, md);
|
||||||
|
if (!bhash) {
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(bhash, ctx);
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return pkcs7_set_content(content);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
||||||
@ -236,65 +263,25 @@ static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached)
|
|||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute a message digest value of a signed or unsigned PE file.
|
/*
|
||||||
|
* Returns a message digest value of a signed or unsigned PE file.
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
* [in] md: message digest algorithm
|
* [in] md: message digest algorithm
|
||||||
* [returns] pointer to calculated message digest
|
* [returns] pointer to calculated message digest
|
||||||
*/
|
*/
|
||||||
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||||
{
|
{
|
||||||
size_t written;
|
u_char *mdbuf;
|
||||||
uint32_t idx = 0, fileend;
|
BIO *bhash = pe_digest_calc_bio(ctx, md);
|
||||||
u_char *mdbuf = NULL;
|
if (!bhash) {
|
||||||
BIO *bhash = BIO_new(BIO_f_md());
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
if (!BIO_set_md(bhash, md)) {
|
|
||||||
printf("Unable to set the message digest of BIO\n");
|
|
||||||
BIO_free_all(bhash);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
|
||||||
if (ctx->pe_ctx->sigpos)
|
|
||||||
fileend = ctx->pe_ctx->sigpos;
|
|
||||||
else
|
|
||||||
fileend = ctx->pe_ctx->fileend;
|
|
||||||
|
|
||||||
/* ctx->pe_ctx->header_size + 88 + 4 + 60 + ctx->pe_ctx->pe32plus * 16 + 8 */
|
|
||||||
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|
|
||||||
|| written != ctx->pe_ctx->header_size + 88) {
|
|
||||||
BIO_free_all(bhash);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
idx += (uint32_t)written + 4;
|
|
||||||
if (!BIO_write_ex(bhash, ctx->options->indata + idx,
|
|
||||||
60 + ctx->pe_ctx->pe32plus * 16, &written)
|
|
||||||
|| written != 60 + ctx->pe_ctx->pe32plus * 16) {
|
|
||||||
BIO_free_all(bhash);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
idx += (uint32_t)written + 8;
|
|
||||||
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
|
|
||||||
printf("Unable to calculate digest\n");
|
|
||||||
BIO_free_all(bhash);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
if (!ctx->pe_ctx->sigpos) {
|
|
||||||
/* pad (with 0's) unsigned PE file to 8 byte boundary */
|
|
||||||
int len = 8 - ctx->pe_ctx->fileend % 8;
|
|
||||||
if (len > 0 && len != 8) {
|
|
||||||
char *buf = OPENSSL_malloc(8);
|
|
||||||
memset(buf, 0, (size_t)len);
|
|
||||||
BIO_write(bhash, buf, len);
|
|
||||||
OPENSSL_free(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
|
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
|
||||||
BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md));
|
BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md));
|
||||||
BIO_free_all(bhash);
|
BIO_free_all(bhash);
|
||||||
return mdbuf; /* OK */
|
return mdbuf; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate message digest and page_hash and compare to values retrieved
|
* Calculate message digest and page_hash and compare to values retrieved
|
||||||
* from PKCS#7 signedData.
|
* from PKCS#7 signedData.
|
||||||
@ -456,6 +443,7 @@ static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
} else if (ctx->options->cmd == CMD_SIGN) {
|
} else if (ctx->options->cmd == CMD_SIGN) {
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
/* Create a new PKCS#7 signature */
|
/* Create a new PKCS#7 signature */
|
||||||
p7 = pkcs7_create(ctx);
|
p7 = pkcs7_create(ctx);
|
||||||
if (!p7) {
|
if (!p7) {
|
||||||
@ -467,10 +455,18 @@ static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
PKCS7_free(p7);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!sign_spc_indirect_data_content(p7, hash, ctx)) {
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
printf("Failed to set signed content\n");
|
if (!content) {
|
||||||
|
printf("Failed to get spcIndirectDataContent\n");
|
||||||
return NULL; /* FAILED */
|
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);
|
||||||
}
|
}
|
||||||
if (ctx->options->nest)
|
if (ctx->options->nest)
|
||||||
ctx->options->prevsig = cursig;
|
ctx->options->prevsig = cursig;
|
||||||
@ -833,6 +829,62 @@ static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute a message digest value of a signed or unsigned PE file.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] calculated message digest BIO
|
||||||
|
*/
|
||||||
|
static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
size_t written;
|
||||||
|
uint32_t idx = 0, fileend;
|
||||||
|
BIO *bhash = BIO_new(BIO_f_md());
|
||||||
|
|
||||||
|
if (!BIO_set_md(bhash, md)) {
|
||||||
|
printf("Unable to set the message digest of BIO\n");
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||||
|
if (ctx->pe_ctx->sigpos)
|
||||||
|
fileend = ctx->pe_ctx->sigpos;
|
||||||
|
else
|
||||||
|
fileend = ctx->pe_ctx->fileend;
|
||||||
|
|
||||||
|
/* ctx->pe_ctx->header_size + 88 + 4 + 60 + ctx->pe_ctx->pe32plus * 16 + 8 */
|
||||||
|
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|
||||||
|
|| written != ctx->pe_ctx->header_size + 88) {
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
idx += (uint32_t)written + 4;
|
||||||
|
if (!BIO_write_ex(bhash, ctx->options->indata + idx,
|
||||||
|
60 + ctx->pe_ctx->pe32plus * 16, &written)
|
||||||
|
|| written != 60 + ctx->pe_ctx->pe32plus * 16) {
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
idx += (uint32_t)written + 8;
|
||||||
|
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
|
||||||
|
printf("Unable to calculate digest\n");
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!ctx->pe_ctx->sigpos) {
|
||||||
|
/* pad (with 0's) unsigned PE file to 8 byte boundary */
|
||||||
|
int len = 8 - ctx->pe_ctx->fileend % 8;
|
||||||
|
if (len > 0 && len != 8) {
|
||||||
|
char *buf = OPENSSL_malloc(8);
|
||||||
|
memset(buf, 0, (size_t)len);
|
||||||
|
BIO_write(bhash, buf, len);
|
||||||
|
OPENSSL_free(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Page hash support
|
* Page hash support
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user