mirror of
https://github.com/mtrojnar/osslsigncode.git
synced 2025-05-20 10:24:29 -05:00
Added support for removing/extracting/verifying signature on PE files
This commit is contained in:
parent
bb7c430b8f
commit
9fb9e1503c
470
osslsigncode.c
470
osslsigncode.c
@ -103,6 +103,10 @@ static const char *rcsid = "$Id: osslsigncode.c,v 1.4 2011/08/12 11:08:12 mfive
|
|||||||
/* 1.3.6.1.4.1.311.4... MS Crypto 2.0 stuff... */
|
/* 1.3.6.1.4.1.311.4... MS Crypto 2.0 stuff... */
|
||||||
|
|
||||||
|
|
||||||
|
#define WIN_CERT_REVISION_2 0x0200
|
||||||
|
#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ASN.1 definitions (more or less from official MS Authenticode docs)
|
ASN.1 definitions (more or less from official MS Authenticode docs)
|
||||||
*/
|
*/
|
||||||
@ -472,16 +476,20 @@ static int add_timestamp(PKCS7 *sig, char *url, char *proxy)
|
|||||||
static void usage(const char *argv0)
|
static void usage(const char *argv0)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s [ --version | -v ]\n"
|
"Usage: %s\n\n\t[ --version | -v ]\n\n"
|
||||||
"\t( -spc <spcfile> -key <keyfile> |\n"
|
"\t[ sign ]\n"
|
||||||
"\t -pkcs12 <pkcs12file> )\n"
|
"\t\t( -spc <spcfile> -key <keyfile> | -pkcs12 <pkcs12file> )\n"
|
||||||
"\t[ -pass <keypass> ]\n"
|
"\t\t[ -pass <keypass> ]\n"
|
||||||
"\t[ -h {md5,sha1,sha2} ]\n"
|
"\t\t[ -h {md5,sha1,sha2} ]\n"
|
||||||
"\t[ -n <desc> ] [ -i <url> ] [ -jp <level> ] [ -comm ]\n"
|
"\t\t[ -n <desc> ] [ -i <url> ] [ -jp <level> ] [ -comm ]\n"
|
||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
"\t[ -t <timestampurl> [ -p <proxy> ]]\n"
|
"\t\t[ -t <timestampurl> [ -p <proxy> ]]\n"
|
||||||
#endif
|
#endif
|
||||||
"\t-in <infile> -out <outfile>\n",
|
"\t\t[ -in ] <infile> [-out ] <outfile>\n\n"
|
||||||
|
"\textract-signature [ -in ] <infile> [ -out ] <outfile>\n\n"
|
||||||
|
"\tremove-signature [ -in ] <infile> [ -out ] <outfile>\n\n"
|
||||||
|
"\tverify [ -in ] <infile>\n\n"
|
||||||
|
"",
|
||||||
argv0);
|
argv0);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
@ -495,6 +503,10 @@ static void usage(const char *argv0)
|
|||||||
#define GET_UINT32_LE(p) (((u_char*)(p))[0] | (((u_char*)(p))[1]<<8) | \
|
#define GET_UINT32_LE(p) (((u_char*)(p))[0] | (((u_char*)(p))[1]<<8) | \
|
||||||
(((u_char*)(p))[2]<<16) | (((u_char*)(p))[3]<<24))
|
(((u_char*)(p))[2]<<16) | (((u_char*)(p))[3]<<24))
|
||||||
|
|
||||||
|
#define PUT_UINT16_LE(i,p) \
|
||||||
|
((u_char*)(p))[0] = (i) & 0xff; \
|
||||||
|
((u_char*)(p))[1] = ((i)>>8) & 0xff
|
||||||
|
|
||||||
#define PUT_UINT32_LE(i,p) \
|
#define PUT_UINT32_LE(i,p) \
|
||||||
((u_char*)(p))[0] = (i) & 0xff; \
|
((u_char*)(p))[0] = (i) & 0xff; \
|
||||||
((u_char*)(p))[1] = ((i)>>8) & 0xff; \
|
((u_char*)(p))[1] = ((i)>>8) & 0xff; \
|
||||||
@ -513,13 +525,20 @@ ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
typedef enum {
|
||||||
FILE_TYPE_CAB,
|
FILE_TYPE_CAB,
|
||||||
FILE_TYPE_PE,
|
FILE_TYPE_PE,
|
||||||
FILE_TYPE_MSI,
|
FILE_TYPE_MSI,
|
||||||
};
|
} file_type_t;
|
||||||
|
|
||||||
static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, int type)
|
typedef enum {
|
||||||
|
CMD_SIGN,
|
||||||
|
CMD_EXTRACT,
|
||||||
|
CMD_REMOVE,
|
||||||
|
CMD_VERIFY,
|
||||||
|
} cmd_type_t;
|
||||||
|
|
||||||
|
static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, file_type_t type)
|
||||||
{
|
{
|
||||||
static const unsigned char obsolete[] = {
|
static const unsigned char obsolete[] = {
|
||||||
0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62,
|
0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62,
|
||||||
@ -606,19 +625,17 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, in
|
|||||||
i2d_SpcIndirectDataContent(idc, &p);
|
i2d_SpcIndirectDataContent(idc, &p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recalc_pe_checksum(BIO *outdata, unsigned int peheader)
|
static unsigned int calc_pe_checksum(BIO *bio, unsigned int peheader)
|
||||||
{
|
{
|
||||||
unsigned int checkSum = 0;
|
unsigned int checkSum = 0;
|
||||||
unsigned short val;
|
unsigned short val;
|
||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
|
|
||||||
/* First set current checksum to 0. */
|
|
||||||
(void)BIO_seek(outdata, peheader + 88);
|
|
||||||
BIO_write(outdata, &checkSum, 4);
|
|
||||||
|
|
||||||
/* recalc checksum. */
|
/* recalc checksum. */
|
||||||
(void)BIO_seek(outdata, 0);
|
(void)BIO_seek(bio, 0);
|
||||||
while (BIO_read(outdata, &val, 2) == 2) {
|
while (BIO_read(bio, &val, 2) == 2) {
|
||||||
|
if (size == peheader + 88 || size == peheader + 90)
|
||||||
|
val = 0;
|
||||||
checkSum += val;
|
checkSum += val;
|
||||||
checkSum = 0xffff & (checkSum + (checkSum >> 0x10));
|
checkSum = 0xffff & (checkSum + (checkSum >> 0x10));
|
||||||
size += 2;
|
size += 2;
|
||||||
@ -627,9 +644,18 @@ static void recalc_pe_checksum(BIO *outdata, unsigned int peheader)
|
|||||||
checkSum = 0xffff & (checkSum + (checkSum >> 0x10));
|
checkSum = 0xffff & (checkSum + (checkSum >> 0x10));
|
||||||
checkSum += size;
|
checkSum += size;
|
||||||
|
|
||||||
|
return checkSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recalc_pe_checksum(BIO *bio, unsigned int peheader)
|
||||||
|
{
|
||||||
|
unsigned int checkSum = calc_pe_checksum(bio, peheader);
|
||||||
|
char buf[4];
|
||||||
|
|
||||||
/* write back checksum. */
|
/* write back checksum. */
|
||||||
(void)BIO_seek(outdata, peheader + 88);
|
(void)BIO_seek(bio, peheader + 88);
|
||||||
BIO_write(outdata, &checkSum, 4);
|
PUT_UINT32_LE(checkSum, buf);
|
||||||
|
BIO_write(bio, buf, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_GSF
|
#ifdef WITH_GSF
|
||||||
@ -703,6 +729,174 @@ static gint msi_cmp(gpointer a, gpointer b)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void tohex(const unsigned char *v, unsigned char *b, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len; i++)
|
||||||
|
sprintf(b+i*2, "%02X", v[i]);
|
||||||
|
b[i*2] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void calc_pe_digest(BIO *bio, const EVP_MD *md, unsigned char *mdbuf,
|
||||||
|
unsigned int peheader, int pe32plus, unsigned int fileend)
|
||||||
|
{
|
||||||
|
EVP_MD_CTX mdctx;
|
||||||
|
EVP_MD_CTX_init(&mdctx);
|
||||||
|
EVP_DigestInit(&mdctx, md);
|
||||||
|
static unsigned char bfb[16*1024*1024];
|
||||||
|
|
||||||
|
memset(mdbuf, 0, EVP_MAX_MD_SIZE);
|
||||||
|
|
||||||
|
BIO_seek(bio, 0);
|
||||||
|
BIO_read(bio, bfb, peheader + 88);
|
||||||
|
EVP_DigestUpdate(&mdctx, bfb, peheader + 88);
|
||||||
|
BIO_read(bio, bfb, 4);
|
||||||
|
BIO_read(bio, bfb, 60+pe32plus*16);
|
||||||
|
EVP_DigestUpdate(&mdctx, bfb, 60+pe32plus*16);
|
||||||
|
BIO_read(bio, bfb, 8);
|
||||||
|
|
||||||
|
unsigned int n = BIO_tell(bio);
|
||||||
|
while (n < fileend) {
|
||||||
|
int l = fileend - n;
|
||||||
|
if (l > sizeof(bfb))
|
||||||
|
l = sizeof(bfb);
|
||||||
|
l = BIO_read(bio, bfb, l);
|
||||||
|
if (l <= 0)
|
||||||
|
break;
|
||||||
|
EVP_DigestUpdate(&mdctx, bfb, l);
|
||||||
|
n += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_DigestFinal(&mdctx, mdbuf, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int der_seq_hdr_len(unsigned char *p, unsigned int len) {
|
||||||
|
if (len <= 2 || p[0] != 0x30)
|
||||||
|
return 0;
|
||||||
|
return (p[1]&0x80) ? (2 + p[1]&0x7f) : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int verify_pe_file(char *indata, unsigned int peheader, int pe32plus,
|
||||||
|
unsigned int sigpos, unsigned int siglen)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int pe_checksum = GET_UINT32_LE(indata + peheader + 88);
|
||||||
|
printf("Current PE checksum : %08X\n", pe_checksum);
|
||||||
|
|
||||||
|
BIO *bio = BIO_new_mem_buf(indata, sigpos + siglen);
|
||||||
|
unsigned int real_pe_checksum = calc_pe_checksum(bio, peheader);
|
||||||
|
if (pe_checksum && pe_checksum != real_pe_checksum)
|
||||||
|
ret = 1;
|
||||||
|
printf("Calculated PE checksum: %08X%s\n\n", real_pe_checksum,
|
||||||
|
ret ? " MISMATCH!!!!" : "");
|
||||||
|
if (siglen == 0) {
|
||||||
|
BIO_free(bio);
|
||||||
|
printf("No signature found.\n\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mdtype = -1;
|
||||||
|
unsigned char mdbuf[EVP_MAX_MD_SIZE];
|
||||||
|
unsigned int pos = 0;
|
||||||
|
unsigned char hexbuf[EVP_MAX_MD_SIZE*2+1];
|
||||||
|
PKCS7 *p7 = NULL;
|
||||||
|
|
||||||
|
while (pos < siglen && mdtype == -1) {
|
||||||
|
unsigned int l = GET_UINT32_LE(indata + sigpos + pos);
|
||||||
|
unsigned short certrev = GET_UINT16_LE(indata + sigpos + pos + 4);
|
||||||
|
unsigned short certtype = GET_UINT16_LE(indata + sigpos + pos + 6);
|
||||||
|
if (certrev == WIN_CERT_REVISION_2 && certtype == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
|
||||||
|
const unsigned char *blob = indata + sigpos + pos + 8;
|
||||||
|
p7 = d2i_PKCS7(NULL, &blob, l - 8);
|
||||||
|
if (p7 && PKCS7_type_is_signed(p7) &&
|
||||||
|
!OBJ_cmp(p7->d.sign->contents->type, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)) &&
|
||||||
|
p7->d.sign->contents->d.other->type == V_ASN1_SEQUENCE) {
|
||||||
|
|
||||||
|
ASN1_STRING *astr = p7->d.sign->contents->d.other->value.sequence;
|
||||||
|
const unsigned char *p = astr->data;
|
||||||
|
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, astr->length);
|
||||||
|
if (idc) {
|
||||||
|
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
|
||||||
|
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
|
||||||
|
memcpy(mdbuf, idc->messageDigest->digest->data, idc->messageDigest->digest->length);
|
||||||
|
}
|
||||||
|
SpcIndirectDataContent_free(idc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p7 && mdtype == -1) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
p7 = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (l%8)
|
||||||
|
l += (8 - l%8);
|
||||||
|
pos += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mdtype == -1) {
|
||||||
|
BIO_free(bio);
|
||||||
|
printf("Failed to extract current message digest\n\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Message digest algorithm : %s\n", OBJ_nid2sn(mdtype));
|
||||||
|
|
||||||
|
const EVP_MD *md = EVP_get_digestbynid(mdtype);
|
||||||
|
tohex(mdbuf, hexbuf, EVP_MD_size(md));
|
||||||
|
printf("Current message digest : %s\n", hexbuf);
|
||||||
|
|
||||||
|
calc_pe_digest(bio, md, mdbuf, peheader, pe32plus, sigpos);
|
||||||
|
printf("Calculated message digest : %s\n\n", hexbuf);
|
||||||
|
BIO_free(bio);
|
||||||
|
|
||||||
|
int seqhdrlen = der_seq_hdr_len(p7->d.sign->contents->d.other->value.sequence->data,
|
||||||
|
p7->d.sign->contents->d.other->value.sequence->length);
|
||||||
|
bio = BIO_new_mem_buf(p7->d.sign->contents->d.other->value.sequence->data + seqhdrlen,
|
||||||
|
p7->d.sign->contents->d.other->value.sequence->length - seqhdrlen);
|
||||||
|
X509_STORE *store = X509_STORE_new();
|
||||||
|
int verok = PKCS7_verify(p7, p7->d.sign->cert, store, bio, NULL, PKCS7_NOVERIFY);
|
||||||
|
/* XXX: add more checks here (attributes, pagehash, timestamp, etc) */
|
||||||
|
printf("Signature verification: %s\n\n", verok ? "ok" : "failed");
|
||||||
|
if (!verok) {
|
||||||
|
ERR_print_errors_fp(stdout);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
STACK_OF(X509) *signers = PKCS7_get0_signers(p7, NULL, 0);
|
||||||
|
printf("Number of signers: %d\n", sk_X509_num(signers));
|
||||||
|
for (i=0; i<sk_X509_num(signers); i++) {
|
||||||
|
X509 *cert = sk_X509_value(signers, i);
|
||||||
|
char *subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
|
||||||
|
char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
|
||||||
|
printf("\tSigner #%d:\n\t\tSubject: %s\n\t\tIssuer : %s\n", i, subject, issuer);
|
||||||
|
OPENSSL_free(subject);
|
||||||
|
OPENSSL_free(issuer);
|
||||||
|
}
|
||||||
|
sk_X509_free(signers);
|
||||||
|
|
||||||
|
printf("\nNumber of certificates: %d\n", sk_X509_num(p7->d.sign->cert));
|
||||||
|
for (i=0; i<sk_X509_num(p7->d.sign->cert); i++) {
|
||||||
|
X509 *cert = sk_X509_value(p7->d.sign->cert, i);
|
||||||
|
char *subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
|
||||||
|
char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
|
||||||
|
printf("\tCert #%d:\n\t\tSubject: %s\n\t\tIssuer : %s\n", i, subject, issuer);
|
||||||
|
OPENSSL_free(subject);
|
||||||
|
OPENSSL_free(issuer);
|
||||||
|
}
|
||||||
|
|
||||||
|
X509_STORE_free(store);
|
||||||
|
BIO_free(bio);
|
||||||
|
PKCS7_free(p7);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
BIO *btmp, *sigdata, *hash, *outdata;
|
BIO *btmp, *sigdata, *hash, *outdata;
|
||||||
@ -724,46 +918,13 @@ int main(int argc, char **argv)
|
|||||||
char *turl = NULL, *proxy = NULL;
|
char *turl = NULL, *proxy = NULL;
|
||||||
#endif
|
#endif
|
||||||
u_char *p;
|
u_char *p;
|
||||||
int i, len = 0, type = 0, jp = -1, fd = -1, pe32plus = 0, comm = 0;
|
int ret = 0, i, len = 0, jp = -1, fd = -1, pe32plus = 0, comm = 0;
|
||||||
unsigned int tmp, peheader = 0, padlen;
|
unsigned int tmp, peheader = 0, padlen;
|
||||||
off_t fileend;
|
off_t fileend;
|
||||||
|
file_type_t type;
|
||||||
|
cmd_type_t cmd = CMD_SIGN;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
char *failarg = NULL;
|
||||||
#if 0
|
|
||||||
static u_char spcIndirectDataContext_blob_cab[] = {
|
|
||||||
0x30, 0x50,
|
|
||||||
|
|
||||||
0x30, 0x2c,
|
|
||||||
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x19,
|
|
||||||
0xa2, 0x1e, 0x80, 0x1c,
|
|
||||||
0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65,
|
|
||||||
0x00, 0x74, 0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
|
|
||||||
|
|
||||||
0x30, 0x20,
|
|
||||||
0x30, 0x0c,
|
|
||||||
0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05,
|
|
||||||
0x05, 0x00,
|
|
||||||
0x04, 0x10 /* + hash */
|
|
||||||
};
|
|
||||||
|
|
||||||
static u_char spcIndirectDataContext_blob_pe[] = {
|
|
||||||
0x30, 0x57,
|
|
||||||
|
|
||||||
0x30, 0x33,
|
|
||||||
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x0f,
|
|
||||||
0x30, 0x25, 0x03, 0x01, 0x00,
|
|
||||||
0xa0, 0x20, 0xa2, 0x1e, 0x80, 0x1c,
|
|
||||||
0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62,
|
|
||||||
0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74,
|
|
||||||
0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
|
|
||||||
|
|
||||||
0x30, 0x20,
|
|
||||||
0x30, 0x0c,
|
|
||||||
0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05,
|
|
||||||
0x05, 0x00,
|
|
||||||
0x04, 0x10 /* + hash */
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static u_char purpose_ind[] = {
|
static u_char purpose_ind[] = {
|
||||||
0x30, 0x0c,
|
0x30, 0x0c,
|
||||||
@ -774,6 +935,7 @@ int main(int argc, char **argv)
|
|||||||
0x30, 0x0c,
|
0x30, 0x0c,
|
||||||
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x16
|
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x16
|
||||||
};
|
};
|
||||||
|
|
||||||
static u_char msi_signature[] = {
|
static u_char msi_signature[] = {
|
||||||
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
|
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
|
||||||
};
|
};
|
||||||
@ -792,25 +954,51 @@ int main(int argc, char **argv)
|
|||||||
spcfile = keyfile = pkcs12file = infile = outfile = desc = url = NULL;
|
spcfile = keyfile = pkcs12file = infile = outfile = desc = url = NULL;
|
||||||
hash = outdata = NULL;
|
hash = outdata = NULL;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
if (!strcmp(argv[1], "sign")) {
|
||||||
|
cmd = CMD_SIGN;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
} else if (!strcmp(argv[1], "extract-signature")) {
|
||||||
|
cmd = CMD_EXTRACT;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
} else if (!strcmp(argv[1], "remove-signature")) {
|
||||||
|
cmd = CMD_REMOVE;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
} else if (!strcmp(argv[1], "verify")) {
|
||||||
|
cmd = CMD_VERIFY;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (argc--,argv++; argc >= 1; argc--,argv++) {
|
for (argc--,argv++; argc >= 1; argc--,argv++) {
|
||||||
if (!strcmp(*argv, "-spc")) {
|
if (!strcmp(*argv, "-in")) {
|
||||||
|
if (--argc < 1) usage(argv0);
|
||||||
|
infile = *(++argv);
|
||||||
|
} else if (!strcmp(*argv, "-out")) {
|
||||||
|
if (--argc < 1) usage(argv0);
|
||||||
|
outfile = *(++argv);
|
||||||
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-spc")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
spcfile = *(++argv);
|
spcfile = *(++argv);
|
||||||
} else if (!strcmp(*argv, "-key")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-key")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
keyfile = *(++argv);
|
keyfile = *(++argv);
|
||||||
} else if (!strcmp(*argv, "-pkcs12")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-pkcs12")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
pkcs12file = *(++argv);
|
pkcs12file = *(++argv);
|
||||||
} else if (!strcmp(*argv, "-pass")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-pass")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
pass = *(++argv);
|
pass = *(++argv);
|
||||||
} else if (!strcmp(*argv, "-comm")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-comm")) {
|
||||||
comm = 1;
|
comm = 1;
|
||||||
} else if (!strcmp(*argv, "-n")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-n")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
desc = *(++argv);
|
desc = *(++argv);
|
||||||
} else if (!strcmp(*argv, "-h")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-h")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
++argv;
|
++argv;
|
||||||
if (!strcmp(*argv, "md5")) {
|
if (!strcmp(*argv, "md5")) {
|
||||||
@ -822,20 +1010,14 @@ int main(int argc, char **argv)
|
|||||||
} else {
|
} else {
|
||||||
usage(argv0);
|
usage(argv0);
|
||||||
}
|
}
|
||||||
} else if (!strcmp(*argv, "-i")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-i")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
url = *(++argv);
|
url = *(++argv);
|
||||||
} else if (!strcmp(*argv, "-in")) {
|
|
||||||
if (--argc < 1) usage(argv0);
|
|
||||||
infile = *(++argv);
|
|
||||||
} else if (!strcmp(*argv, "-out")) {
|
|
||||||
if (--argc < 1) usage(argv0);
|
|
||||||
outfile = *(++argv);
|
|
||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
} else if (!strcmp(*argv, "-t")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-t")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
turl = *(++argv);
|
turl = *(++argv);
|
||||||
} else if (!strcmp(*argv, "-p")) {
|
} else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-p")) {
|
||||||
if (--argc < 1) usage(argv0);
|
if (--argc < 1) usage(argv0);
|
||||||
proxy = *(++argv);
|
proxy = *(++argv);
|
||||||
#endif
|
#endif
|
||||||
@ -876,36 +1058,57 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
if (jp != 0) usage(argv0); /* XXX */
|
if (jp != 0) usage(argv0); /* XXX */
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unknown option: %s\n", *argv);
|
failarg = *argv;
|
||||||
usage(argv0);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!infile || !outfile || !((spcfile && keyfile) || pkcs12file))
|
if (!infile && argc > 0) {
|
||||||
|
infile = *(argv++);
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd != CMD_VERIFY && (!outfile && argc > 0)) {
|
||||||
|
if (!strcmp(*argv, "-out")) {
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
if (argc > 0) {
|
||||||
|
outfile = *(argv++);
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 0 || !infile || (cmd != CMD_VERIFY && !outfile) || (cmd == CMD_SIGN && !((spcfile && keyfile) || pkcs12file))) {
|
||||||
|
if (failarg)
|
||||||
|
fprintf(stderr, "Unknown option: %s\n", failarg);
|
||||||
usage(argv0);
|
usage(argv0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Read certificate and key */
|
if (cmd == CMD_SIGN) {
|
||||||
if (pkcs12file != NULL) {
|
/* Read certificate and key */
|
||||||
if ((btmp = BIO_new_file(pkcs12file, "rb")) == NULL ||
|
if (pkcs12file != NULL) {
|
||||||
(p12 = d2i_PKCS12_bio(btmp, NULL)) == NULL)
|
if ((btmp = BIO_new_file(pkcs12file, "rb")) == NULL ||
|
||||||
DO_EXIT_1("Failed to read PKCS#12 file: %s\n", pkcs12file);
|
(p12 = d2i_PKCS12_bio(btmp, NULL)) == NULL)
|
||||||
BIO_free(btmp);
|
DO_EXIT_1("Failed to read PKCS#12 file: %s\n", pkcs12file);
|
||||||
if (!PKCS12_parse(p12, pass, &pkey, &cert, &certs))
|
BIO_free(btmp);
|
||||||
DO_EXIT_1("Failed to parse PKCS#12 file: %s (Wrong password?)\n", pkcs12file);
|
if (!PKCS12_parse(p12, pass, &pkey, &cert, &certs))
|
||||||
PKCS12_free(p12);
|
DO_EXIT_1("Failed to parse PKCS#12 file: %s (Wrong password?)\n", pkcs12file);
|
||||||
} else {
|
PKCS12_free(p12);
|
||||||
if ((btmp = BIO_new_file(spcfile, "rb")) == NULL ||
|
} else {
|
||||||
(p7 = d2i_PKCS7_bio(btmp, NULL)) == NULL)
|
if ((btmp = BIO_new_file(spcfile, "rb")) == NULL ||
|
||||||
DO_EXIT_1("Failed to read DER-encoded spc file: %s\n", spcfile);
|
(p7 = d2i_PKCS7_bio(btmp, NULL)) == NULL)
|
||||||
BIO_free(btmp);
|
DO_EXIT_1("Failed to read DER-encoded spc file: %s\n", spcfile);
|
||||||
|
BIO_free(btmp);
|
||||||
|
|
||||||
if ((btmp = BIO_new_file(keyfile, "rb")) == NULL ||
|
if ((btmp = BIO_new_file(keyfile, "rb")) == NULL ||
|
||||||
( (pkey = d2i_PrivateKey_bio(btmp, NULL)) == NULL &&
|
( (pkey = d2i_PrivateKey_bio(btmp, NULL)) == NULL &&
|
||||||
(pkey = PEM_read_bio_PrivateKey(btmp, NULL, NULL, pass)) == NULL &&
|
(pkey = PEM_read_bio_PrivateKey(btmp, NULL, NULL, pass)) == NULL &&
|
||||||
(pkey = PEM_read_bio_PrivateKey(btmp, NULL, NULL, NULL)) == NULL))
|
(pkey = PEM_read_bio_PrivateKey(btmp, NULL, NULL, NULL)) == NULL))
|
||||||
DO_EXIT_1("Failed to read private key file: %s (Wrong password?)\n", keyfile);
|
DO_EXIT_1("Failed to read private key file: %s (Wrong password?)\n", keyfile);
|
||||||
BIO_free(btmp);
|
BIO_free(btmp);
|
||||||
certs = p7->d.sign->cert;
|
certs = p7->d.sign->cert;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if indata is cab or pe */
|
/* Check if indata is cab or pe */
|
||||||
@ -920,7 +1123,7 @@ int main(int argc, char **argv)
|
|||||||
if ((fd = open(infile, O_RDONLY)) < 0)
|
if ((fd = open(infile, O_RDONLY)) < 0)
|
||||||
DO_EXIT_1("Failed to open file: %s\n", infile);
|
DO_EXIT_1("Failed to open file: %s\n", infile);
|
||||||
|
|
||||||
indata = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
indata = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
if (indata == NULL)
|
if (indata == NULL)
|
||||||
DO_EXIT_1("Failed to open file: %s\n", infile);
|
DO_EXIT_1("Failed to open file: %s\n", infile);
|
||||||
|
|
||||||
@ -933,6 +1136,9 @@ int main(int argc, char **argv)
|
|||||||
else
|
else
|
||||||
DO_EXIT_1("Unrecognized file type: %s\n", infile);
|
DO_EXIT_1("Unrecognized file type: %s\n", infile);
|
||||||
|
|
||||||
|
if (cmd != CMD_SIGN && type != FILE_TYPE_PE)
|
||||||
|
DO_EXIT_1("Command is not supported for non-PE files: %s\n", infile);
|
||||||
|
|
||||||
hash = BIO_new(BIO_f_md());
|
hash = BIO_new(BIO_f_md());
|
||||||
BIO_set_md(hash, md);
|
BIO_set_md(hash, md);
|
||||||
|
|
||||||
@ -1010,12 +1216,13 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type == FILE_TYPE_CAB || type == FILE_TYPE_PE) {
|
if (type == FILE_TYPE_CAB || type == FILE_TYPE_PE) {
|
||||||
/* Create outdata file */
|
if (cmd != CMD_VERIFY) {
|
||||||
outdata = BIO_new_file(outfile, "w+b");
|
/* Create outdata file */
|
||||||
if (outdata == NULL)
|
outdata = BIO_new_file(outfile, "w+b");
|
||||||
DO_EXIT_1("Failed to create file: %s\n", outfile);
|
if (outdata == NULL)
|
||||||
|
DO_EXIT_1("Failed to create file: %s\n", outfile);
|
||||||
BIO_push(hash, outdata);
|
BIO_push(hash, outdata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == FILE_TYPE_CAB) {
|
if (type == FILE_TYPE_CAB) {
|
||||||
@ -1081,7 +1288,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
nrvas = GET_UINT32_LE(indata + peheader + 116 + pe32plus*16);
|
nrvas = GET_UINT32_LE(indata + peheader + 116 + pe32plus*16);
|
||||||
if (nrvas < 5)
|
if (nrvas < 5)
|
||||||
DO_EXIT_1("Can not sign PE files without certificate table resource: %s\n", infile);
|
DO_EXIT_1("Can not handle PE files without certificate table resource: %s\n", infile);
|
||||||
|
|
||||||
sigpos = GET_UINT32_LE(indata + peheader + 152 + pe32plus*16);
|
sigpos = GET_UINT32_LE(indata + peheader + 152 + pe32plus*16);
|
||||||
siglen = GET_UINT32_LE(indata + peheader + 152 + pe32plus*16 + 4);
|
siglen = GET_UINT32_LE(indata + peheader + 152 + pe32plus*16 + 4);
|
||||||
@ -1091,6 +1298,21 @@ int main(int argc, char **argv)
|
|||||||
if (sigpos > 0 && sigpos + siglen != st.st_size)
|
if (sigpos > 0 && sigpos + siglen != st.st_size)
|
||||||
DO_EXIT_1("Corrupt PE file - current signature not at end of file: %s\n", infile);
|
DO_EXIT_1("Corrupt PE file - current signature not at end of file: %s\n", infile);
|
||||||
|
|
||||||
|
if ((cmd == CMD_REMOVE || cmd == CMD_EXTRACT) && sigpos == 0)
|
||||||
|
DO_EXIT_1("PE file does not have any signature: %s\n", infile);
|
||||||
|
|
||||||
|
if (cmd == CMD_EXTRACT) {
|
||||||
|
/* A lil' bit of ugliness. Reset stream, write signature and skip forward */
|
||||||
|
BIO_reset(outdata);
|
||||||
|
BIO_write(outdata, indata + sigpos, siglen);
|
||||||
|
goto skip_signing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == CMD_VERIFY) {
|
||||||
|
ret = verify_pe_file(indata, peheader, pe32plus, sigpos ? sigpos : fileend, siglen);
|
||||||
|
goto skip_signing;
|
||||||
|
}
|
||||||
|
|
||||||
if (sigpos > 0) {
|
if (sigpos > 0) {
|
||||||
/* Strip current signature */
|
/* Strip current signature */
|
||||||
fileend = sigpos;
|
fileend = sigpos;
|
||||||
@ -1103,7 +1325,8 @@ int main(int argc, char **argv)
|
|||||||
i += 4;
|
i += 4;
|
||||||
BIO_write(hash, indata + i, 60+pe32plus*16);
|
BIO_write(hash, indata + i, 60+pe32plus*16);
|
||||||
i += 60+pe32plus*16;
|
i += 60+pe32plus*16;
|
||||||
BIO_write(outdata, indata + i, 8);
|
memset(buf, 0, 8);
|
||||||
|
BIO_write(outdata, buf, 8); /* zero out sigtable offset + pos */
|
||||||
i += 8;
|
i += 8;
|
||||||
|
|
||||||
BIO_write(hash, indata + i, fileend - i);
|
BIO_write(hash, indata + i, fileend - i);
|
||||||
@ -1116,6 +1339,10 @@ int main(int argc, char **argv)
|
|||||||
fileend += len;
|
fileend += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd != CMD_SIGN)
|
||||||
|
goto skip_signing;
|
||||||
|
|
||||||
sig = PKCS7_new();
|
sig = PKCS7_new();
|
||||||
PKCS7_set_type(sig, NID_pkcs7_signed);
|
PKCS7_set_type(sig, NID_pkcs7_signed);
|
||||||
|
|
||||||
@ -1214,7 +1441,8 @@ int main(int argc, char **argv)
|
|||||||
len -= EVP_MD_size(md);
|
len -= EVP_MD_size(md);
|
||||||
memcpy(buf, p, len);
|
memcpy(buf, p, len);
|
||||||
i = BIO_gets(hash, buf + len, EVP_MAX_MD_SIZE);
|
i = BIO_gets(hash, buf + len, EVP_MAX_MD_SIZE);
|
||||||
BIO_write(sigdata, buf+2, len-2+i);
|
int seqhdrlen = der_seq_hdr_len(buf, len);
|
||||||
|
BIO_write(sigdata, buf+seqhdrlen, len-seqhdrlen+i);
|
||||||
|
|
||||||
if (!PKCS7_dataFinal(sig, sigdata))
|
if (!PKCS7_dataFinal(sig, sigdata))
|
||||||
DO_EXIT_0("Signing failed(PKCS7_dataFinal)\n");
|
DO_EXIT_0("Signing failed(PKCS7_dataFinal)\n");
|
||||||
@ -1248,12 +1476,10 @@ 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 cert_rev_and_type[] = {
|
|
||||||
0x00, 0x02, 0x02, 0x00
|
|
||||||
};
|
|
||||||
PUT_UINT32_LE(len+8+padlen, buf);
|
PUT_UINT32_LE(len+8+padlen, buf);
|
||||||
BIO_write(outdata, buf, 4);
|
PUT_UINT16_LE(WIN_CERT_REVISION_2, buf + 4);
|
||||||
BIO_write(outdata, cert_rev_and_type, sizeof(cert_rev_and_type));
|
PUT_UINT16_LE(WIN_CERT_TYPE_PKCS_SIGNED_DATA, buf + 6);
|
||||||
|
BIO_write(outdata, buf, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == FILE_TYPE_PE || type == FILE_TYPE_CAB) {
|
if (type == FILE_TYPE_PE || type == FILE_TYPE_CAB) {
|
||||||
@ -1275,13 +1501,19 @@ int main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skip_signing:
|
||||||
|
|
||||||
if (type == FILE_TYPE_PE) {
|
if (type == FILE_TYPE_PE) {
|
||||||
(void)BIO_seek(outdata, peheader+152+pe32plus*16);
|
if (cmd == CMD_SIGN) {
|
||||||
PUT_UINT32_LE(fileend, buf);
|
/* Update signature position and size */
|
||||||
BIO_write(outdata, buf, 4);
|
(void)BIO_seek(outdata, peheader+152+pe32plus*16);
|
||||||
PUT_UINT32_LE(len+8+padlen, buf);
|
PUT_UINT32_LE(fileend, buf); /* Previous file end = signature table start */
|
||||||
BIO_write(outdata, buf, 4);
|
BIO_write(outdata, buf, 4);
|
||||||
recalc_pe_checksum(outdata, peheader);
|
PUT_UINT32_LE(len+8+padlen, buf);
|
||||||
|
BIO_write(outdata, buf, 4);
|
||||||
|
}
|
||||||
|
if (cmd == CMD_SIGN || cmd == CMD_REMOVE)
|
||||||
|
recalc_pe_checksum(outdata, peheader);
|
||||||
} else if (type == FILE_TYPE_CAB) {
|
} else if (type == FILE_TYPE_CAB) {
|
||||||
(void)BIO_seek(outdata, 0x30);
|
(void)BIO_seek(outdata, 0x30);
|
||||||
PUT_UINT32_LE(len+padlen, buf);
|
PUT_UINT32_LE(len+padlen, buf);
|
||||||
@ -1291,9 +1523,9 @@ int main(int argc, char **argv)
|
|||||||
BIO_free_all(hash);
|
BIO_free_all(hash);
|
||||||
hash = outdata = NULL;
|
hash = outdata = NULL;
|
||||||
|
|
||||||
printf("Succeeded\n");
|
printf(ret ? "Failed\n" : "Succeeded\n");
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
|
|
||||||
err_cleanup:
|
err_cleanup:
|
||||||
ERR_print_errors_fp(stderr);
|
ERR_print_errors_fp(stderr);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user