mirror of
https://github.com/mtrojnar/osslsigncode.git
synced 2025-07-03 19:52:47 -05:00
Enable verification that a catalog file was signed by a valid certificate.
Simplify setting and signing a content blob. Clean up a support library.
This commit is contained in:

committed by
Michał Trojnara

parent
33253afb5e
commit
900ffed596
6
appx.c
6
appx.c
@ -587,12 +587,16 @@ static PKCS7 *appx_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
printf("Creating a new signature failed\n");
|
printf("Creating a new signature failed\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!add_indirect_data_object(p7, hashes, ctx)) {
|
if (!add_indirect_data_object(p7)) {
|
||||||
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
||||||
BIO_free_all(hashes);
|
BIO_free_all(hashes);
|
||||||
PKCS7_free(p7);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
|
if (!sign_spc_indirect_data_content(p7, hashes, ctx)) {
|
||||||
|
printf("Failed to set signed content\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
BIO_free_all(hashes);
|
BIO_free_all(hashes);
|
||||||
}
|
}
|
||||||
return p7; /* OK */
|
return p7; /* OK */
|
||||||
|
6
cab.c
6
cab.c
@ -498,11 +498,15 @@ 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 (!add_indirect_data_object(p7, hash, ctx)) {
|
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);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
|
if (!sign_spc_indirect_data_content(p7, hash, ctx)) {
|
||||||
|
printf("Failed to set signed content\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ctx->options->nest)
|
if (ctx->options->nest)
|
||||||
ctx->options->prevsig = cursig;
|
ctx->options->prevsig = cursig;
|
||||||
|
135
cat.c
135
cat.c
@ -19,10 +19,13 @@ struct cat_ctx_st {
|
|||||||
uint32_t sigpos;
|
uint32_t sigpos;
|
||||||
uint32_t siglen;
|
uint32_t siglen;
|
||||||
uint32_t fileend;
|
uint32_t fileend;
|
||||||
|
PKCS7 *p7;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FILE_FORMAT method prototypes */
|
/* FILE_FORMAT method prototypes */
|
||||||
static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
||||||
|
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_extract(FILE_FORMAT_CTX *ctx);
|
||||||
static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
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);
|
||||||
@ -31,6 +34,8 @@ static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
|||||||
|
|
||||||
FILE_FORMAT file_format_cat = {
|
FILE_FORMAT file_format_cat = {
|
||||||
.ctx_new = cat_ctx_new,
|
.ctx_new = cat_ctx_new,
|
||||||
|
.check_file = cat_check_file,
|
||||||
|
.verify_digests = cat_verify_digests,
|
||||||
.pkcs7_extract = cat_pkcs7_extract,
|
.pkcs7_extract = cat_pkcs7_extract,
|
||||||
.pkcs7_prepare = cat_pkcs7_prepare,
|
.pkcs7_prepare = cat_pkcs7_prepare,
|
||||||
.append_pkcs7 = cat_append_pkcs7,
|
.append_pkcs7 = cat_append_pkcs7,
|
||||||
@ -40,6 +45,8 @@ FILE_FORMAT file_format_cat = {
|
|||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
|
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
|
||||||
|
static int cat_add_ms_ctl_object(PKCS7 *p7);
|
||||||
|
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FILE_FORMAT method definitions
|
* FILE_FORMAT method definitions
|
||||||
@ -58,17 +65,12 @@ 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;
|
||||||
|
|
||||||
/* squash unused parameter warnings */
|
|
||||||
(void)outdata;
|
|
||||||
(void)hash;
|
|
||||||
|
|
||||||
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH) {
|
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH) {
|
||||||
printf("Unsupported command\n");
|
printf("Unsupported command\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (options->cmd == CMD_VERIFY) {
|
if (options->cmd == CMD_VERIFY) {
|
||||||
printf("Use -catalog option\n");
|
printf("Warning: Use -catalog option to verify that a file, listed in catalog file, is signed\n\n");
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
}
|
||||||
filesize = get_file_size(options->infile);
|
filesize = get_file_size(options->infile);
|
||||||
if (filesize == 0)
|
if (filesize == 0)
|
||||||
@ -109,6 +111,45 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cat_check_file(FILE_FORMAT_CTX *ctx, int detached)
|
||||||
|
{
|
||||||
|
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||||
|
PKCS7_SIGNER_INFO *si;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
printf("Init error\n\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (detached) {
|
||||||
|
printf("CAT format does not support detached PKCS#7 signature\n\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
signer_info = PKCS7_get_signer_info(ctx->cat_ctx->p7);
|
||||||
|
if (!signer_info) {
|
||||||
|
printf("Failed catalog file\n\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
|
||||||
|
if (!si) {
|
||||||
|
printf("No signature found\n\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ContentInfo value is the inner content of pkcs7-signedData.
|
||||||
|
* An extra verification is not necessary when a content type data
|
||||||
|
* is the inner content of the signed-data type.
|
||||||
|
*/
|
||||||
|
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
||||||
|
{
|
||||||
|
/* squash unused parameter warnings */
|
||||||
|
(void)ctx;
|
||||||
|
(void)p7;
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract existing signature in DER format.
|
* Extract existing signature in DER format.
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
@ -116,7 +157,7 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
*/
|
*/
|
||||||
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
return pkcs7_get(ctx->options->indata, ctx->cat_ctx->sigpos, ctx->cat_ctx->siglen);
|
return PKCS7_dup(ctx->cat_ctx->p7);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -128,35 +169,32 @@ 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_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
PKCS7 *cursig = NULL, *p7 = NULL;
|
PKCS7 *p7 = NULL;
|
||||||
|
|
||||||
/* squash unused parameter warnings */
|
/* squash unused parameter warnings */
|
||||||
(void)outdata;
|
(void)outdata;
|
||||||
(void)hash;
|
(void)hash;
|
||||||
|
|
||||||
/* Obtain an existing signature */
|
/* Obtain an existing signature */
|
||||||
cursig = pkcs7_get(ctx->options->indata, ctx->cat_ctx->sigpos, ctx->cat_ctx->siglen);
|
|
||||||
if (!cursig) {
|
|
||||||
printf("Unable to extract existing signature\n");
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) {
|
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) {
|
||||||
p7 = cursig;
|
p7 = PKCS7_dup(ctx->cat_ctx->p7);
|
||||||
} 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);
|
||||||
if (!p7) {
|
if (!p7) {
|
||||||
printf("Creating a new signature failed\n");
|
printf("Creating a new signature failed\n");
|
||||||
PKCS7_free(cursig);
|
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!add_ms_ctl_object(p7, cursig)) {
|
if (!cat_add_ms_ctl_object(p7)) {
|
||||||
printf("Adding MS_CTL_OBJID failed\n");
|
printf("Adding MS_CTL_OBJID failed\n");
|
||||||
PKCS7_free(p7);
|
PKCS7_free(p7);
|
||||||
PKCS7_free(cursig);
|
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
PKCS7_free(cursig);
|
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 */
|
return p7; /* OK */
|
||||||
}
|
}
|
||||||
@ -224,6 +262,7 @@ static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
unmap_file(ctx->options->indata, ctx->cat_ctx->fileend);
|
unmap_file(ctx->options->indata, ctx->cat_ctx->fileend);
|
||||||
|
PKCS7_free(ctx->cat_ctx->p7);
|
||||||
OPENSSL_free(ctx->cat_ctx);
|
OPENSSL_free(ctx->cat_ctx);
|
||||||
OPENSSL_free(ctx);
|
OPENSSL_free(ctx);
|
||||||
}
|
}
|
||||||
@ -233,7 +272,7 @@ static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify mapped CAT file TODO and create CAT format specific structure.
|
* Verify mapped CAT file and create CAT format specific structure.
|
||||||
* [in] indata: mapped CAT file (unused)
|
* [in] indata: mapped CAT file (unused)
|
||||||
* [in] filesize: size of CAT file
|
* [in] filesize: size of CAT file
|
||||||
* [returns] pointer to CAT format specific structure
|
* [returns] pointer to CAT format specific structure
|
||||||
@ -241,17 +280,69 @@ static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
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);
|
||||||
|
|
||||||
/* squash the unused parameter warning */
|
if (!p7)
|
||||||
(void)indata;
|
return NULL; /* FAILED */
|
||||||
|
|
||||||
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
|
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
|
||||||
|
cat_ctx->p7 = p7;
|
||||||
cat_ctx->sigpos = 0;
|
cat_ctx->sigpos = 0;
|
||||||
cat_ctx->siglen = filesize;
|
cat_ctx->siglen = filesize;
|
||||||
cat_ctx->fileend = filesize;
|
cat_ctx->fileend = filesize;
|
||||||
return cat_ctx; /* OK */
|
return cat_ctx; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add "1.3.6.1.4.1.311.10.1" MS_CTL_OBJID signed attribute
|
||||||
|
* [in, out] p7: new PKCS#7 signature
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int cat_add_ms_ctl_object(PKCS7 *p7)
|
||||||
|
{
|
||||||
|
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||||
|
PKCS7_SIGNER_INFO *si;
|
||||||
|
|
||||||
|
signer_info = PKCS7_get_signer_info(p7);
|
||||||
|
if (!signer_info)
|
||||||
|
return 0; /* FAILED */
|
||||||
|
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
|
||||||
|
if (!si)
|
||||||
|
return 0; /* FAILED */
|
||||||
|
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
||||||
|
V_ASN1_OBJECT, OBJ_txt2obj(MS_CTL_OBJID, 1)))
|
||||||
|
return 0; /* FAILED */
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sign the MS CTL blob.
|
||||||
|
* Certificate Trust List (CTL) is a list of file names or thumbprints.
|
||||||
|
* All the items in this list are authenticated (approved) by the signing entity.
|
||||||
|
* [in, out] p7: new PKCS#7 signature
|
||||||
|
* [in] contents: Certificate Trust List (CTL)
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents)
|
||||||
|
{
|
||||||
|
u_char *content;
|
||||||
|
int seqhdrlen, content_length;
|
||||||
|
|
||||||
|
seqhdrlen = asn1_simple_hdr_len(contents->d.other->value.sequence->data,
|
||||||
|
contents->d.other->value.sequence->length);
|
||||||
|
content = contents->d.other->value.sequence->data + seqhdrlen;
|
||||||
|
content_length = contents->d.other->value.sequence->length - seqhdrlen;
|
||||||
|
|
||||||
|
if (!pkcs7_sign_content(p7, content, content_length)) {
|
||||||
|
printf("Failed to sign content\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!PKCS7_set_content(p7, PKCS7_dup(contents))) {
|
||||||
|
printf("PKCS7_set_content failed\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Local Variables:
|
Local Variables:
|
||||||
c-basic-offset: 4
|
c-basic-offset: 4
|
||||||
|
436
helpers.c
436
helpers.c
@ -9,12 +9,12 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
static int pkcs7_set_content_blob(PKCS7 *sig, PKCS7 *cursig);
|
|
||||||
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_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx);
|
||||||
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, 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 int X509_compare(const X509 *const *a, const X509 *const *b);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Common functions
|
* Common functions
|
||||||
@ -108,60 +108,6 @@ void unmap_file(char *indata, const size_t size)
|
|||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* [in, out] si: PKCS7_SIGNER_INFO structure
|
|
||||||
* [in] ctx: FILE_FORMAT_CTX structure
|
|
||||||
* [returns] 0 on error or 1 on success
|
|
||||||
*/
|
|
||||||
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
|
||||||
{
|
|
||||||
SpcSpOpusInfo *opus;
|
|
||||||
ASN1_STRING *astr;
|
|
||||||
int len;
|
|
||||||
u_char *p = NULL;
|
|
||||||
|
|
||||||
opus = spc_sp_opus_info_create(ctx);
|
|
||||||
if ((len = i2d_SpcSpOpusInfo(opus, NULL)) <= 0
|
|
||||||
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
|
||||||
SpcSpOpusInfo_free(opus);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
i2d_SpcSpOpusInfo(opus, &p);
|
|
||||||
p -= len;
|
|
||||||
astr = ASN1_STRING_new();
|
|
||||||
ASN1_STRING_set(astr, p, len);
|
|
||||||
OPENSSL_free(p);
|
|
||||||
SpcSpOpusInfo_free(opus);
|
|
||||||
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
|
|
||||||
V_ASN1_SEQUENCE, astr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* [in, out] si: PKCS7_SIGNER_INFO structure
|
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [returns] 0 on error or 1 on success
|
|
||||||
*/
|
|
||||||
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
|
||||||
{
|
|
||||||
static const u_char purpose_ind[] = {
|
|
||||||
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
|
|
||||||
0x01, 0x82, 0x37, 0x02, 0x01, 0x15
|
|
||||||
};
|
|
||||||
static const u_char purpose_comm[] = {
|
|
||||||
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
|
|
||||||
0x01, 0x82, 0x37, 0x02, 0x01, 0x16
|
|
||||||
};
|
|
||||||
ASN1_STRING *purpose = ASN1_STRING_new();
|
|
||||||
|
|
||||||
if (ctx->options->comm) {
|
|
||||||
ASN1_STRING_set(purpose, purpose_comm, sizeof purpose_comm);
|
|
||||||
} else {
|
|
||||||
ASN1_STRING_set(purpose, purpose_ind, sizeof purpose_ind);
|
|
||||||
}
|
|
||||||
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
|
|
||||||
V_ASN1_SEQUENCE, purpose);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a custom, non-trusted time to the PKCS7 structure to prevent OpenSSL
|
* Add a custom, non-trusted time to the PKCS7 structure to prevent OpenSSL
|
||||||
* adding the _current_ time. This allows to create a deterministic signature
|
* adding the _current_ time. This allows to create a deterministic signature
|
||||||
@ -216,81 +162,6 @@ PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx)
|
|||||||
return p7;
|
return p7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* X.690-compliant certificate comparison function
|
|
||||||
* Windows requires catalog files to use PKCS#7
|
|
||||||
* content ordering specified in X.690 section 11.6
|
|
||||||
* https://support.microsoft.com/en-us/topic/october-13-2020-kb4580358-security-only-update-d3f6eb3c-d7c4-a9cb-0de6-759386bf7113
|
|
||||||
* This algorithm is different from X509_cmp()
|
|
||||||
* [in] a_ptr, b_ptr: pointers to X509 certificates
|
|
||||||
* [returns] certificates order
|
|
||||||
*/
|
|
||||||
static int X509_compare(const X509 *const *a, const X509 *const *b)
|
|
||||||
{
|
|
||||||
u_char *a_data, *b_data, *a_tmp, *b_tmp;
|
|
||||||
size_t a_len, b_len;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
a_len = (size_t)i2d_X509(*a, NULL);
|
|
||||||
a_tmp = a_data = OPENSSL_malloc(a_len);
|
|
||||||
i2d_X509(*a, &a_tmp);
|
|
||||||
|
|
||||||
b_len = (size_t)i2d_X509(*b, NULL);
|
|
||||||
b_tmp = b_data = OPENSSL_malloc(b_len);
|
|
||||||
i2d_X509(*b, &b_tmp);
|
|
||||||
|
|
||||||
ret = memcmp(a_data, b_data, MIN(a_len, b_len));
|
|
||||||
OPENSSL_free(a_data);
|
|
||||||
OPENSSL_free(b_data);
|
|
||||||
|
|
||||||
if (ret == 0 && a_len != b_len) /* identical up to the length of the shorter DER */
|
|
||||||
ret = a_len < b_len ? -1 : 1; /* shorter is smaller */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create certificate chain sorted in ascending order by their DER encoding.
|
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [in] signer: signer's certificate number in the certificate chain
|
|
||||||
* [returns] sorted certificate chain
|
|
||||||
*/
|
|
||||||
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
STACK_OF(X509) *chain = sk_X509_new(X509_compare);
|
|
||||||
|
|
||||||
/* add the signer's certificate */
|
|
||||||
if (ctx->options->cert != NULL && !sk_X509_push(chain, ctx->options->cert)) {
|
|
||||||
sk_X509_free(chain);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (signer != -1 && !sk_X509_push(chain, sk_X509_value(ctx->options->certs, signer))) {
|
|
||||||
sk_X509_free(chain);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* add the certificate chain */
|
|
||||||
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
|
|
||||||
if (i == signer)
|
|
||||||
continue;
|
|
||||||
if (!sk_X509_push(chain, sk_X509_value(ctx->options->certs, i))) {
|
|
||||||
sk_X509_free(chain);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* add all cross certificates */
|
|
||||||
if (ctx->options->xcerts) {
|
|
||||||
for (i=0; i<sk_X509_num(ctx->options->xcerts); i++) {
|
|
||||||
if (!sk_X509_push(chain, sk_X509_value(ctx->options->xcerts, i))) {
|
|
||||||
sk_X509_free(chain);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* sort certificate chain using the supplied comparison function */
|
|
||||||
sk_X509_sort(chain);
|
|
||||||
return chain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
@ -305,7 +176,7 @@ PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
|
|||||||
|
|
||||||
p7 = PKCS7_new();
|
p7 = PKCS7_new();
|
||||||
PKCS7_set_type(p7, NID_pkcs7_signed);
|
PKCS7_set_type(p7, NID_pkcs7_signed);
|
||||||
|
PKCS7_content_new(p7, NID_pkcs7_data);
|
||||||
if (ctx->options->cert != NULL) {
|
if (ctx->options->cert != NULL) {
|
||||||
/*
|
/*
|
||||||
* the private key and corresponding certificate are parsed from the PKCS12
|
* the private key and corresponding certificate are parsed from the PKCS12
|
||||||
@ -335,17 +206,14 @@ PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pkcs7_signer_info_add_signing_time(si, ctx);
|
pkcs7_signer_info_add_signing_time(si, ctx);
|
||||||
|
if (!pkcs7_signer_info_add_purpose(si, ctx)) {
|
||||||
if (!pkcs7_signer_info_add_purpose(si, ctx))
|
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
if ((ctx->options->desc || ctx->options->url) &&
|
if ((ctx->options->desc || ctx->options->url) &&
|
||||||
!pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) {
|
!pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) {
|
||||||
printf("Couldn't allocate memory for opus info\n");
|
printf("Couldn't allocate memory for opus info\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
PKCS7_content_new(p7, NID_pkcs7_data);
|
|
||||||
|
|
||||||
/* create X509 chain sorted in ascending order by their DER encoding */
|
/* create X509 chain sorted in ascending order by their DER encoding */
|
||||||
chain = X509_chain_get_sorted(ctx, signer);
|
chain = X509_chain_get_sorted(ctx, signer);
|
||||||
if (chain == NULL) {
|
if (chain == NULL) {
|
||||||
@ -366,12 +234,12 @@ PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* PE, MSI, CAB and APPX file specific
|
||||||
|
* Add "1.3.6.1.4.1.311.2.1.4" SPC_INDIRECT_DATA_OBJID signed attribute
|
||||||
* [in, out] p7: new PKCS#7 signature
|
* [in, out] p7: new PKCS#7 signature
|
||||||
* [in] hash: message digest BIO
|
|
||||||
* [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 add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
int add_indirect_data_object(PKCS7 *p7)
|
||||||
{
|
{
|
||||||
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||||
PKCS7_SIGNER_INFO *si;
|
PKCS7_SIGNER_INFO *si;
|
||||||
@ -385,67 +253,85 @@ int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
|||||||
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
||||||
V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)))
|
V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)))
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
if (!pkcs7_set_data_content(p7, hash, ctx)) {
|
return 1; /* OK */
|
||||||
printf("Signing failed\n");
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PE, MSI, CAB and APPX format specific
|
||||||
|
* Sign the MS Authenticode spcIndirectDataContent blob.
|
||||||
|
* The spcIndirectDataContent structure is used in Authenticode signatures
|
||||||
|
* to store the digest and other attributes of the signed file.
|
||||||
|
* [in, out] p7: new PKCS#7 signature
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
int sign_spc_indirect_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
|
||||||
|
int mdlen, seqhdrlen, hashlen;
|
||||||
|
PKCS7 *td7;
|
||||||
|
u_char *p = NULL;
|
||||||
|
int len = 0;
|
||||||
|
u_char *buf;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (!spc_indirect_data_content_get(&p, &len, ctx))
|
||||||
|
return 0; /* FAILED */
|
||||||
|
|
||||||
|
buf = OPENSSL_malloc(SIZE_64K);
|
||||||
|
memcpy(buf, p, (size_t)len);
|
||||||
|
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 */
|
||||||
|
}
|
||||||
|
td7 = PKCS7_new();
|
||||||
|
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 = ASN1_STRING_new();
|
||||||
|
ASN1_STRING_set(td7->d.other->value.sequence, buf, len + mdlen);
|
||||||
|
OPENSSL_free(buf);
|
||||||
|
if (!PKCS7_set_content(p7, td7)) {
|
||||||
|
printf("PKCS7_set_content failed\n");
|
||||||
|
PKCS7_free(td7);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Signs the data and place the signature in p7
|
||||||
* [in, out] p7: new PKCS#7 signature
|
* [in, out] p7: new PKCS#7 signature
|
||||||
* [in] cursig: current PKCS#7 signature
|
* [in] data: content data
|
||||||
* [returns] 0 on error or 1 on success
|
* [in] len: content length
|
||||||
*/
|
*/
|
||||||
int add_ms_ctl_object(PKCS7 *p7, PKCS7 *cursig)
|
int pkcs7_sign_content(PKCS7 *p7, u_char *data, int len)
|
||||||
{
|
{
|
||||||
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
BIO *p7bio;
|
||||||
PKCS7_SIGNER_INFO *si;
|
|
||||||
|
|
||||||
signer_info = PKCS7_get_signer_info(p7);
|
if ((p7bio = PKCS7_dataInit(p7, NULL)) == NULL) {
|
||||||
if (!signer_info)
|
|
||||||
return 0; /* FAILED */
|
|
||||||
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
|
|
||||||
if (!si)
|
|
||||||
return 0; /* FAILED */
|
|
||||||
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
|
||||||
V_ASN1_OBJECT, OBJ_txt2obj(MS_CTL_OBJID, 1)))
|
|
||||||
return 0; /* FAILED */
|
|
||||||
if (!pkcs7_set_content_blob(p7, cursig)) {
|
|
||||||
printf("Signing failed\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
return 1; /* OK */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pkcs7_set_content_blob(PKCS7 *sig, PKCS7 *cursig)
|
|
||||||
{
|
|
||||||
PKCS7 *contents;
|
|
||||||
u_char *content;
|
|
||||||
int seqhdrlen, content_length;
|
|
||||||
BIO *sigbio;
|
|
||||||
|
|
||||||
contents = cursig->d.sign->contents;
|
|
||||||
seqhdrlen = asn1_simple_hdr_len(contents->d.other->value.sequence->data,
|
|
||||||
contents->d.other->value.sequence->length);
|
|
||||||
content = contents->d.other->value.sequence->data + seqhdrlen;
|
|
||||||
content_length = contents->d.other->value.sequence->length - seqhdrlen;
|
|
||||||
|
|
||||||
if ((sigbio = PKCS7_dataInit(sig, NULL)) == NULL) {
|
|
||||||
printf("PKCS7_dataInit failed\n");
|
printf("PKCS7_dataInit failed\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
BIO_write(sigbio, content, content_length);
|
BIO_write(p7bio, data, len);
|
||||||
(void)BIO_flush(sigbio);
|
(void)BIO_flush(p7bio);
|
||||||
if (!PKCS7_dataFinal(sig, sigbio)) {
|
if (!PKCS7_dataFinal(p7, p7bio)) {
|
||||||
printf("PKCS7_dataFinal failed\n");
|
printf("PKCS7_dataFinal failed\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
BIO_free_all(sigbio);
|
BIO_free_all(p7bio);
|
||||||
if (!PKCS7_set_content(sig, PKCS7_dup(contents))) {
|
|
||||||
printf("PKCS7_set_content failed\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,32 +411,6 @@ int is_content_type(PKCS7 *p7, const char *objid)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* [out] p7: new PKCS#7 signature
|
|
||||||
* [in] hash: message digest BIO
|
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [returns] 0 on error or 1 on success
|
|
||||||
*/
|
|
||||||
int pkcs7_set_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
|
||||||
{
|
|
||||||
u_char *p = NULL;
|
|
||||||
int len = 0;
|
|
||||||
u_char *buf;
|
|
||||||
|
|
||||||
if (!spc_indirect_data_content_get(&p, &len, ctx))
|
|
||||||
return 0; /* FAILED */
|
|
||||||
buf = OPENSSL_malloc(SIZE_64K);
|
|
||||||
memcpy(buf, p, (size_t)len);
|
|
||||||
OPENSSL_free(p);
|
|
||||||
if (!pkcs7_set_spc_indirect_data_content(p7, hash, buf, len, ctx)) {
|
|
||||||
OPENSSL_free(buf);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
OPENSSL_free(buf);
|
|
||||||
|
|
||||||
return 1; /* OK */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PE and CAB format specific
|
* PE and CAB format specific
|
||||||
* [in] none
|
* [in] none
|
||||||
@ -673,56 +533,132 @@ static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CT
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace the data part with the MS Authenticode spcIndirectDataContent blob
|
* [in, out] si: PKCS7_SIGNER_INFO structure
|
||||||
* [out] p7: new PKCS#7 signature
|
|
||||||
* [in] hash: message digest BIO
|
|
||||||
* [in] blob: SpcIndirectDataContent data
|
|
||||||
* [in] len: SpcIndirectDataContent data length
|
|
||||||
* [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 pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx)
|
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
|
SpcSpOpusInfo *opus;
|
||||||
int mdlen, seqhdrlen, hashlen;
|
ASN1_STRING *astr;
|
||||||
BIO *bio;
|
int len;
|
||||||
PKCS7 *td7;
|
u_char *p = NULL;
|
||||||
|
|
||||||
hashlen = ctx->format->hash_length_get(ctx);
|
opus = spc_sp_opus_info_create(ctx);
|
||||||
if (hashlen > EVP_MAX_MD_SIZE) {
|
if ((len = i2d_SpcSpOpusInfo(opus, NULL)) <= 0
|
||||||
/* APPX format specific */
|
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
||||||
mdlen = BIO_read(hash, (char*)mdbuf, hashlen);
|
SpcSpOpusInfo_free(opus);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
i2d_SpcSpOpusInfo(opus, &p);
|
||||||
|
p -= len;
|
||||||
|
astr = ASN1_STRING_new();
|
||||||
|
ASN1_STRING_set(astr, p, len);
|
||||||
|
OPENSSL_free(p);
|
||||||
|
SpcSpOpusInfo_free(opus);
|
||||||
|
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
|
||||||
|
V_ASN1_SEQUENCE, astr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* [in, out] si: PKCS7_SIGNER_INFO structure
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
static const u_char purpose_ind[] = {
|
||||||
|
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
|
||||||
|
0x01, 0x82, 0x37, 0x02, 0x01, 0x15
|
||||||
|
};
|
||||||
|
static const u_char purpose_comm[] = {
|
||||||
|
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
|
||||||
|
0x01, 0x82, 0x37, 0x02, 0x01, 0x16
|
||||||
|
};
|
||||||
|
ASN1_STRING *purpose = ASN1_STRING_new();
|
||||||
|
|
||||||
|
if (ctx->options->comm) {
|
||||||
|
ASN1_STRING_set(purpose, purpose_comm, sizeof purpose_comm);
|
||||||
} else {
|
} else {
|
||||||
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE);
|
ASN1_STRING_set(purpose, purpose_ind, sizeof purpose_ind);
|
||||||
|
}
|
||||||
|
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
|
||||||
|
V_ASN1_SEQUENCE, purpose);
|
||||||
}
|
}
|
||||||
memcpy(buf + len, mdbuf, (size_t)mdlen);
|
|
||||||
seqhdrlen = asn1_simple_hdr_len(buf, len);
|
|
||||||
|
|
||||||
if ((bio = PKCS7_dataInit(p7, NULL)) == NULL) {
|
/*
|
||||||
printf("PKCS7_dataInit failed\n");
|
* Create certificate chain sorted in ascending order by their DER encoding.
|
||||||
return 0; /* FAILED */
|
* [in] ctx: structure holds input and output data
|
||||||
}
|
* [in] signer: signer's certificate number in the certificate chain
|
||||||
BIO_write(bio, buf + seqhdrlen, len - seqhdrlen + mdlen);
|
* [returns] sorted certificate chain
|
||||||
(void)BIO_flush(bio);
|
*/
|
||||||
|
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
STACK_OF(X509) *chain = sk_X509_new(X509_compare);
|
||||||
|
|
||||||
if (!PKCS7_dataFinal(p7, bio)) {
|
/* add the signer's certificate */
|
||||||
printf("PKCS7_dataFinal failed\n");
|
if (ctx->options->cert != NULL && !sk_X509_push(chain, ctx->options->cert)) {
|
||||||
return 0; /* FAILED */
|
sk_X509_free(chain);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (signer != -1 && !sk_X509_push(chain, sk_X509_value(ctx->options->certs, signer))) {
|
||||||
|
sk_X509_free(chain);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* add the certificate chain */
|
||||||
|
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
|
||||||
|
if (i == signer)
|
||||||
|
continue;
|
||||||
|
if (!sk_X509_push(chain, sk_X509_value(ctx->options->certs, i))) {
|
||||||
|
sk_X509_free(chain);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* add all cross certificates */
|
||||||
|
if (ctx->options->xcerts) {
|
||||||
|
for (i=0; i<sk_X509_num(ctx->options->xcerts); i++) {
|
||||||
|
if (!sk_X509_push(chain, sk_X509_value(ctx->options->xcerts, i))) {
|
||||||
|
sk_X509_free(chain);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* sort certificate chain using the supplied comparison function */
|
||||||
|
sk_X509_sort(chain);
|
||||||
|
return chain;
|
||||||
}
|
}
|
||||||
BIO_free_all(bio);
|
|
||||||
|
|
||||||
td7 = PKCS7_new();
|
/*
|
||||||
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
|
* X.690-compliant certificate comparison function
|
||||||
td7->d.other = ASN1_TYPE_new();
|
* Windows requires catalog files to use PKCS#7
|
||||||
td7->d.other->type = V_ASN1_SEQUENCE;
|
* content ordering specified in X.690 section 11.6
|
||||||
td7->d.other->value.sequence = ASN1_STRING_new();
|
* https://support.microsoft.com/en-us/topic/october-13-2020-kb4580358-security-only-update-d3f6eb3c-d7c4-a9cb-0de6-759386bf7113
|
||||||
ASN1_STRING_set(td7->d.other->value.sequence, buf, len + mdlen);
|
* This algorithm is different from X509_cmp()
|
||||||
if (!PKCS7_set_content(p7, td7)) {
|
* [in] a_ptr, b_ptr: pointers to X509 certificates
|
||||||
PKCS7_free(td7);
|
* [returns] certificates order
|
||||||
printf("PKCS7_set_content failed\n");
|
*/
|
||||||
return 0; /* FAILED */
|
static int X509_compare(const X509 *const *a, const X509 *const *b)
|
||||||
}
|
{
|
||||||
return 1; /* OK */
|
u_char *a_data, *b_data, *a_tmp, *b_tmp;
|
||||||
|
size_t a_len, b_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
a_len = (size_t)i2d_X509(*a, NULL);
|
||||||
|
a_tmp = a_data = OPENSSL_malloc(a_len);
|
||||||
|
i2d_X509(*a, &a_tmp);
|
||||||
|
|
||||||
|
b_len = (size_t)i2d_X509(*b, NULL);
|
||||||
|
b_tmp = b_data = OPENSSL_malloc(b_len);
|
||||||
|
i2d_X509(*b, &b_tmp);
|
||||||
|
|
||||||
|
ret = memcmp(a_data, b_data, MIN(a_len, b_len));
|
||||||
|
OPENSSL_free(a_data);
|
||||||
|
OPENSSL_free(b_data);
|
||||||
|
|
||||||
|
if (ret == 0 && a_len != b_len) /* identical up to the length of the shorter DER */
|
||||||
|
ret = a_len < b_len ? -1 : 1; /* shorter is smaller */
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -12,14 +12,13 @@ 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_create(FILE_FORMAT_CTX *ctx);
|
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx);
|
||||||
void add_content_type(PKCS7 *p7);
|
int add_indirect_data_object(PKCS7 *p7);
|
||||||
int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx);
|
int sign_spc_indirect_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx);
|
||||||
int add_ms_ctl_object(PKCS7 *p7, PKCS7 *cursig);
|
int pkcs7_sign_content(PKCS7 *p7, 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);
|
||||||
int is_content_type(PKCS7 *p7, const char *objid);
|
int is_content_type(PKCS7 *p7, const char *objid);
|
||||||
int pkcs7_set_data_content(PKCS7 *sig, BIO *hash, FILE_FORMAT_CTX *ctx);
|
|
||||||
SpcLink *spc_link_obsolete_get(void);
|
SpcLink *spc_link_obsolete_get(void);
|
||||||
PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen);
|
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);
|
||||||
|
6
msi.c
6
msi.c
@ -668,11 +668,15 @@ static PKCS7 *msi_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
printf("Creating a new signature failed\n");
|
printf("Creating a new signature failed\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!add_indirect_data_object(p7, hash, ctx)) {
|
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);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
|
if (!sign_spc_indirect_data_content(p7, hash, ctx)) {
|
||||||
|
printf("Failed to set signed content\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ctx->options->nest)
|
if (ctx->options->nest)
|
||||||
ctx->options->prevsig = cursig;
|
ctx->options->prevsig = cursig;
|
||||||
|
@ -1236,7 +1236,7 @@ static int trusted_cert(X509 *cert, int error) {
|
|||||||
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);
|
||||||
|
|
||||||
hex = OPENSSL_buf2hexstr(mdbuf, (size_t)EVP_MD_size(md));
|
hex = OPENSSL_buf2hexstr(mdbuf, (long)EVP_MD_size(md));
|
||||||
if (!hex) {
|
if (!hex) {
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -1746,6 +1746,13 @@ static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X50
|
|||||||
p7->d.sign->contents->d.other->value.sequence->length);
|
p7->d.sign->contents->d.other->value.sequence->length);
|
||||||
}
|
}
|
||||||
printf("\nSigning Certificate Chain:\n");
|
printf("\nSigning Certificate Chain:\n");
|
||||||
|
/*
|
||||||
|
* In the PKCS7_verify() function, the BIO *indata parameter refers to
|
||||||
|
* the signed data if the content is detached from p7.
|
||||||
|
* Otherwise, indata should be NULL, and then the signed data must be in p7.
|
||||||
|
* The OpenSSL error workaround is to put the inner content into BIO *indata parameter
|
||||||
|
* https://github.com/openssl/openssl/pull/22575
|
||||||
|
*/
|
||||||
if (!PKCS7_verify(p7, NULL, store, bio, NULL, 0)) {
|
if (!PKCS7_verify(p7, NULL, store, bio, NULL, 0)) {
|
||||||
printf("\nPKCS7_verify error\n");
|
printf("\nPKCS7_verify error\n");
|
||||||
X509_STORE_free(store);
|
X509_STORE_free(store);
|
||||||
@ -2304,21 +2311,25 @@ static int verify_member(FILE_FORMAT_CTX *ctx, CatalogAuthAttr *attribute)
|
|||||||
ASN1_TYPE_free(content);
|
ASN1_TYPE_free(content);
|
||||||
if (mdtype == -1) {
|
if (mdtype == -1) {
|
||||||
printf("Failed to extract current message digest\n\n");
|
printf("Failed to extract current message digest\n\n");
|
||||||
|
SpcIndirectDataContent_free(idc);
|
||||||
return 1; /* FAILED */
|
return 1; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!ctx->format->digest_calc) {
|
if (!ctx->format->digest_calc) {
|
||||||
printf("Unsupported method: digest_calc\n");
|
printf("Unsupported method: digest_calc\n");
|
||||||
|
SpcIndirectDataContent_free(idc);
|
||||||
return 1; /* FAILED */
|
return 1; /* FAILED */
|
||||||
}
|
}
|
||||||
md = EVP_get_digestbynid(mdtype);
|
md = EVP_get_digestbynid(mdtype);
|
||||||
cmdbuf = ctx->format->digest_calc(ctx, md);
|
cmdbuf = ctx->format->digest_calc(ctx, md);
|
||||||
if (!cmdbuf) {
|
if (!cmdbuf) {
|
||||||
printf("Failed to compute a message digest value\n\n");
|
printf("Failed to compute a message digest value\n\n");
|
||||||
return 1; /* Failed */
|
SpcIndirectDataContent_free(idc);
|
||||||
|
return 1; /* FAILED */
|
||||||
}
|
}
|
||||||
mdlen = EVP_MD_size(EVP_get_digestbynid(mdtype));
|
mdlen = EVP_MD_size(EVP_get_digestbynid(mdtype));
|
||||||
if (memcmp(mdbuf, cmdbuf, (size_t)mdlen)) {
|
if (memcmp(mdbuf, cmdbuf, (size_t)mdlen)) {
|
||||||
OPENSSL_free(cmdbuf);
|
OPENSSL_free(cmdbuf);
|
||||||
|
SpcIndirectDataContent_free(idc);
|
||||||
return 1; /* FAILED */
|
return 1; /* FAILED */
|
||||||
} else {
|
} else {
|
||||||
printf("Message digest algorithm : %s\n", OBJ_nid2sn(mdtype));
|
printf("Message digest algorithm : %s\n", OBJ_nid2sn(mdtype));
|
||||||
|
6
pe.c
6
pe.c
@ -462,11 +462,15 @@ static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
printf("Creating a new signature failed\n");
|
printf("Creating a new signature failed\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!add_indirect_data_object(p7, hash, ctx)) {
|
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);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
|
if (!sign_spc_indirect_data_content(p7, hash, ctx)) {
|
||||||
|
printf("Failed to set signed content\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ctx->options->nest)
|
if (ctx->options->nest)
|
||||||
ctx->options->prevsig = cursig;
|
ctx->options->prevsig = cursig;
|
||||||
|
Reference in New Issue
Block a user