Add support for signing and verifying appcast feeds#2822
Conversation
a8f8ad4 to
46940b6
Compare
This provides enhanced opt-in security preventing informational attacks that for example suggest the user the auto-updater is broken and an update needs to be installed from a compromised website (assuming the developer's website is hijacked). To opt in, developers need to add SURequireSignedFeed Info.plist key to their bundle. generate_appcast and sign_update have been updated to support signing appcast feeds and release note files (both need to be signed). By default, they embed a HTML comment warning in the files that further modifications will invalidate previously signed signatures. Signed appcasts include a signing block comment at the end of the XML file describing the signature of the content preceding it. Signed release notes will have their signatures annotated in the <sparkle:releaseNotesLink> element with a sparkle:edSignature attribute (and optionally a sparkle:length attribute for diagnostic purposes). A signingValidationStatus property is also now added to SUAppcast and SUAppcastItem indicating the signing status (skipped, succeeded, failed). The standard user driver's release notes HTML web view rejects external file references when appcasts are signed. A bug has also been fixed where the update alert would not provide errors when loading external release note files fails. These changes also introduce a showing new error / localizable strings when the release notes is not signed correctly or fails to load. As a hardening policy, we also enforce SUVerifyUpdateBeforeExtraction when opting into signed feeds, so key rotation is only possible with Developer ID code signed dmg archives. A fallback feed signing failure expiration policy has also been added. When a signed feed has failed validation for more than a configurable period of time (by default SUSignedFeedFailureExpirationInterval is set to 20 days), Sparkle will allow appcast items to be shown to the user. However, these items operate in a safe mode that strip abusable information like release notes / descriptions / links, sanitize the version strings, and they cannot be marked critical or informational, nor be installed automatically. After this policy expires, this allows users installing updates as long as the updates are signed correctly, or be aware that the updater has not been functioning correctly. Fixes #971.
46940b6 to
32fa638
Compare
|
Hi, I just tried this out. I noticed that when I run Just for context, for various workflow and legacy reasons, I currently generate my appcast XML using a script and combine them dynamically using Jekyll (which GitHub Pages will generate the final output for me) instead of using the generate_appcast script. With the way sign_update works, I would have to manually commit a new version of it since the signature would be signed against the reformatted file. I guess a compromise would be that I could just split out my release notes into a separate file and only sign that, and that can be done cleanly with the signature specified in the appcast (via releaseNotesLink). Actually I don't think that would work since SURequireSignedFeed would mean I have to sign the whole feed. |
|
Can you try with passing The XML reading/writing is done to add a sign warning about making further modifications to the file (unfortunately with XML parsing because XML doesn't allow comments in the very beginning), but the actual signing is just appending a block of comment text to the end of the file (with no XML parsing). However signing the XML file still has to update the file.. otherwise we would have to serve/download a new/different file just for the signature, which I thought would be the worse alternative than embedding the signature inside the appcast. |
Thanks. The flag did work. It appended the signature to the end of file without reformatting of the XML file.
Sure, this makes sense. I can see the tradeoffs with this specific design and I think it's fine to embed the signature in the same file. I was just surprised when I saw that the entire file was reformatted. I would vote for exposing this command-line flag (in maybe a more user-friendly name), since I think it should be up to each maintainer to decide whether they want that warning to exist or not as it highly depends on each project's workflow. Just a simple warning may not work anyway if the appcast is generated and someone somehow mistakenly re-generates the appcast without re-signing. Projects that opt in to this will need their own way of making sure the steps are followed. Actually, I think if this flag is added I think it might be better to just print out the string rather than modifying the file in-place, IMO. It's more flexible for the user who could then add that to their own file in their own way, and it's more consistent with how the sign_update tool works with other files as it usually just prints out a string that you can embed into elsewhere. In fact, playing around with this, it seems like I can already do this in a hacky version by just renaming myappcast.xml to myappcast.txt, call sign_update on it, then parse the results and manually extract the signature to the form that the appcast signature wants… 😅 |
Me too. Maybe I can get it to preserve formatting more, but not sure. Need to look into that.
Indeed but I'm still thinking it should be on by default(?).
This allows it to be possible for the developer to add/update the signing block incorrectly (e.g add extra newline or whatever). This block is more stringent than other parts of the file and isn't as forgiving to place with adjustment. In this case, there is no other file to embed the signature into; it's the same file. There should be no downside for sign_update just updating it for you in the byte-exact way it's intended. |
Add support for signing and verifying appcast feeds
This provides enhanced opt-in security preventing informational attacks that for example suggest the user the auto-updater is broken and an update needs to be installed from a compromised website (assuming the developer's website is hijacked).
To opt in, developers need to add SURequireSignedFeed Info.plist key to their bundle.
generate_appcast and sign_update have been updated to support signing appcast feeds and release note files (both need to be signed). By default, they embed a HTML comment warning in the files that further modifications will invalidate previously signed signatures. Signed appcasts include a signing block comment at the end of the XML file describing the signature of the content preceding it. Signed release notes will have their signatures annotated in the sparkle:releaseNotesLink element with a sparkle:edSignature attribute (and optionally a sparkle:length attribute for diagnostic purposes).
A signingValidationStatus property is also now added to SUAppcast and SUAppcastItem indicating the signing status (skipped, succeeded, failed).
The standard user driver's release notes HTML web view rejects external file references when appcasts are signed. A bug has also been fixed where the update alert would not provide errors when loading external release note files fails. These changes also introduce a showing new error / localizable strings when the release notes is not signed correctly or fails to load.
As a hardening policy, we also enforce SUVerifyUpdateBeforeExtraction when opting into signed feeds, so key rotation is only possible with Developer ID code signed dmg archives.
A fallback feed signing failure expiration policy has also been added. When a signed feed has failed validation for more than a configurable period of time (by default SUSignedFeedFailureExpirationInterval is set to 20 days), Sparkle will allow appcast items to be shown to the user. However, these items operate in a safe mode that strip abusable information like release notes / descriptions / links, sanitize the version strings, and they cannot be marked critical or informational, nor be installed automatically. After this policy expires, this allows users installing updates as long as the updates are signed correctly, or be aware that the updater has not been functioning correctly.
Fixes #971.
Misc Checklist
Testing
I tested and verified my change by using one or multiple of these methods:
--disable-embedded-sign-warningand-poption for both tools for signing feeds and release notes.macOS version tested:
26.2 (25C56)
12.7 VM
10.14.6 VM