- improved checks for valid PE file

- initialize OpenSSL before we use it
- updated documentation links
- fixed bug in MSI merge (missing CAB OBJID set)
- reindentation + Emacs settings for it
- fixed various warnings
This commit is contained in:
Per Allansson 2013-03-07 07:52:46 +01:00
parent b34b3b67e7
commit d16acb6019

View File

@ -37,6 +37,14 @@ static const char *rcsid = "$Id: osslsigncode.c,v 1.4 2011/08/12 11:08:12 mfive
http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
* MS Windows Authenticode PE Signature Format
http://msdn.microsoft.com/en-US/windows/hardware/gg463183
(Although the part of how the actual checksumming is done is not
how it is done inside Windows. The end result is however the same
on all "normal" PE files.)
* tail -c, tcpdump, mimencode & openssl asn1parse :) * tail -c, tcpdump, mimencode & openssl asn1parse :)
*/ */
@ -480,6 +488,7 @@ static void usage(const char *argv0)
#define DO_EXIT_0(x) { fputs(x, stderr); goto err_cleanup; } #define DO_EXIT_0(x) { fputs(x, stderr); goto err_cleanup; }
#define DO_EXIT_1(x, y) { fprintf(stderr, x, y); goto err_cleanup; } #define DO_EXIT_1(x, y) { fprintf(stderr, x, y); goto err_cleanup; }
#define DO_EXIT_2(x, y, z) { fprintf(stderr, x, y, z); goto err_cleanup; }
#define GET_UINT16_LE(p) (((u_char*)(p))[0] | (((u_char*)(p))[1]<<8)) #define GET_UINT16_LE(p) (((u_char*)(p))[0] | (((u_char*)(p))[1]<<8))
@ -544,6 +553,7 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in
p = OPENSSL_malloc(l); p = OPENSSL_malloc(l);
i2d_SpcLink(link, &p); i2d_SpcLink(link, &p);
p -= l; p -= l;
idc->data->type = OBJ_txt2obj(SPC_CAB_DATA_OBJID, 1);
} else if (type == FILE_TYPE_PE) { } else if (type == FILE_TYPE_PE) {
SpcPeImageData *pid = SpcPeImageData_new(); SpcPeImageData *pid = SpcPeImageData_new();
pid->flags = ASN1_BIT_STRING_new(); pid->flags = ASN1_BIT_STRING_new();
@ -572,6 +582,7 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in
p -= l; p -= l;
idc->data->type = OBJ_txt2obj(SPC_SIPINFO_OBJID, 1); idc->data->type = OBJ_txt2obj(SPC_SIPINFO_OBJID, 1);
} else { } else {
fprintf(stderr, "Unexpected file type: %d\n", type);
exit(1); exit(1);
} }
@ -703,7 +714,7 @@ int main(int argc, char **argv)
PKCS7_SIGNER_INFO *si; PKCS7_SIGNER_INFO *si;
ASN1_TYPE dummy; ASN1_TYPE dummy;
ASN1_STRING *astr; ASN1_STRING *astr;
const EVP_MD *md = EVP_sha1(); const EVP_MD *md;
const char *argv0 = argv[0]; const char *argv0 = argv[0];
static char buf[64*1024]; static char buf[64*1024];
@ -715,14 +726,9 @@ int main(int argc, char **argv)
u_char *p; u_char *p;
int i, len = 0, type = 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; unsigned int tmp, peheader = 0, padlen;
off_t fileend;
struct stat st; struct stat st;
#ifdef WITH_GSF
GsfOutfile *outole;
GsfOutput *sink;
gsf_init();
#endif
#if 0 #if 0
static u_char spcIndirectDataContext_blob_cab[] = { static u_char spcIndirectDataContext_blob_cab[] = {
0x30, 0x50, 0x30, 0x50,
@ -772,6 +778,17 @@ int main(int argc, char **argv)
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
}; };
#ifdef WITH_GSF
GsfOutfile *outole = NULL;
GsfOutput *sink = NULL;
gsf_init();
#endif
/* Set up OpenSSL */
ERR_load_crypto_strings();
OPENSSL_add_all_algorithms_conf();
md = EVP_sha1();
spcfile = keyfile = pkcs12file = infile = outfile = desc = url = NULL; spcfile = keyfile = pkcs12file = infile = outfile = desc = url = NULL;
hash = outdata = NULL; hash = outdata = NULL;
@ -867,10 +884,6 @@ int main(int argc, char **argv)
if (!infile || !outfile || !((spcfile && keyfile) || pkcs12file)) if (!infile || !outfile || !((spcfile && keyfile) || pkcs12file))
usage(argv0); usage(argv0);
/* Set up OpenSSL */
ERR_load_crypto_strings();
OPENSSL_add_all_algorithms_conf();
/* Read certificate and key */ /* Read certificate and key */
if (pkcs12file != NULL) { if (pkcs12file != NULL) {
if ((btmp = BIO_new_file(pkcs12file, "rb")) == NULL || if ((btmp = BIO_new_file(pkcs12file, "rb")) == NULL ||
@ -899,6 +912,8 @@ int main(int argc, char **argv)
if (stat(infile, &st)) if (stat(infile, &st))
DO_EXIT_1("Failed to open file: %s\n", infile); DO_EXIT_1("Failed to open file: %s\n", infile);
fileend = st.st_size;
if (st.st_size < 4) if (st.st_size < 4)
DO_EXIT_1("Unrecognized file type - file is too short: %s\n", infile); DO_EXIT_1("Unrecognized file type - file is too short: %s\n", infile);
@ -960,7 +975,7 @@ int main(int argc, char **argv)
for (i = 0; i < gsf_infile_num_children(ole); i++) { for (i = 0; i < gsf_infile_num_children(ole); i++) {
GsfInput *child = gsf_infile_child_by_index(ole, i); GsfInput *child = gsf_infile_child_by_index(ole, i);
const guint8 *name = gsf_input_name(child); const guint8 *name = (const guint8*)gsf_input_name(child);
msi_decode(name, decoded); msi_decode(name, decoded);
if (!g_strcmp0(decoded, "\05DigitalSignature")) if (!g_strcmp0(decoded, "\05DigitalSignature"))
continue; continue;
@ -1048,18 +1063,38 @@ int main(int argc, char **argv)
/* Write what's left */ /* Write what's left */
BIO_write(hash, indata+i, st.st_size-i); BIO_write(hash, indata+i, st.st_size-i);
} else if (type == FILE_TYPE_PE) { } else if (type == FILE_TYPE_PE) {
unsigned int sigpos, siglen, nrvas;
unsigned short magic;
if (jp >= 0) if (jp >= 0)
fprintf(stderr, "Warning: -jp option is only valid " fprintf(stderr, "Warning: -jp option is only valid "
"for CAB files.\n"); "for CAB files.\n");
pe32plus = GET_UINT16_LE(indata + peheader + 24) == 0x20b ? 1 : 0; magic = GET_UINT16_LE(indata + peheader + 24);
if (magic == 0x20b) {
pe32plus = 1;
} else if (magic == 0x10b) {
pe32plus = 0;
} else {
DO_EXIT_2("Corrupt PE file - found unknown magic %x: %s\n", magic, infile);
}
/* If the file has been signed already, this will let us pretend the file we are signing is nrvas = GET_UINT32_LE(indata + peheader + 116 + pe32plus*16);
* only as big as the portion that exists before the signed data at the end of the file. if (nrvas < 5)
* This prevents adding more and more data to the end of the file with each signing. DO_EXIT_1("Can not sign PE files without certificate table resource: %s\n", infile);
*/
i = GET_UINT32_LE(indata + peheader + 152 + pe32plus*16); sigpos = GET_UINT32_LE(indata + peheader + 152 + pe32plus*16);
if( i > 0 ) st.st_size = i; siglen = GET_UINT32_LE(indata + peheader + 152 + pe32plus*16 + 4);
/* Since fix for MS Bulletin MS12-024 we can really assume
that signature should be last part of file */
if (sigpos > 0 && sigpos + siglen != st.st_size)
DO_EXIT_1("Corrupt PE file - current signature not at end of file: %s\n", infile);
if (sigpos > 0) {
/* Strip current signature */
fileend = sigpos;
}
BIO_write(hash, indata, peheader + 88); BIO_write(hash, indata, peheader + 88);
i = peheader + 88; i = peheader + 88;
@ -1071,14 +1106,14 @@ int main(int argc, char **argv)
BIO_write(outdata, indata + i, 8); BIO_write(outdata, indata + i, 8);
i += 8; i += 8;
BIO_write(hash, indata + i, st.st_size - i); BIO_write(hash, indata + i, fileend - i);
/* pad (with 0's) pe file to 8 byte boundary */ /* pad (with 0's) pe file to 8 byte boundary */
len = 8 - st.st_size % 8; len = 8 - fileend % 8;
if (len > 0 && len != 8) { if (len > 0 && len != 8) {
memset(buf, 0, len); memset(buf, 0, len);
BIO_write(hash, buf, len); BIO_write(hash, buf, len);
st.st_size += len; fileend += len;
} }
} }
sig = PKCS7_new(); sig = PKCS7_new();
@ -1213,12 +1248,12 @@ int main(int argc, char **argv)
padlen = (8 - len%8) % 8; padlen = (8 - len%8) % 8;
if (type == FILE_TYPE_PE) { if (type == FILE_TYPE_PE) {
static const char magic[] = { static const char cert_rev_and_type[] = {
0x00, 0x02, 0x02, 0x00 0x00, 0x02, 0x02, 0x00
}; };
PUT_UINT32_LE(len+8+padlen, buf); PUT_UINT32_LE(len+8+padlen, buf);
BIO_write(outdata, buf, 4); BIO_write(outdata, buf, 4);
BIO_write(outdata, magic, sizeof(magic)); BIO_write(outdata, cert_rev_and_type, sizeof(cert_rev_and_type));
} }
if (type == FILE_TYPE_PE || type == FILE_TYPE_CAB) { if (type == FILE_TYPE_PE || type == FILE_TYPE_CAB) {
@ -1231,10 +1266,7 @@ int main(int argc, char **argv)
} }
#ifdef WITH_GSF #ifdef WITH_GSF
} else if (type == FILE_TYPE_MSI) { } else if (type == FILE_TYPE_MSI) {
GsfOutput *child; GsfOutput *child = gsf_outfile_new_child(outole, "\05DigitalSignature", FALSE);
GError *error = NULL;
child = gsf_outfile_new_child(outole, "\05DigitalSignature", FALSE);
if (!gsf_output_write(child, len, p)) if (!gsf_output_write(child, len, p))
DO_EXIT_1("Failed to write MSI signature to %s", infile); DO_EXIT_1("Failed to write MSI signature to %s", infile);
gsf_output_close(child); gsf_output_close(child);
@ -1245,7 +1277,7 @@ int main(int argc, char **argv)
if (type == FILE_TYPE_PE) { if (type == FILE_TYPE_PE) {
(void)BIO_seek(outdata, peheader+152+pe32plus*16); (void)BIO_seek(outdata, peheader+152+pe32plus*16);
PUT_UINT32_LE(st.st_size, buf); PUT_UINT32_LE(fileend, buf);
BIO_write(outdata, buf, 4); BIO_write(outdata, buf, 4);
PUT_UINT32_LE(len+8+padlen, buf); PUT_UINT32_LE(len+8+padlen, buf);
BIO_write(outdata, buf, 4); BIO_write(outdata, buf, 4);
@ -1271,3 +1303,11 @@ err_cleanup:
fprintf(stderr, "\nFailed\n"); fprintf(stderr, "\nFailed\n");
return -1; return -1;
} }
/*
Local Variables:
c-basic-offset: 4
tab-width: 4
indent-tabs-mode: t
End:
*/