Repository navigation
fix(release): the Authenticode gate pins Artifact Signing's issuer and EKU, so a trusted self-signed CN=Matt Gradwohl certificate no longer passes (#2990) - #3000
Merged
Conversation
…er and extended key usage, so a trusted self-signed CN=Matt Gradwohl certificate no longer passes (#2990) cmake/VerifyWindowsSignatures.cmake accepted any Valid, timestamped signature whose signer CN was TASKSMACK_EXPECTED_SIGNER. It now also requires the signer certificate's issuer to be like TASKSMACK_EXPECTED_ISSUER (default "CN=Microsoft ID Verified CS [AE]OC CA [0-9][0-9], O=Microsoft Corporation, C=US"; the dry run's certificate is issued by "... EOC CA 04 ...") and one of its extended key usages to be like TASKSMACK_EXPECTED_EKU (default 1.3.6.1.4.1.311.97.*; the certificate carries 1.3.6.1.4.1.311.97.1.0 and its identity validation's own 1.3.6.1.4.1.311.97.<id>). Both are stable across the certificates' few-day rotation, and the issuer pattern survives a CA rollover. The CN and same-subject checks stay. The decision is now one PowerShell function, Test-TaskSmackSignatures, which the script can write out (TASKSMACK_WRITE_SIGNATURE_CHECK) without checking anything. tools/test-verify-windows-signatures.ps1 (CTest VerifyWindowsSignaturesScript, pwsh-script) calls it with certificates made in memory with CertificateRequest: a self-signed CN=Matt Gradwohl one, an internal CA's and a lookalike CA name fail, the Azure-shaped chain passes, also across a rotation onto CA 05. Nothing is signed, stored or trusted. Both new options are CMake cache options beside TASKSMACK_EXPECTED_SIGNER and reach CPack's pre-build check through CPackProjectConfig.cmake.in; tools/verify-windows-signatures.ps1 takes optional -ExpectedIssuer/-ExpectedEku and otherwise uses the script's defaults, so release.yml needs no change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
mgradwohl
enabled auto-merge (squash)
October 26, 2026 03:05
Owner
Author
|
Lane review: the issuer pattern |
…a bracket pair the link audit reads as a reference (#2990) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r-pin # Conflicts: # CONTRIBUTING.md
Owner
Author
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.9
git worktree add -d .worktree/backport-3000-to-release/0.9 origin/release/0.9
cd .worktree/backport-3000-to-release/0.9
git switch --create backport-3000-to-release/0.9
git cherry-pick -x 2bc934d75431324451290f84b55e64dde79a8693 |
mgradwohl
added a commit
that referenced
this pull request
Oct 26, 2026
…d EKU, so a trusted self-signed CN=Matt Gradwohl certificate no longer passes (#2990) (#3000) (#3021) * fix(release): the Authenticode gate also pins Artifact Signing's issuer and extended key usage, so a trusted self-signed CN=Matt Gradwohl certificate no longer passes (#2990) cmake/VerifyWindowsSignatures.cmake accepted any Valid, timestamped signature whose signer CN was TASKSMACK_EXPECTED_SIGNER. It now also requires the signer certificate's issuer to be like TASKSMACK_EXPECTED_ISSUER (default "CN=Microsoft ID Verified CS [AE]OC CA [0-9][0-9], O=Microsoft Corporation, C=US"; the dry run's certificate is issued by "... EOC CA 04 ...") and one of its extended key usages to be like TASKSMACK_EXPECTED_EKU (default 1.3.6.1.4.1.311.97.*; the certificate carries 1.3.6.1.4.1.311.97.1.0 and its identity validation's own 1.3.6.1.4.1.311.97.<id>). Both are stable across the certificates' few-day rotation, and the issuer pattern survives a CA rollover. The CN and same-subject checks stay. The decision is now one PowerShell function, Test-TaskSmackSignatures, which the script can write out (TASKSMACK_WRITE_SIGNATURE_CHECK) without checking anything. tools/test-verify-windows-signatures.ps1 (CTest VerifyWindowsSignaturesScript, pwsh-script) calls it with certificates made in memory with CertificateRequest: a self-signed CN=Matt Gradwohl one, an internal CA's and a lookalike CA name fail, the Azure-shaped chain passes, also across a rotation onto CA 05. Nothing is signed, stored or trusted. Both new options are CMake cache options beside TASKSMACK_EXPECTED_SIGNER and reach CPack's pre-build check through CPackProjectConfig.cmake.in; tools/verify-windows-signatures.ps1 takes optional -ExpectedIssuer/-ExpectedEku and otherwise uses the script's defaults, so release.yml needs no change. * docs(release): the expected-issuer row describes the pattern without a bracket pair the link audit reads as a reference (#2990) --------- (cherry picked from commit 2bc934d) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Description
cmake/VerifyWindowsSignatures.cmakeaccepted any Valid, timestamped signature whose signer CN wasTASKSMACK_EXPECTED_SIGNER(Matt Gradwohl), with the same Subject on both exes. A self-signed or internal code-signing certificate withCN=Matt Gradwohlthat the build machine trusts passed. The check now also pins two things about the signer certificate that stay the same across Azure Artifact Signing's few-day rotation:-likeTASKSMACK_EXPECTED_ISSUER, defaultCN=Microsoft ID Verified CS [AE]OC CA [0-9][0-9], O=Microsoft Corporation, C=US. Any two-digit CA number matches, so a rollover from CA 04 to 05 still passes. The pattern takes AOC as well as EOC because both are Microsoft ID Verified code-signing issuing CAs; drop[AE]toEif you'd rather pin EOC only.-likeTASKSMACK_EXPECTED_EKU, default1.3.6.1.4.1.311.97.*(Artifact Signing's).Both checks are required. The CN, Valid, timestamp and same-subject checks stay as they were.
The real certificate (main's dry run 40245228873,
release-assets-dry-run, bothTaskSmack-0.9.0-win64.zipand-windows-arm64.zip; read withGet-AuthenticodeSignature):CN=Matt Gradwohl, O=Matt Gradwohl, L=REDMOND, S=wa, C=USCN=Microsoft ID Verified CS EOC CA 04, O=Microsoft Corporation, C=USMicrosoft ID Verified Code Signing PCA 2021→Microsoft Identity Verification Root Certificate Authority 20201.3.6.1.4.1.311.97.1.0,1.3.6.1.5.5.7.3.3(Code Signing),1.3.6.1.4.1.311.97.703777433.107619563.194876341.588498515(the identity validation's own)CN=Microsoft Public RSA Time Stamping Authority, ...The pin doesn't use the identity-validation-specific EKU, because it changes whenever the identity is validated again.
311.97.*covers it and311.97.1.0.Plumbing.
cmake/Options.cmake, documented next toTASKSMACK_EXPECTED_SIGNER.CPackProjectConfig.cmake.in.-Pmode the script falls back to the same defaults. An empty value also means the default, so a pin can't be dropped by mistake.tools/verify-windows-signatures.ps1takes optional-ExpectedIssuer/-ExpectedEkuand logs each signer's EKUs. Without them it uses the defaults.release.ymlis not changed:validate-windows-packageandverify-published-releasepick up the pins through the defaults.sign-windows' "quick look" before repacking still checks only the CN. That step isn't the gate, and editing a workflow needs your confirmation.Testability.
Test-TaskSmackSignatures, kept in a bracket argument in the.cmakefile.-DTASKSMACK_WRITE_SIGNATURE_CHECK=<file>writes the function out and returns without checking anything.Fixes #2990
PR Size
Medium: about 290 lines. About 160 of them are the new test.
Type of Change
Checklist
clang-tidyand addressed any warnings (no C++ changed)clang-formaton my changes (no C++ changed)pre-commit run --all-filesor installed pre-commit hooks (pre-commit run --fileson every touched file)Testing
1. New test:
tools/test-verify-windows-signatures.ps1, run by CTest asVerifyWindowsSignaturesScript(labelpwsh-script,RESOURCE_LOCK pwsh-script-tests, 120 s timeout).CertificateRequest. Nothing is signed, no store is opened, and nothing is trusted.Options.cmake's cache defaults are identical.Pass:
Fail:
CN=Matt Gradwohlwith Code Signing (the issue's repro);CN=Microsoft ID Verified CS EOC CA 04, O=Contoso;HashMismatch,NotSigned;2. The real signed exes from dry run 40245228873, extracted x64 and ARM64
.zips. The default pins pass:Other runs:
tools/verify-windows-signatures.ps1 -PackageRoot ... -ExpectedSigner 'Matt Gradwohl' -VerifyScript cmake/VerifyWindowsSignatures.cmake, release.yml's call: exit 0.-DTASKSMACK_EXPECTED_ISSUER=CN=Contoso*: fails with "issued by CN=Microsoft ID Verified CS EOC CA 04, ...".-DTASKSMACK_EXPECTED_EKU=1.2.3.*: fails and lists the three real EKUs.OKunder Windows PowerShell 5.1, which the script falls back to when pwsh is missing.CPackProjectConfig.cmake.inconfigured with@ONLYsets all three values for the NSIS pre-build check.Additional Notes
backport:0.9is on this PR. The commit cherry-picks ontoorigin/release/0.9with one modify/delete conflict,tools/verify-windows-signatures.ps1, because release/0.9 has no such file. Resolve it withgit rm tools/verify-windows-signatures.ps1; everything else applies cleanly. release/0.9 keeps the check inline inrelease.yml:cmake "-DTASKSMACK_VERIFY_DIR=$pkg" "-DTASKSMACK_EXPECTED_SIGNER=..." -P repo/cmake/VerifyWindowsSignatures.cmake, with a sparse checkout of just that file. It gets the pins from the defaults with no workflow change. On the cherry-picked tree, the new test passes and that inline-style call prints OK on the real exes.Microsoft ID Verified CS EOC CA 04, O=Microsoft Corporationto the machine's trusted roots.🤖 Generated with Claude Code