johndbritton / teleport

Virtual KVM for macOS
GNU General Public License v2.0
790 stars 132 forks source link

Update Sparkle public key #84

Closed johndbritton closed 3 years ago

johndbritton commented 3 years ago

While I was working on automating the release process in https://github.com/johndbritton/teleport/pull/80 and more specifically https://github.com/johndbritton/teleport/pull/82 I needed to find a way for Fastlane to generate ed25519 signatures for the release assets.

This sent me down a deep rabbit-hole, investigating how Sparkle generates the keys, signs, and verifies. It turns out that https://github.com/sparkle-project/ed25519 uses an older style when generating the keys. It basically generates the keys from a random seed saves the private and public keys and throws away the seed.

In newer implementations of the algorithm, the seed is saved and the keys are derived from the seed each time they are needed.

I found https://github.com/RubyCrypto/ed25519 and used that to generate signatures on our releases from Fastlane, but since it's following the newer pattern, it requires a seed to derive the keys and make signatures. Technically it is possible to create and verify signatures without the seed, it's just not supported by the library.

I considered adding the ability to use the library without providing a seed, but it was substantial work (see: https://github.com/RubyCrypto/ed25519/issues/27).

I couldn't find much documentation on Sparkle about this topic, but by looking at the code:

https://github.com/sparkle-project/Sparkle/blob/master/Sparkle/SUUpdateValidator.m#L126-L211

I found that Sparkle performs two checks when installing an update and only requires one to pass. It checks if the new version is signed with an ed25519 that can be verified from the existing public key and it checks if the new application is signed by the same apple developer certificate as the current one.

Because only one check is required to pass, as long as the new version is signed with the same developer ID certificate then it is possible to release a new version of the application with a new public key embedded in the app and it will be accepted and installed.

It's important to note that when changing the public key inside the new version of the application, the new version must be signed with the corresponding private key in the appcast feed in order for the application to be installed. This is not really a security measure, it's more to prevent mistakes. The new version will have been verified with a matching developer id certificate but to make sure your ed25519 signing is configured correctly, the update will only be installed if the signature matches.

In order to get our automated builds to work with with signatures for Sparkle, I ultimately created a new keypair derived from a new seed value which I have stored securely. Using this seed I have generated a new public key and embedded it in the app (in this PR) and I have configured our build environment with the seed to derive the private key as needed using https://github.com/RubyCrypto/ed25519.