Signing Windows application on Linux-based distros Signing Windows application on Linux-based distros windows windows

Signing Windows application on Linux-based distros


You can try osslsigncode

To sign an EXE or MSI file you can now do:

osslsigncode sign -certs <cert-file> -key <der-key-file> \        -n "Your Application" -i http://www.yourwebsite.com/ \        -in yourapp.exe -out yourapp-signed.exe

or if you are using a PEM or PVK key file with a password togetherwith a PEM certificate:

osslsigncode sign -certs <cert-file> \        -key <key-file> -pass <key-password> \        -n "Your Application" -i http://www.yourwebsite.com/ \        -in yourapp.exe -out yourapp-signed.exe

or if you want to add a timestamp as well:

osslsigncode sign -certs <cert-file> -key <key-file> \        -n "Your Application" -i http://www.yourwebsite.com/ \        -t http://timestamp.verisign.com/scripts/timstamp.dll \        -in yourapp.exe -out yourapp-signed.exe

You can use a certificate and key stored in a PKCS#12 container:

osslsigncode sign -pkcs12 <pkcs12-file> -pass <pkcs12-password> \        -n "Your Application" -i http://www.yourwebsite.com/ \        -in yourapp.exe -out yourapp-signed.exe

To sign a CAB file containing java class files:

osslsigncode sign -certs <cert-file> -key <key-file> \        -n "Your Application" -i http://www.yourwebsite.com/ \        -jp low \        -in yourapp.cab -out yourapp-signed.cab


It's actually quite straight forward to do using Mono's signtool; the tricky part (described in more detail in the linked Mozilla article) is copying the certificate in the correct format from Windows to Linux.

Converting the Windows PFX certificate file to PVK and SPC files, only needs to be done once when copying the certificate from Windows to Linux;

openssl pkcs12 -in authenticode.pfx -nocerts -nodes -out key.pemopenssl rsa -in key.pem -outform PVK -pvk-strong -out authenticode.pvkopenssl pkcs12 -in authenticode.pfx -nokeys -nodes -out cert.pemopenssl crl2pkcs7 -nocrl -certfile cert.pem -outform DER -out authenticode.spc

Actually signing the exe is straight forward;

signcode \ -spc authenticode.spc \ -v authenticode.pvk \ -a sha1 -$ commercial \ -n My\ Application \ -i http://www.example.com/ \ -t http://timestamp.digicert.com/scripts/timstamp.dll \ -tr 10 \ MyApp.exe


If you want to do that programmatically in runtime you can usee Jsign tool. Especially it could be quite helpful when you generate self-executable archive on the backend by request signing it after. And you do that using Java/Kotlin obviously (name of the tool is suggesting). Here is API provided from the official site:

Simply add this dependency to the project:

    <dependency>      <groupId>net.jsign</groupId>      <artifactId>jsign-core</artifactId>      <version>3.1</version>    </dependency> 

and then use the AuthenticodeSigner class like this:

 KeyStore keystore = KeyStoreUtils.load(newFile("keystore.p12"), "PKCS12", "password", null); AuthenticodeSigner signer = new AuthenticodeSigner(keystore, "test", "secret");  signer.withProgramName("My Application")       .withProgramURL("http://www.example.com")       .withTimestamping(true)       .withTimestampingAuthority("http://timestamp.comodoca.com/authenticode"); Signable file = Signable.of(new File("application.exe"));  signer.sign(file); 

See the Javadoc for more details about the API.

Besides signing via Java KeyStore AuthenticodeSigner has (Certificate, PrivateKey) constructor and you can freely use it like I did in my "Spring on Kotlin" backend:

    @Bean    fun certsChain(): Array<Certificate> {        val fact: CertificateFactory = CertificateFactory.getInstance("X.509")        val `is` = ResourceUtil.getResourceFileAsInputStream("cert/certificate.pem")        val cer: X509Certificate = fact.generateCertificate(`is`) as X509Certificate        return arrayOf(cer)    }    @Bean    fun privateKey(): PrivateKey {        var key = ResourceUtil.getResourceFileAsString("cert/privateKey.pem")        key = key.replace("-----BEGIN PRIVATE KEY-----", "")        key = key.replace("\n", "")        key = key.replace("-----END PRIVATE KEY-----", "")        val encoded = Base64.getDecoder().decode(key)        val kf = KeyFactory.getInstance("RSA")        val keySpec = PKCS8EncodedKeySpec(encoded)        return kf.generatePrivate(keySpec) as RSAPrivateKey    }    @Bean    fun signer(            certs: Array<Certificate>,            privateKey: PrivateKey    ): AuthenticodeSigner =            AuthenticodeSigner(certs, privateKey)                    .withProgramName("Your Company Name")                    .withProgramURL("https://something.com")                    .withTimestamping(true)                    .withTimestampingAuthority("http://timestamp.comodoca.com/authenticode");

after, you can just @Autowire the signer bean and call its method sign() with the required file