From c784e8b9bf3e93823757c3cb48dfeebb4b02a1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sun, 12 Mar 2017 23:00:12 +0100 Subject: [PATCH 1/3] Make code work with OpenSSL 1.1. Changes in consist of: - Use EVP_MD_CTX_new/free API instead of on-stack allocation - Remove some M_ prefixes like for ASN1_IA5STRING_new - Remove pagehash functionality because it is useless to me and fixing it would be a pain. Would require declaring a few ASN_SEQUENCES and use that to get the required i2d functions from what I could find out. - Add dummy arguments to OBJ_create calls, since they now crash because NULL pointers are no longer handled (who changes API that way?!). Note that for me everything worked fine for me without these. so test-cases where they are needed would be very useful... --- osslsigncode.c | 176 ++++++++++++++----------------------------------- 1 file changed, 48 insertions(+), 128 deletions(-) diff --git a/osslsigncode.c b/osslsigncode.c index 32e37c8..241935f 100644 --- a/osslsigncode.c +++ b/osslsigncode.c @@ -450,16 +450,16 @@ static SpcSpOpusInfo* createOpus(const char *desc, const char *url) if (desc) { info->programName = SpcString_new(); info->programName->type = 1; - info->programName->value.ascii = M_ASN1_IA5STRING_new(); - ASN1_STRING_set((ASN1_STRING *)info->programName->value.ascii, + info->programName->value.ascii = ASN1_IA5STRING_new(); + ASN1_STRING_set(info->programName->value.ascii, (const unsigned char*)desc, strlen(desc)); } if (url) { info->moreInfo = SpcLink_new(); info->moreInfo->type = 0; - info->moreInfo->value.url = M_ASN1_IA5STRING_new(); - ASN1_STRING_set((ASN1_STRING *)info->moreInfo->value.url, + info->moreInfo->value.url = ASN1_IA5STRING_new(); + ASN1_STRING_set(info->moreInfo->value.url, (const unsigned char*)url, strlen(url)); } @@ -609,19 +609,20 @@ static int add_timestamp(PKCS7 *sig, char *url, char *proxy, int rfc3161, const if (rfc3161) { unsigned char mdbuf[EVP_MAX_MD_SIZE]; - EVP_MD_CTX mdctx; + EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); - EVP_MD_CTX_init(&mdctx); - EVP_DigestInit(&mdctx, md); - EVP_DigestUpdate(&mdctx, si->enc_digest->data, si->enc_digest->length); - EVP_DigestFinal(&mdctx, mdbuf, NULL); + EVP_DigestInit(mdctx, md); + EVP_DigestUpdate(mdctx, si->enc_digest->data, si->enc_digest->length); + EVP_DigestFinal(mdctx, mdbuf, NULL); + EVP_MD_CTX_free(mdctx); + mdctx = NULL; TimeStampReq *req = TimeStampReq_new(); ASN1_INTEGER_set(req->version, 1); req->messageImprint->digestAlgorithm->algorithm = OBJ_nid2obj(EVP_MD_nid(md)); req->messageImprint->digestAlgorithm->parameters = ASN1_TYPE_new(); req->messageImprint->digestAlgorithm->parameters->type = V_ASN1_NULL; - M_ASN1_OCTET_STRING_set(req->messageImprint->digest, mdbuf, EVP_MD_size(md)); + ASN1_OCTET_STRING_set(req->messageImprint->digest, mdbuf, EVP_MD_size(md)); req->certReq = (void*)0x1; len = i2d_TimeStampReq(req, NULL); @@ -815,7 +816,7 @@ static void cleanup_lib_state(void) EVP_cleanup(); CONF_modules_free(); CRYPTO_cleanup_all_ex_data(); -#if OPENSSL_VERSION_NUMBER > 0x10000000 +#if OPENSSL_VERSION_NUMBER > 0x10000000 && OPENSSL_VERSION_NUMBER < 0x10100000 ERR_remove_thread_state(NULL); #endif ERR_free_strings(); @@ -921,83 +922,8 @@ static const unsigned char classid_page_hash[] = { 0xAE, 0x05, 0xA2, 0x17, 0xDA, 0x8E, 0x60, 0xD6 }; -static unsigned char *calc_page_hash(char *indata, unsigned int peheader, int pe32plus, - unsigned int sigpos, int phtype, unsigned int *phlen); - -DECLARE_STACK_OF(ASN1_OCTET_STRING) -#ifndef sk_ASN1_OCTET_STRING_new_null -#define sk_ASN1_OCTET_STRING_new_null() SKM_sk_new_null(ASN1_OCTET_STRING) -#define sk_ASN1_OCTET_STRING_free(st) SKM_sk_free(ASN1_OCTET_STRING, (st)) -#define sk_ASN1_OCTET_STRING_push(st, val) SKM_sk_push(ASN1_OCTET_STRING, (st), (val)) -#define i2d_ASN1_SET_OF_ASN1_OCTET_STRING(st, pp, i2d_func, ex_tag, ex_class, is_set) \ - SKM_ASN1_SET_OF_i2d(ASN1_OCTET_STRING, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) -#endif - -DECLARE_STACK_OF(SpcAttributeTypeAndOptionalValue) -#ifndef sk_SpcAttributeTypeAndOptionalValue_new_null -#define sk_SpcAttributeTypeAndOptionalValue_new_null() SKM_sk_new_null(SpcAttributeTypeAndOptionalValue) -#define sk_SpcAttributeTypeAndOptionalValue_free(st) SKM_sk_free(SpcAttributeTypeAndOptionalValue, (st)) -#define sk_SpcAttributeTypeAndOptionalValue_push(st, val) SKM_sk_push(SpcAttributeTypeAndOptionalValue, (st), (val)) -#define i2d_SpcAttributeTypeAndOptionalValue(st, pp, i2d_func, ex_tag, ex_class, is_set) \ - SKM_ASN1_SET_OF_i2d(SpcAttributeTypeAndOptionalValue, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) -#endif - -static SpcLink *get_page_hash_link(int phtype, char *indata, unsigned int peheader, int pe32plus, unsigned int sigpos) -{ - unsigned int phlen; - unsigned char *ph = calc_page_hash(indata, peheader, pe32plus, sigpos, phtype, &phlen); - if (!ph) { - fprintf(stderr, "Failed to calculate page hash\n"); - exit(-1); - } - - ASN1_OCTET_STRING *ostr = M_ASN1_OCTET_STRING_new(); - M_ASN1_OCTET_STRING_set(ostr, ph, phlen); - free(ph); - - STACK_OF(ASN1_OCTET_STRING) *oset = sk_ASN1_OCTET_STRING_new_null(); - sk_ASN1_OCTET_STRING_push(oset, ostr); - unsigned char *p, *tmp; - unsigned int l; - l = i2d_ASN1_SET_OF_ASN1_OCTET_STRING(oset, NULL, i2d_ASN1_OCTET_STRING, - V_ASN1_SET, V_ASN1_UNIVERSAL, IS_SET); - tmp = p = OPENSSL_malloc(l); - i2d_ASN1_SET_OF_ASN1_OCTET_STRING(oset, &tmp, i2d_ASN1_OCTET_STRING, - V_ASN1_SET, V_ASN1_UNIVERSAL, IS_SET); - ASN1_OCTET_STRING_free(ostr); - sk_ASN1_OCTET_STRING_free(oset); - - SpcAttributeTypeAndOptionalValue *aval = SpcAttributeTypeAndOptionalValue_new(); - aval->type = OBJ_txt2obj((phtype == NID_sha1) ? SPC_PE_IMAGE_PAGE_HASHES_V1 : SPC_PE_IMAGE_PAGE_HASHES_V2, 1); - aval->value = ASN1_TYPE_new(); - aval->value->type = V_ASN1_SET; - aval->value->value.set = ASN1_STRING_new(); - ASN1_STRING_set(aval->value->value.set, p, l); - OPENSSL_free(p); - - STACK_OF(SpcAttributeTypeAndOptionalValue) *aset = sk_SpcAttributeTypeAndOptionalValue_new_null(); - sk_SpcAttributeTypeAndOptionalValue_push(aset, aval); - l = i2d_SpcAttributeTypeAndOptionalValue(aset, NULL, i2d_SpcAttributeTypeAndOptionalValue, - V_ASN1_SET, V_ASN1_UNIVERSAL, IS_SET); - tmp = p = OPENSSL_malloc(l); - l = i2d_SpcAttributeTypeAndOptionalValue(aset, &tmp, i2d_SpcAttributeTypeAndOptionalValue, - V_ASN1_SET, V_ASN1_UNIVERSAL, IS_SET); - sk_SpcAttributeTypeAndOptionalValue_free(aset); - SpcAttributeTypeAndOptionalValue_free(aval); - - SpcSerializedObject *so = SpcSerializedObject_new(); - M_ASN1_OCTET_STRING_set(so->classId, classid_page_hash, sizeof(classid_page_hash)); - M_ASN1_OCTET_STRING_set(so->serializedData, p, l); - OPENSSL_free(p); - - SpcLink *link = SpcLink_new(); - link->type = 1; - link->value.moniker = so; - return link; -} - static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, file_type_t type, - int pagehash, char *indata, unsigned int peheader, int pe32plus, + char *indata, unsigned int peheader, int pe32plus, unsigned int sigpos) { static const unsigned char msistr[] = { @@ -1024,14 +950,7 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, fi } else if (type == FILE_TYPE_PE) { SpcPeImageData *pid = SpcPeImageData_new(); ASN1_BIT_STRING_set(pid->flags, (unsigned char*)"0", 0); - if (pagehash) { - int phtype = NID_sha1; - if (EVP_MD_size(md) > EVP_MD_size(EVP_sha1())) - phtype = NID_sha256; - pid->file = get_page_hash_link(phtype, indata, peheader, pe32plus, sigpos); - } else { - pid->file = get_obsolete_link(); - } + pid->file = get_obsolete_link(); l = i2d_SpcPeImageData(pid, NULL); p = OPENSSL_malloc(l); i2d_SpcPeImageData(pid, &p); @@ -1046,7 +965,7 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, fi ASN1_INTEGER_set(si->d, 0); ASN1_INTEGER_set(si->e, 0); ASN1_INTEGER_set(si->f, 0); - M_ASN1_OCTET_STRING_set(si->string, msistr, sizeof(msistr)); + ASN1_OCTET_STRING_set(si->string, msistr, sizeof(msistr)); l = i2d_SpcSipInfo(si, NULL); p = OPENSSL_malloc(l); i2d_SpcSipInfo(si, &p); @@ -1068,7 +987,7 @@ static void get_indirect_data_blob(u_char **blob, int *len, const EVP_MD *md, fi hashlen = EVP_MD_size(md); hash = OPENSSL_malloc(hashlen); memset(hash, 0, hashlen); - M_ASN1_OCTET_STRING_set(idc->messageDigest->digest, hash, hashlen); + ASN1_OCTET_STRING_set(idc->messageDigest->digest, hash, hashlen); OPENSSL_free(hash); *len = i2d_SpcIndirectDataContent(idc, NULL); @@ -1923,19 +1842,18 @@ static void calc_pe_digest(BIO *bio, const EVP_MD *md, unsigned char *mdbuf, unsigned int peheader, int pe32plus, unsigned int fileend) { static unsigned char bfb[16*1024*1024]; - EVP_MD_CTX mdctx; + EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); - EVP_MD_CTX_init(&mdctx); - EVP_DigestInit(&mdctx, md); + EVP_DigestInit(mdctx, md); memset(mdbuf, 0, EVP_MAX_MD_SIZE); (void)BIO_seek(bio, 0); BIO_read(bio, bfb, peheader + 88); - EVP_DigestUpdate(&mdctx, 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); + EVP_DigestUpdate(mdctx, bfb, 60+pe32plus*16); BIO_read(bio, bfb, 8); unsigned int n = peheader + 88 + 4 + 60+pe32plus*16 + 8; @@ -1946,11 +1864,12 @@ static void calc_pe_digest(BIO *bio, const EVP_MD *md, unsigned char *mdbuf, int l = BIO_read(bio, bfb, want); if (l <= 0) break; - EVP_DigestUpdate(&mdctx, bfb, l); + EVP_DigestUpdate(mdctx, bfb, l); n += l; } - EVP_DigestFinal(&mdctx, mdbuf, NULL); + EVP_DigestFinal(mdctx, mdbuf, NULL); + EVP_MD_CTX_free(mdctx); } @@ -2019,16 +1938,15 @@ static unsigned char *calc_page_hash(char *indata, unsigned int peheader, int pe int phlen = pphlen * (3 + nsections + sigpos / pagesize); unsigned char *res = malloc(phlen); unsigned char *zeroes = calloc(pagesize, 1); - EVP_MD_CTX mdctx; - - EVP_MD_CTX_init(&mdctx); - EVP_DigestInit(&mdctx, md); - EVP_DigestUpdate(&mdctx, indata, peheader + 88); - EVP_DigestUpdate(&mdctx, indata + peheader + 92, 60 + pe32plus*16); - EVP_DigestUpdate(&mdctx, indata + peheader + 160 + pe32plus*16, hdrsize - (peheader + 160 + pe32plus*16)); - EVP_DigestUpdate(&mdctx, zeroes, pagesize - hdrsize); + EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); + + EVP_DigestInit(mdctx, md); + EVP_DigestUpdate(mdctx, indata, peheader + 88); + EVP_DigestUpdate(mdctx, indata + peheader + 92, 60 + pe32plus*16); + EVP_DigestUpdate(mdctx, indata + peheader + 160 + pe32plus*16, hdrsize - (peheader + 160 + pe32plus*16)); + EVP_DigestUpdate(mdctx, zeroes, pagesize - hdrsize); memset(res, 0, 4); - EVP_DigestFinal(&mdctx, res + 4, NULL); + EVP_DigestFinal(mdctx, res + 4, NULL); unsigned short sizeofopthdr = GET_UINT16_LE(indata + peheader + 20); char *sections = indata + peheader + 24 + sizeofopthdr; @@ -2040,18 +1958,20 @@ static unsigned char *calc_page_hash(char *indata, unsigned int peheader, int pe unsigned int l; for (l=0; l < rs; l+=pagesize, pi++) { PUT_UINT32_LE(ro + l, res + pi*pphlen); - EVP_DigestInit(&mdctx, md); + EVP_DigestInit(mdctx, md); if (rs - l < pagesize) { - EVP_DigestUpdate(&mdctx, indata + ro + l, rs - l); - EVP_DigestUpdate(&mdctx, zeroes, pagesize - (rs - l)); + EVP_DigestUpdate(mdctx, indata + ro + l, rs - l); + EVP_DigestUpdate(mdctx, zeroes, pagesize - (rs - l)); } else { - EVP_DigestUpdate(&mdctx, indata + ro + l, pagesize); + EVP_DigestUpdate(mdctx, indata + ro + l, pagesize); } - EVP_DigestFinal(&mdctx, res + pi*pphlen + 4, NULL); + EVP_DigestFinal(mdctx, res + pi*pphlen + 4, NULL); } lastpos = ro + rs; sections += 40; } + EVP_MD_CTX_free(mdctx); + mdctx = NULL; PUT_UINT32_LE(lastpos, res + pi*pphlen); memset(res + pi*pphlen + 4, 0, EVP_MD_size(md)); pi++; @@ -2413,7 +2333,7 @@ int main(int argc, char **argv) int nturl = 0, ntsurl = 0; int addBlob = 0; u_char *p = NULL; - int ret = 0, i, len = 0, jp = -1, pe32plus = 0, comm = 0, pagehash = 0; + int ret = 0, i, len = 0, jp = -1, pe32plus = 0, comm = 0; unsigned int tmp, peheader = 0, padlen = 0; off_t filesize, fileend, sigfilesize, sigfileend, outdatasize; file_type_t type; @@ -2448,12 +2368,14 @@ int main(int argc, char **argv) ERR_load_crypto_strings(); OPENSSL_add_all_algorithms_conf(); - /* create some MS Authenticode OIDS we need later on */ - if (!OBJ_create(SPC_STATEMENT_TYPE_OBJID, NULL, NULL) || - !OBJ_create(SPC_MS_JAVA_SOMETHING, NULL, NULL) || - !OBJ_create(SPC_SP_OPUS_INFO_OBJID, NULL, NULL) || - !OBJ_create(SPC_NESTED_SIGNATURE_OBJID, NULL, NULL)) - DO_EXIT_0("Failed to add objects\n"); + /* create some MS Authenticode OIDS we have to use via PKCS7 functions later on and thus + * need NIDs. Short and long names are fake, since I do not know the + * proper values but OpenSSL no longer supports NULL for them. */ + if (!OBJ_create(SPC_STATEMENT_TYPE_OBJID, "SPC_STATEMENT_TYPE_OBJID", "SPC_STATEMENT_TYPE_OBJID") || + !OBJ_create(SPC_MS_JAVA_SOMETHING, "SPC_MS_JAVA_SOMETHING", "SPC_MS_JAVA_SOMETHING") || + !OBJ_create(SPC_SP_OPUS_INFO_OBJID, "SPC_SP_OPUS_INFO_OBJID", "SPC_SP_OPUS_INFO_OBJID") || + !OBJ_create(SPC_NESTED_SIGNATURE_OBJID, "SPC_NESTED_SIGNATURE_OBJID", "SPC_NESTED_SIGNATURE_OBJID")) + DO_EXIT_0("Failed to add objects\n"); md = EVP_sha1(); @@ -2531,8 +2453,6 @@ int main(int argc, char **argv) readpass = *(++argv); } else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-comm")) { comm = 1; - } else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-ph")) { - pagehash = 1; } else if ((cmd == CMD_SIGN) && !strcmp(*argv, "-n")) { if (--argc < 1) usage(argv0); desc = *(++argv); @@ -3243,7 +3163,7 @@ int main(int argc, char **argv) p7x = NULL; } - get_indirect_data_blob(&p, &len, md, type, pagehash, indata, peheader, pe32plus, fileend); + get_indirect_data_blob(&p, &len, md, type, indata, peheader, pe32plus, fileend); len -= EVP_MD_size(md); memcpy(buf, p, len); OPENSSL_free(p); From 39a4a5032f07a99f497322ce002e417e5c03c983 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Tue, 7 Aug 2018 21:44:35 +0200 Subject: [PATCH 2/3] Add some documentation to README - which packages to install (on Ubuntu-18.04) - how to sign with HSM device --- README | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/README b/README index a404bee..0b7fcad 100644 --- a/README +++ b/README @@ -31,8 +31,15 @@ removal and extraction. == INSTALLATION -The usual way: +Make sure dependent libraries are installed: + * On Ubuntu-18.04: + sudo apt install libssl-dev autoconf build-essential automake libtool libcurl4-openssl-dev libengine-pkcs11-openssl1.1 + +Then download, build and install: + + git clone https://github.com/larskanis/osslsigncode + sh autogen.sh ./configure make make install @@ -41,7 +48,8 @@ The usual way: == USAGE Before you can sign a file you need a Software Publishing -Certificate (spc) and a corresponding private key. +Certificate (spc) and a corresponding private key as file, on +smart card or a HSM. This article provides a good starting point as to how to do the signing with the Microsoft signtool.exe: @@ -52,6 +60,9 @@ To sign with osslsigncode you need the certificate file mentioned in the article above, in SPC or PEM format, and you will also need the private key which must be a key file in DER or PEM format, or if osslsigncode was compiled against OpenSSL 1.0.0 or later, in PVK format. +Alternatively this version of osslsigncode supports private keys stored +on high security modules (HSM) through OpenSSL engines. + To sign a PE or MSI file you can now do: @@ -80,6 +91,32 @@ You can use a certificate and key stored in a PKCS#12 container: -n "Your Application" -i http://www.yourwebsite.com/ \ -in yourapp.exe -out yourapp-signed.exe +To use a key stored on a HSM or a smart card, you need a OpenSSL engine +compatible shared library for operations on the private key. +Since most HSMs don't support the OpenSSL engine interface directly +but the more common standard PKCS#11, it's necessary to use a bridge +called engine-pkcs11. It can be installed like: + + sudo apt install libengine-pkcs11-openssl1.1 + +Furthermore you can make use the pkcs11 library of the OpenSC project, +which is compatible to many smart cards. It can be installed like: + + sudo apt install opensc + +To sign a PE file with private key stored on smart card and +interactive prompt for the PIN code: + + osslsigncode sign -certs -askpass \ + -pkcs11engine /usr/lib/x86_64-linux-gnu/engines-1.1/libpkcs11.so \ + -pkcs11module /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so \ + -in yourapp.exe -out yourapp-signed.exe + +The certificate has to be provided as a file. It is currently not +supported to read the certificate from the smard card directly. +Some smart card vendors provide their own PKCS#11 library, which can be +used alternatively instead of opensc-pkcs11.so. + To sign a CAB file containing java class files: osslsigncode sign -certs -key \ From 64cec15c3359039e22fabe7b28bf7ad8804c1603 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Sat, 11 Feb 2023 11:07:18 +0100 Subject: [PATCH 3/3] Update README for Ubuntu-22.04+ --- README | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README b/README index 0b7fcad..b1e64e3 100644 --- a/README +++ b/README @@ -33,8 +33,8 @@ removal and extraction. Make sure dependent libraries are installed: - * On Ubuntu-18.04: - sudo apt install libssl-dev autoconf build-essential automake libtool libcurl4-openssl-dev libengine-pkcs11-openssl1.1 + * On Ubuntu-18.04 to 22.10: + sudo apt install libssl-dev autoconf build-essential automake libtool libcurl4-openssl-dev libengine-pkcs11-openssl Then download, build and install: @@ -58,8 +58,7 @@ to do the signing with the Microsoft signtool.exe: To sign with osslsigncode you need the certificate file mentioned in the article above, in SPC or PEM format, and you will also need the private -key which must be a key file in DER or PEM format, or if osslsigncode was -compiled against OpenSSL 1.0.0 or later, in PVK format. +key which must be a key file in DER, PEM format or PVK format. Alternatively this version of osslsigncode supports private keys stored on high security modules (HSM) through OpenSSL engines. @@ -97,7 +96,7 @@ Since most HSMs don't support the OpenSSL engine interface directly but the more common standard PKCS#11, it's necessary to use a bridge called engine-pkcs11. It can be installed like: - sudo apt install libengine-pkcs11-openssl1.1 + sudo apt install libengine-pkcs11-openssl Furthermore you can make use the pkcs11 library of the OpenSC project, which is compatible to many smart cards. It can be installed like: @@ -108,10 +107,12 @@ To sign a PE file with private key stored on smart card and interactive prompt for the PIN code: osslsigncode sign -certs -askpass \ - -pkcs11engine /usr/lib/x86_64-linux-gnu/engines-1.1/libpkcs11.so \ + -pkcs11engine /usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so \ -pkcs11module /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so \ -in yourapp.exe -out yourapp-signed.exe +Use `/usr/lib/x86_64-linux-gnu/engines-1.1/libpkcs11.so` on a OpenSSL-1.1 +based distribution instead. The certificate has to be provided as a file. It is currently not supported to read the certificate from the smard card directly. Some smart card vendors provide their own PKCS#11 library, which can be