From 24c95a1338bf84be3376034d5c65f023563f7626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 19 Feb 2013 23:39:40 +0100 Subject: [PATCH 1/4] build-sys: link with libgsf optionnally --- Makefile.am | 4 ++-- config.h.in | 3 +++ configure.ac | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 539bbb0..68ce495 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,9 +8,9 @@ MAINTAINERCLEANFILES = \ $(srcdir)/config.guess $(srcdir)/config.sub EXTRA_DIST = .gitignore -AM_CFLAGS = $(OPENSSL_CFLAGS) $(OPTIONAL_LIBCURL_CFLAGS) +AM_CFLAGS = $(GSF_CFLAGS) $(OPENSSL_CFLAGS) $(OPTIONAL_LIBCURL_CFLAGS) bin_PROGRAMS = osslsigncode osslsigncode_SOURCES = osslsigncode.c -osslsigncode_LDADD = $(OPENSSL_LIBS) $(OPTIONAL_LIBCURL_LIBS) +osslsigncode_LDADD = $(GSF_LIBS) $(OPENSSL_LIBS) $(OPTIONAL_LIBCURL_LIBS) diff --git a/config.h.in b/config.h.in index 4f29fcf..f872a40 100644 --- a/config.h.in +++ b/config.h.in @@ -88,6 +88,9 @@ /* Version number of package */ #undef VERSION +/* Have libgsf? */ +#undef WITH_GSF + /* Define to 1 if on MINIX. */ #undef _MINIX diff --git a/configure.ac b/configure.ac index 4ff5b8e..ee8f015 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,20 @@ AC_CHECK_LIB( [DL_LIBS="-ldl"] ) +AC_ARG_WITH([gsf], + AS_HELP_STRING([--without-gsf], [Ignore presence of libgsf and disable it]) +) +AS_IF([test "x$with_gsf" != "xno"], + [PKG_CHECK_MODULES([GSF], [libgsf-1], [have_gsf=yes], [have_gsf=no])], + [have_gsf=no] +) +AS_IF([test "x$have_gsf" = "xyes"], + [AC_DEFINE([WITH_GSF], 1, [Have libgsf?])], + [AS_IF([test "x$with_gsf" = "xyes"], + [AC_MSG_ERROR([libgsf requested but not found])])] +) + + PKG_CHECK_MODULES( [OPENSSL], [libcrypto >= 0.9.8], From 7dd6c8d3aab52404177323ec2ea4d8a45b9e2482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 5 Mar 2013 11:50:35 +0100 Subject: [PATCH 2/4] build-sys: remove generated file --- config.h.in | 105 ---------------------------------------------------- 1 file changed, 105 deletions(-) delete mode 100644 config.h.in diff --git a/config.h.in b/config.h.in deleted file mode 100644 index f872a40..0000000 --- a/config.h.in +++ /dev/null @@ -1,105 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* libcurl is enabled */ -#undef ENABLE_CURL - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have mmap */ -#undef HAVE_MMAP - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_MMAN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define to 1 if you can safely include both and . */ -#undef TIME_WITH_SYS_TIME - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ -#endif - - -/* Version number of package */ -#undef VERSION - -/* Have libgsf? */ -#undef WITH_GSF - -/* Define to 1 if on MINIX. */ -#undef _MINIX - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -#undef _POSIX_1_SOURCE - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -#undef _POSIX_SOURCE - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const From 0c6c7f042fbd04d9f881f17e643bf527fa00b5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 20 Feb 2013 10:34:22 +0100 Subject: [PATCH 3/4] Use an enum for file type --- osslsigncode.c | 71 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/osslsigncode.c b/osslsigncode.c index 89040f2..f78f98f 100644 --- a/osslsigncode.c +++ b/osslsigncode.c @@ -472,8 +472,13 @@ ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid) } #endif +enum { + FILE_TYPE_CAB, + FILE_TYPE_PE, + FILE_TYPE_MSI, +}; -static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, int isjava) +static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, int type) { static const unsigned char obsolete[] = { 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62, @@ -487,7 +492,6 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in SpcLink *link; SpcIndirectDataContent *idc = SpcIndirectDataContent_new(); idc->data = SpcAttributeTypeAndOptionalValue_new(); - idc->data->type = OBJ_txt2obj(isjava ? SPC_CAB_DATA_OBJID : SPC_PE_IMAGE_DATA_OBJID, 1); link = SpcLink_new(); link->type = 2; @@ -499,12 +503,12 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in idc->data->value = ASN1_TYPE_new(); idc->data->value->type = V_ASN1_SEQUENCE; idc->data->value->value.sequence = ASN1_STRING_new(); - if (isjava) { + if (type == FILE_TYPE_CAB) { l = i2d_SpcLink(link, NULL); p = OPENSSL_malloc(l); i2d_SpcLink(link, &p); p -= l; - } else { + } else if (type == FILE_TYPE_PE) { SpcPeImageData *pid = SpcPeImageData_new(); pid->flags = ASN1_BIT_STRING_new(); ASN1_BIT_STRING_set(pid->flags, (unsigned char*)"0", 0); @@ -513,7 +517,11 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in p = OPENSSL_malloc(l); i2d_SpcPeImageData(pid, &p); p -= l; + idc->data->type = OBJ_txt2obj(SPC_PE_IMAGE_DATA_OBJID, 1); + } else { + exit(1); } + idc->data->value->value.sequence->data = p; idc->data->value->value.sequence->length = l; idc->messageDigest = DigestInfo_new(); @@ -555,7 +563,7 @@ int main(int argc, char **argv) char *turl = NULL, *proxy = NULL; #endif u_char *p; - int i, len = 0, is_cabinet = 0, jp = -1, fd = -1, pe32plus = 0, comm = 0; + int i, len = 0, type = 0, jp = -1, fd = -1, pe32plus = 0, comm = 0; unsigned int tmp, peheader = 0, padlen; struct stat st; @@ -731,16 +739,21 @@ int main(int argc, char **argv) DO_EXIT_1("Failed to open file: %s\n", infile); if (!memcmp(indata, "MSCF", 4)) - is_cabinet = 1; - else if (memcmp(indata, "MZ", 2)) + type = FILE_TYPE_CAB; + else if (!memcmp(indata, "MZ", 2)) + type = FILE_TYPE_PE; + else DO_EXIT_1("Unrecognized file type: %s\n", infile); - if (is_cabinet) { + hash = BIO_new(BIO_f_md()); + BIO_set_md(hash, md); + + if (type == FILE_TYPE_CAB) { if (st.st_size < 44) DO_EXIT_1("Corrupt cab file - too short: %s\n", infile); if (indata[0x1e] != 0x00 || indata[0x1f] != 0x00) DO_EXIT_0("Cannot sign cab files with flag bits set!\n"); /* XXX */ - } else { + } else if (type == FILE_TYPE_PE) { if (st.st_size < 64) DO_EXIT_1("Corrupt DOS file - too short: %s\n", infile); peheader = GET_UINT32_LE(indata+60); @@ -750,16 +763,16 @@ int main(int argc, char **argv) DO_EXIT_1("Unrecognized DOS file type: %s\n", infile); } - /* Create outdata file */ - outdata = BIO_new_file(outfile, "wb"); - if (outdata == NULL) - DO_EXIT_1("Failed to create file: %s\n", outfile); + if (type == FILE_TYPE_CAB || type == FILE_TYPE_PE) { + /* Create outdata file */ + outdata = BIO_new_file(outfile, "wb"); + if (outdata == NULL) + DO_EXIT_1("Failed to create file: %s\n", outfile); - hash = BIO_new(BIO_f_md()); - BIO_set_md(hash, md); - BIO_push(hash, outdata); + BIO_push(hash, outdata); + } - if (is_cabinet) { + if (type == FILE_TYPE_CAB) { unsigned short nfolders; u_char cabsigned[] = { @@ -803,7 +816,7 @@ int main(int argc, char **argv) /* Write what's left */ BIO_write(hash, indata+i, st.st_size-i); - } else { + } else if (type == FILE_TYPE_PE) { if (jp >= 0) fprintf(stderr, "Warning: -jp option is only valid " "for CAB files.\n"); @@ -865,7 +878,7 @@ int main(int argc, char **argv) (si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)); - if (is_cabinet && jp >= 0) { + if (type == FILE_TYPE_CAB && jp >= 0) { const u_char *attrs = NULL; static const u_char java_attrs_low[] = { 0x30, 0x06, 0x03, 0x02, 0x00, 0x01, 0x30, 0x00 @@ -931,7 +944,7 @@ int main(int argc, char **argv) if ((sigdata = PKCS7_dataInit(sig, NULL)) == NULL) DO_EXIT_0("Signing failed(PKCS7_dataInit)\n"); - get_indirect_data_blob(&p, &len, md, is_cabinet); + get_indirect_data_blob(&p, &len, md, type); len -= EVP_MD_size(md); memcpy(buf, p, len); i = BIO_gets(hash, buf + len, EVP_MAX_MD_SIZE); @@ -968,7 +981,7 @@ int main(int argc, char **argv) p -= len; padlen = (8 - len%8) % 8; - if (!is_cabinet) { + if (type == FILE_TYPE_PE) { static const char magic[] = { 0x00, 0x02, 0x02, 0x00 }; @@ -977,21 +990,23 @@ int main(int argc, char **argv) BIO_write(outdata, magic, sizeof(magic)); } - BIO_write(outdata, p, len); + if (type == FILE_TYPE_PE || type == FILE_TYPE_CAB) { + BIO_write(outdata, p, len); - /* pad (with 0's) asn1 blob to 8 byte boundary */ - if (padlen > 0) { - memset(p, 0, padlen); - BIO_write(outdata, p, padlen); + /* pad (with 0's) asn1 blob to 8 byte boundary */ + if (padlen > 0) { + memset(p, 0, padlen); + BIO_write(outdata, p, padlen); + } } - if (!is_cabinet) { + if (type == FILE_TYPE_PE) { (void)BIO_seek(outdata, peheader+152+pe32plus*16); PUT_UINT32_LE(st.st_size, buf); BIO_write(outdata, buf, 4); PUT_UINT32_LE(len+8+padlen, buf); BIO_write(outdata, buf, 4); - } else { + } else if (type == FILE_TYPE_CAB) { (void)BIO_seek(outdata, 0x30); PUT_UINT32_LE(len+padlen, buf); BIO_write(outdata, buf, 4); From a1abd3f11f45eab2bef70987d726978814bf9292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 19 Feb 2013 23:44:23 +0100 Subject: [PATCH 4/4] Add MSI signing I have tested signing with various MSI files, but I wouldn't be surprised if we have to refine a little bit the hashing order. It took me a while to realize that they probably just memcmp the utf16 OLE directory entry name, and take them in order... I got confused because libgsf uses utf8, and the stream name themself are weirdly encoded to pack them in utf16, making it hard to understand why a stream name "FO"<"AA" but "FA">"AA", anyway... --- osslsigncode.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 222 insertions(+), 4 deletions(-) diff --git a/osslsigncode.c b/osslsigncode.c index f78f98f..269562a 100644 --- a/osslsigncode.c +++ b/osslsigncode.c @@ -58,6 +58,16 @@ static const char *rcsid = "$Id: osslsigncode.c,v 1.4 2011/08/12 11:08:12 mfive #include #endif +#ifdef WITH_GSF +#include +#include +#include +#include +#include +#include +#include +#endif + #include #include #include @@ -81,7 +91,7 @@ static const char *rcsid = "$Id: osslsigncode.c,v 1.4 2011/08/12 11:08:12 mfive #define SPC_PE_IMAGE_DATA_OBJID "1.3.6.1.4.1.311.2.1.15" #define SPC_CAB_DATA_OBJID "1.3.6.1.4.1.311.2.1.25" #define SPC_TIME_STAMP_REQUEST_OBJID "1.3.6.1.4.1.311.3.2.1" - +#define SPC_SIPINFO_OBJID "1.3.6.1.4.1.311.2.1.30" /* 1.3.6.1.4.1.311.4... MS Crypto 2.0 stuff... */ @@ -212,6 +222,28 @@ ASN1_SEQUENCE(SpcPeImageData) = { IMPLEMENT_ASN1_FUNCTIONS(SpcPeImageData) +typedef struct { + ASN1_INTEGER *a; + ASN1_OCTET_STRING *string; + ASN1_INTEGER *b; + ASN1_INTEGER *c; + ASN1_INTEGER *d; + ASN1_INTEGER *e; + ASN1_INTEGER *f; +} SpcSipinfo; + +ASN1_SEQUENCE(SpcSipinfo) = { + ASN1_SIMPLE(SpcSipinfo, a, ASN1_INTEGER), + ASN1_SIMPLE(SpcSipinfo, string, ASN1_OCTET_STRING), + ASN1_SIMPLE(SpcSipinfo, b, ASN1_INTEGER), + ASN1_SIMPLE(SpcSipinfo, c, ASN1_INTEGER), + ASN1_SIMPLE(SpcSipinfo, d, ASN1_INTEGER), + ASN1_SIMPLE(SpcSipinfo, e, ASN1_INTEGER), + ASN1_SIMPLE(SpcSipinfo, f, ASN1_INTEGER), +} ASN1_SEQUENCE_END(SpcSipinfo) + +IMPLEMENT_ASN1_FUNCTIONS(SpcSipinfo) + #ifdef ENABLE_CURL typedef struct { @@ -485,6 +517,10 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e }; + static const unsigned char msistr[] = { + 0xf1, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 + }; u_char *p; int hashlen, l; @@ -518,6 +554,23 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in i2d_SpcPeImageData(pid, &p); p -= l; idc->data->type = OBJ_txt2obj(SPC_PE_IMAGE_DATA_OBJID, 1); + } else if (type == FILE_TYPE_MSI) { + SpcSipinfo *si = SpcSipinfo_new(); + + si->a = ASN1_INTEGER_new(); + ASN1_INTEGER_set(si->a, 1); + si->string = M_ASN1_OCTET_STRING_new(); + M_ASN1_OCTET_STRING_set(si->string, msistr, sizeof(msistr)); + si->b = ASN1_INTEGER_new(); + si->c = ASN1_INTEGER_new(); + si->d = ASN1_INTEGER_new(); + si->e = ASN1_INTEGER_new(); + si->f = ASN1_INTEGER_new(); + l = i2d_SpcSipinfo(si, NULL); + p = OPENSSL_malloc(l); + i2d_SpcSipinfo(si, &p); + p -= l; + idc->data->type = OBJ_txt2obj(SPC_SIPINFO_OBJID, 1); } else { exit(1); } @@ -542,6 +595,78 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in i2d_SpcIndirectDataContent(idc, &p); } + +#ifdef WITH_GSF +static gint msi_base64_decode(gint x) +{ + if (x < 10) + return x + '0'; + if (x < (10 + 26)) + return x - 10 + 'A'; + if (x < (10 + 26 + 26)) + return x - 10 - 26 + 'a'; + if (x == (10 + 26 + 26)) + return '.'; + return 1; +} + +static void msi_decode(const guint8 *in, gchar *out) +{ + guint count = 0; + guint8 *q = (guint8 *)out; + + /* utf-8 encoding of 0x4840 */ + if (in[0] == 0xe4 && in[1] == 0xa1 && in[2] == 0x80) + in += 3; + + while (*in) { + guint8 ch = *in; + if ((ch == 0xe3 && in[1] >= 0xa0) || (ch == 0xe4 && in[1] < 0xa0)) { + *q++ = msi_base64_decode(in[2] & 0x7f); + *q++ = msi_base64_decode(in[1] ^ 0xa0); + in += 3; + count += 2; + continue; + } + if (ch == 0xe4 && in[1] == 0xa0) { + *q++ = msi_base64_decode(in[2] & 0x7f); + in += 3; + count++; + continue; + } + *q++ = *in++; + if (ch >= 0xc1) + *q++ = *in++; + if (ch >= 0xe0) + *q++ = *in++; + if (ch >= 0xf0) + *q++ = *in++; + count++; + } + *q = 0; +} + +/* + * Sorry if this code looks a bit silly, but that seems + * to be the best solution so far... + */ +static gint msi_cmp(gpointer a, gpointer b) +{ + gchar *pa = (gchar*)g_utf8_to_utf16(a, -1, NULL, NULL, NULL); + gchar *pb = (gchar*)g_utf8_to_utf16(b, -1, NULL, NULL, NULL); + gint diff; + + diff = memcmp(pa, pb, MIN(strlen(pa), strlen(pb))); + /* apparently the longer wins */ + if (diff == 0) + return strlen(pa) > strlen(pb) ? 1 : -1; + g_free(pa); + g_free(pb); + + return diff; +} +#endif + int main(int argc, char **argv) { BIO *btmp, *sigdata, *hash, *outdata; @@ -567,6 +692,12 @@ int main(int argc, char **argv) unsigned int tmp, peheader = 0, padlen; struct stat st; +#ifdef WITH_GSF + GsfOutfile *outole; + GsfOutput *sink; + gsf_init(); +#endif + #if 0 static u_char spcIndirectDataContext_blob_cab[] = { 0x30, 0x50, @@ -612,6 +743,9 @@ int main(int argc, char **argv) 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x16 }; + static u_char msi_signature[] = { + 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 + }; spcfile = keyfile = pkcs12file = infile = outfile = desc = url = NULL; hash = outdata = NULL; @@ -664,16 +798,28 @@ int main(int argc, char **argv) proxy = *(++argv); #endif } else if (!strcmp(*argv, "-v") || !strcmp(*argv, "--version")) { - printf(PACKAGE_STRING ", using:\n\t%s\n\t%s\n\nPlease send bug-reports to " - PACKAGE_BUGREPORT - "\n\n", + printf(PACKAGE_STRING ", using:\n\t%s\n\t%s\n", SSLeay_version(SSLEAY_VERSION), #ifdef ENABLE_CURL curl_version() #else "no libcurl available" +#endif + ); + printf( +#ifdef WITH_GSF + "\tlibgsf %d.%d.%d\n", + libgsf_major_version, + libgsf_minor_version, + libgsf_micro_version +#else + "\tno libgsf available\n" #endif ); + printf("\nPlease send bug-reports to " + PACKAGE_BUGREPORT + "\n\n"); + } else if (!strcmp(*argv, "-jp")) { char *ap; if (--argc < 1) usage(argv0); @@ -742,6 +888,8 @@ int main(int argc, char **argv) type = FILE_TYPE_CAB; else if (!memcmp(indata, "MZ", 2)) type = FILE_TYPE_PE; + else if (!memcmp(indata, msi_signature, sizeof(msi_signature))) + type = FILE_TYPE_MSI; else DO_EXIT_1("Unrecognized file type: %s\n", infile); @@ -761,6 +909,64 @@ int main(int argc, char **argv) DO_EXIT_1("Corrupt PE file - too short: %s\n", infile); if (memcmp(indata+peheader, "PE\0\0", 4)) DO_EXIT_1("Unrecognized DOS file type: %s\n", infile); + } else if (type == FILE_TYPE_MSI) { +#ifdef WITH_GSF + GsfInput *src; + GsfInfile *ole; + GSList *sorted = NULL; + guint8 classid[16]; + gchar decoded[0x40]; + + BIO_push(hash, BIO_new(BIO_s_null())); + + src = gsf_input_stdio_new(infile, NULL); + if (!src) + DO_EXIT_1("Error opening file %s", infile); + + sink = gsf_output_stdio_new(outfile, NULL); + if (!sink) + DO_EXIT_1("Error opening output file %s", outfile); + + ole = gsf_infile_msole_new(src, NULL); + gsf_infile_msole_get_class_id(GSF_INFILE_MSOLE(ole), classid); + + outole = gsf_outfile_msole_new(sink); + gsf_outfile_msole_set_class_id(GSF_OUTFILE_MSOLE(outole), classid); + + for (i = 0; i < gsf_infile_num_children(ole); i++) { + GsfInput *child = gsf_infile_child_by_index(ole, i); + const guint8 *name = gsf_input_name(child); + msi_decode(name, decoded); + if (!g_strcmp0(decoded, "\05DigitalSignature")) + continue; + + sorted = g_slist_insert_sorted(sorted, (gpointer)name, (GCompareFunc)msi_cmp); + } + + for (; sorted; sorted = sorted->next) { + GsfInput *child = gsf_infile_child_by_name(ole, (gchar*)sorted->data); + msi_decode(sorted->data, decoded); + if (child == NULL) + continue; + + GsfOutput *outchild = gsf_outfile_new_child(outole, (gchar*)sorted->data, FALSE); + while (gsf_input_remaining(child) > 0) { + gsf_off_t size = MIN(gsf_input_remaining(child), 4096); + guint8 const *data = gsf_input_read(child, size, NULL); + BIO_write(hash, data, size); + if (!gsf_output_write(outchild, size, data)) + DO_EXIT_1("Error writing %s", outfile); + } + g_object_unref(child); + gsf_output_close(outchild); + g_object_unref(outchild); + } + + BIO_write(hash, classid, sizeof(classid)); + g_slist_free(sorted); +#else + DO_EXIT_1("libgsf is not available, msi support is disabled: %s\n", infile); +#endif } if (type == FILE_TYPE_CAB || type == FILE_TYPE_PE) { @@ -998,6 +1204,18 @@ int main(int argc, char **argv) memset(p, 0, padlen); BIO_write(outdata, p, padlen); } +#ifdef WITH_GSF + } else if (type == FILE_TYPE_MSI) { + GsfOutput *child; + GError *error = NULL; + + child = gsf_outfile_new_child(outole, "\05DigitalSignature", FALSE); + if (!gsf_output_write(child, len, p)) + DO_EXIT_1("Failed to write MSI signature to %s", infile); + gsf_output_close(child); + gsf_output_close(GSF_OUTPUT(outole)); + g_object_unref(sink); +#endif } if (type == FILE_TYPE_PE) {