nefarius / vicius

Nefarius' nŏvīcĭus universal software updater agent for Windows.
https://docs.nefarius.at/projects/Vicius
BSD 3-Clause "New" or "Revised" License
52 stars 5 forks source link

Implement proper Authenticode signature verification #7

Open nefarius opened 10 months ago

nefarius commented 10 months ago

Adding signature validation/verification turned out to be a tougher challenge than a few checkboxes in the README can keep track of, so here we are 😛

There are a couple of issues to solve, primarily: what is considered a valid, trustworthy signature?

The expectation of the user and developer might be as follows: if the distributed updater executable either is signed itself (best case scenario) and the downloaded setup is signed by the same company/publisher, it is considered trusted.

Sounds simple enough in theory, how can that be achieved in practice? First, trusting a signed executable involves multiple parameters. The signature is valid as it has not been tampered with. Has it been signed by a CA the OS considers as trustworthy? How do we reliably identify that CA and the publisher/signer? By names? by serial numbers? By certificate fingerprints?

How do we avoid spoofing; let's say someone imports their own "DigiCert" CA and self-signes with the same publisher name; the OS APIs would consider the signatures valid. Now this is an unlikely scenario; importing additional CAs requires elevated permissions so if that is possible, the user system is considered compromised anyway.

Which parameters of the signature and the certificate chain can't be spoofed easily? Which values can be used for comparison?

To be continued...

fredemmott commented 6 months ago

Sounds simple enough in theory, how can that be achieved in practice? First, trusting a signed executable involves multiple parameters. The signature is valid as it has not been tampered with. Has it been signed by a CA the OS considers as trustworthy? How do we reliably identify that CA and the publisher/signer? By names? by serial numbers? By certificate fingerprints?

These are all addressed as a black box with WinVerifyTrust(), e.g. https://github.com/fredemmott/OpenXR-API-Layers-GUI/blob/main/src/linters/windows/UnsignedDllLinter.cpp

This doesn't provide any flexibility though - just "is it valid?" and to a (largely undocumented) extent, 'if not, why not?'.

How do we avoid spoofing; let's say someone imports their own "DigiCert" CA and self-signs with the same publisher name; the OS APIs would consider the signatures valid. Now this is an unlikely scenario; importing additional CAs requires elevated permissions so if that is possible, the user system is considered compromised anyway.

IMO this is completely fine and Microsoft's problem; the CA list should be maintained by Windows Update/Defender and the system/network administrator.

fredemmott commented 6 months ago

Though, compared to my example, for an autoupdater you'd probably want WTD_REVOCATION_CHECK_CHAIN instead of WTD_REVOCATION_CHECK_NONE

nefarius commented 6 months ago

A few very good points! What's still missing though is how would a user of the solution want to configure it to make sure that the binary that gets downloaded not just has a valid signature but is actually signed by a source considered trusted. After all, some random text editor setup might be signed by a company other than mine but the expectation in Signatur verification wouldn't be that this would be a trusted update, only binaries signed by a certain company certificate or publisher in general should be accepted by the updater, otherwise any random signed binary would be considered trusted.

fredemmott commented 6 months ago

I guess the combination of 'got a cert' and 'got an https cert for the update domain' doesn't work for the totally hypothetical situation of someone else getting your domain via a trademark claim :p

fredemmott commented 6 months ago

The cert/CA chain stuff isn't really designed for that problem - perhaps adopting https://theupdateframework.github.io/specification/latest/ (or the crypto approach from it, or something related) could be the way to go as an alternative, or just simple libsodium-based signatures?

Added bonus is they don't require authors to give money to CAs.

nefarius commented 6 months ago

Good points. Something that wouldn't require official expensive CAs would indeed be cool. Rolling your own crypto is doomed to fail so I gotta do more research first.