skeeto / w64devkit

Portable C and C++ Development Kit for x64 (and x86) Windows
The Unlicense
3.09k stars 213 forks source link

Self-sign w64devkit.exe with osslsigncode? #177

Open Peter0x44 opened 3 weeks ago

Peter0x44 commented 3 weeks ago

https://github.com/mtrojnar/osslsigncode @CrackedPixel recently informed me about self-signing executables which supposedly can reduce the frequency of problems with Windows Defender. It might be something worth integrating for releases, as an optional step in the docker file perhaps.

skeeto commented 3 weeks ago

That may be a good idea, and my understanding is that, in theory, it might build reputation across releases by cryptographically associating them. I tried going through the steps today, but, as usual with these things, I'm stumped when the rubber meets the road. I know in principle all the steps, even the algorithms at a technical level, but I can't produce the desired results, and the supporting software is opaque and unhelpful.

To try this out, first I generated a 10-year self-signed certificate using a modified command I found on Stack Overflow:

$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3650 -nodes -subj /CN=nullprogram.com

If I inspect it I see it has a basic constraint of "CA:TRUE". I assume EdDSA isn't supported, otherwise I could wrap my OpenPGP key in an X.509 certificate and use it. (To generate the real certificate I'll whip up a custom tool to derive an EC key from a passphrase so that I can store the certificate in my brain alongside all my other keys.) Then I compiled a "hello world" program and signed it:

$ osslsigncode sign -certs cert.pem -key key.pem -in hello.exe -out signed.exe

This works even if I concatenate arbitrary data to the binary, which is important for the real w64devkit distribution. (Is the concatenated data signed, too? I dont know, but in this case I also don't care.) I also added a Mark of the Web attribute to simulate a download. In Windows, the signed.exe properties window has a Digital Signatures tab with the correct details. SmartScreen still blocks it as "Unknown publisher", and I can understand why it won't let me control the "publisher" string in that display at this point.

If I install my new root certificate then I can somewhat simulate a future where my self-signed certificate improves a release's reputation. In the Digital Signatures tab there's an "Install Certificate" button to place it in the "Trusted Root Certification Authorities" store for the machine. I do this and it says it's successful. If I examine the store it includes the public key, confirming the self-signed certificate itself was attached to signed.exe. For "Intended Purposes" it's listed as "All" and its status is "This certificate is OK." So far so good.

However if I go back and examine signed.exe it says the certificate is invalid because the CA is not "allowed to issue certificates" or "cannot be used as an end-entity certificate." Does the latter mean self-signed certificates are not supported? Or maybe I need an additional property or constraint? The Digital Signatures tab reports that the "basic constraint extension has not been observed" (despite CA:TRUE per above). SmartScreen still blocks and reports "Unknown publisher." Rebooting does nothing. It seems whatever I've done isn't going to help anything, but Windows won't tell me what's wrong so that I can fix it.

Peter0x44 commented 1 week ago

https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-self-signed-certificate Perhaps creating the certificate on windows following Microsoft's documentation will work, though I am not sure.