Repository navigation
fix: exit codes, cmd expansion, signed self-update, import arguments - #31
Merged
Merged
Conversation
D1: the benign exit-code list in Get-UpdateStatus was off by one. Warnings are now 0x8A150109, 0x8A15010B, 0x8A15010D, 3010 and 1641 (names checked with winget error 1.29.380); a failed or cancelled install is an error again. One assertion per code. D2: Invoke-WinGet refuses any argument line containing '%', which cmd expands after the quote check, and runs cmd with /v:off so a DelayedExpansion value in HKCU cannot expand !VAR!. D3: the self-update also checks the Authenticode signer against the thumbprint of assets\WinGetStudio-codesign.cer (Valid or UnknownError), in every channel, and downloads to %SystemRoot%\Temp\wgt_update_<guid> with an Administrators/SYSTEM-only ACL. The portable exe is copied into place so it keeps the destination ACL. ADR 0022. D4: import keeps only PackageIdentifier, Version, Channel and Scope by default, even with every package ticked; an unticked box in the preview keeps the saved --custom/--override arguments.
Altering single bytes inside the signature of a signed release showed hundreds of broken variants that Get-AuthenticodeSignature reports as UnknownError with our certificate as signer, like the good file, and that the previous check accepted. Test-UpdateSignature now takes the WinVerifyTrust result (Get-UpdateSignerTrust, a P/Invoke compiled on first use) and accepts only 0 or CERT_E_UNTRUSTEDROOT. The pin is the SHA-256 of the public key of assets\WinGetStudio-codesign.cer instead of the certificate thumbprint, so renewing the certificate with the same key before 2031 needs no bridge release. When the signature does not match, a dialog says the update was not installed and links to the latest release. Test-Ui finds the WgtRow type by name, now that it is not the only Add-Type -TypeDefinition. ADR 0022, ADR 0012 and DEVELOPMENT.md (renewing the certificate) updated.
Rehearsed in Windows PowerShell 5.1 on a key of the same kind as the real one (CNG, Software KSP, exportable): the renewed certificate has a new thumbprint and the same public key, and the pinned check accepts exes signed before and after the renewal. The rehearsal found two gaps in the documented snippet: X509Store.Add stores the certificate without the link to its private key, so it now goes into the store through a .pfx export and import (which is also the backup), and the key usage and subject key identifier extensions of the current certificate were missing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Four defects found while comparing WinGet Studio with UniGetUI: one wrong result shown to the user, and three ways an app that always runs elevated (ADR 0002) could be made to run something it should not.
0x8A15010A, restart and try again) or a cancelled one (0x8A15010C) showed as a warning and was skipped by Retry failed, while already installed (0x8A15010D) and the PC will restart (0x8A15010B) showed as failures. Names checked withwinget erroron winget 1.29.380.%in a winget command line (D2).cmdexpands%VAR%after the quote guard of ADR 0004, even inside quotes. Any argument line with%is now refused, with the reason in the log, andcmdruns with/v:off, so aDelayedExpansionvalue set in HKCU by a non-elevated process cannot expand!VAR!either.assets\WinGetStudio-codesign.cer, not the certificate thumbprint, so renewing the certificate with the same key before 2031 needs no bridge release.WinVerifyTrust(accepting0orCERT_E_UNTRUSTEDROOT), notGet-AuthenticodeSignature'sStatus: altering bytes of a real signature produced hundreds of broken variants that PowerShell reports asUnknownErrorwith our certificate, exactly like the good file.%SystemRoot%\Temp\wgt_update_<guid>, with an ACL for Administrators and SYSTEM only, instead of the user's%TEMP%, where a non-elevated process could swap it between check and run.PackageIdentifier,Version,ChannelandScope, even with every package ticked; the--custom/--overridearguments winget saved are passed again only if the user ticks a new box under the preview. An import file can come from anyone.Also in DEVELOPMENT.md: the procedure to renew the certificate with the same key, rehearsed on a throwaway key of the same kind (the rehearsal found that
X509Store.Adddrops the private key, so the renewed certificate goes in through a.pfx).From now on every release must be signed with the published key: an unsigned build, or one signed with another key, is refused by every copy that has this change. Copies up to v1.12.0 do not check signatures and are not affected.
How it was tested
Test-Ui.ps1passes (offline), including one run with a signeddist\WinGetStudio.exe, where the test also alters bytes of its signature and checks they are refusedTest-InvokeWinGet.ps1passes: one assertion per exit code,%refused on both paths,/v:offTest-Ui.ps1 -Live: not run. This touches thecmdline used for writes; worth running before the release%SystemRoot%\Tempand its sweep (tests run unelevated, on%TEMP%), and a visual check of the new box in the import previewWinVerifyTruston the real signed exe and setup (accepted), oncmd.exeand a text file (refused), and on about 1,000 single-byte alterations of the signature (none of the broken ones accepted)Checklist
## UnreleasedinCHANGELOG.md(and the existing import line corrected)docs/adr/if this is an architectural decision (ADR 0022; notes in 0004, 0012, 0013, 0016)