curl / curl-for-win

Reproducible curl binaries for Linux, macOS and Windows
https://curl.se/windows/
MIT License
694 stars 207 forks source link

Digital signatures not valid beyond certificate expiration date #23

Closed dnebeker closed 3 years ago

dnebeker commented 3 years ago

Thank you for signing the binary files - with the growing supply chain hacks this is increasingly important.

I wanted to point out something odd about the signing. For example, curl-7.65.3-win64-mingw\bin\libcurl-x64.dll. In the attached image you can see that Windows says the file's signature is not within the certificate validity period (which has just expired). Somehow Windows Explorer does show a valid signing date, but if you call WinVerifyTrust and look at the CRYPT_PROVIDER_DATA.sftVerifyAsOf parameter, it does seem to be empty. So WinVerifyTrust won't trust the signature on that file any more.

Perhaps you are purposely not signing with a timestamp to provide a reproducible build. Perhaps there is some other way to accomplish this while still having a signature that is valid beyond the certificate end date?

cert

vszakats commented 3 years ago

@dnebeker: Thanks for your comment!

Perhaps you are purposely not signing with a timestamp to provide a reproducible build. Perhaps there is some other way to accomplish this while still having a signature that is valid beyond the certificate end date?

This is the reason exactly. When signed timestamps are enabled, the builds will lose their reproducible nature, meaning each, unaltered build will result in a different binary, thus invalidating the effort, or at least making it difficult to verify. So far I haven't found a solution to this. With reproducible builds we'd need a signature for the reference timestamp (always in the past) of the source package, not the actual moment the code signing is done.

I'm happy to hear about ideas or pointers on how to better deal with this.

In the meantime I think the solution is to keep the binaries updated and the signature expiration with them.

dnebeker commented 3 years ago

I suggest logging the hash both before and after proper signing. Anyone that is going to the effort to reproduce the build will have the binary before the signing, and can verify the reproducibility via that hash at that point in time (before proper signing). Then you could do a proper signing, and have reproducibility as well.

The problem with the current method is shipping software with these DLLs eventually becomes untrusted, and updating them in customer installations isn't always possible.

vszakats commented 3 years ago

If done that way, the final downloadable archives will have an ever changing hash, so regardless of what additional hashes are documented inside (e.g. in logs, or additional text files), it would require a fair bit of non-trivial investigation work to find out if the actual binaries (after stripping the signatures with a reproducible method) are the same. In practice I expect very few people willing to do that. Plus we'd need a documented, reproducible way of stripping signatures.

I understand it's a problem if signatures expire, but disregarding expiring signatures, it is probably useful practice to keep these binaries updated in the downstream distribution channels to keep up with fixes anyway. There is an almost certain chance that the distributed EXE and DLL components (in practice this is curl and OpenSSL ones) get regular updates before their signatures expire.

An alternative solution is to custom re-sign the binaries after verifying them and before re-distributing them. This can be done with any signature configuration, and even with a proper code signing certificate. Due to the sad (and expensive) state of Windows code signatures, the currently shipping curl-for-win ones are just "best-effort", self-signed, experimental signatures, with its own set of downsides, most notably the need to install a custom root certificate.

Another alternative is to make a local fork of this repo, and create the builds with a custom signature and also enabling the -ts option inside _sign-code.sh.

None of these is ideal, but overall I feel that Microsoft would need to step in to fix these issues on their platform, with reproducbility in mind.

UPDATE: I'm not sure if this is a thing on Windows (or on any platform) but detached code signature may resolve these issues, by distributing these detached code signature in separate packages from the actual binaries.

vszakats commented 3 years ago

It is actually possible to create detached signatures. This is supported by the official signtool.exe tool, and possible to do with osslsigncode as well. The signature extension is .p7. Information is scarce, but it seems this is meant to be used for non-executable files, akin to GPG's detached signatures. The question is if Windows recognizes such detached signature (and if it overrides an embedded one or not).