Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 19, 2025

Fixes #121373

Description

macOS 26 changed codesign to hash only the __TEXT segment instead of the entire file. Updated the managed ad-hoc signing implementation to match this behavior and added enhanced diagnostic output for test failures.

Changes:

  • CodeDirectoryBlob.cs: Modified Create() to accept __TEXT segment boundaries and hash only that range instead of the entire file up to signature. Updated code slot count calculation accordingly. Added ToCodesignString() method for formatting output to match codesign's format. Enhanced Equals() to output detailed diagnostics using Debug.WriteLine() when comparisons fail.
  • EmbeddedSignatureBlob.cs: Enhanced AssertEquivalent() to output diagnostic details when blob comparisons fail, including full CodeDirectory details in codesign format.
  • MachObjectFile.cs: Extract __TEXT segment VM address range and file bounds, pass to CodeDirectoryBlob.Create(). Sets execSegmentBase and execSegmentLimit CodeDirectory header fields to __TEXT VM address range.
  • SigningTests.cs: Re-enabled MatchesCodesignOutput test.

Backwards compatible: falls back to legacy behavior (hash entire file) when textSegmentFileEnd parameter is not provided.

Diagnostic Output: When signature validation fails, the test now outputs detailed information in codesign-compatible format including identifier, CodeDirectory version/size/flags, hash type, executable segment details, page size, and all special slot and code hashes with proper numbering (-7 to -1 for special slots, 0 to N for code hashes).

Customer Impact

Without this fix, managed code signing produces signatures that don't match codesign output on macOS 26, breaking validation for .NET apps on the latest macOS.

Regression

No, this addresses a behavioral change in macOS 26 codesign tool.

Testing

Code builds without errors. Test suite includes MatchesCodesignOutput which validates signatures match Apple's codesign on both macOS 26 and 15. Enhanced diagnostic output will help identify any signature mismatches during testing.

Risk

Low. Changes are isolated to Mach-O code signing implementation. Debug assertion verifies __TEXT segment structure assumptions. Falls back to existing behavior when new parameters aren't provided. Diagnostic output only activates on test failures and uses Debug.WriteLine() which doesn't impact production code.

Original prompt

This section details on the original issue you should resolve

<issue_title>Update ad-hoc signing in HostModel to only hash the __TEXT segment</issue_title>
<issue_description>It looks like the new behavior of codesign is to only hash the __TEXT segment, whereas it used to hash the entire file. It looks like this doesn't affect whether or not Mac allows the file to be run. We could disable the test to get this in and file an issue for the fix. It may be simple enough for copilot.

Originally posted by @jtschuster in #121373 (comment)

The MatchesCodesignOutput test was temporarily disabled due a change in the behaviour of codesign in macOS 26.

[Theory(Skip = "Temporarily disabled due to macOS 26 codesign behavior change - only hashing __TEXT segment")]
[MemberData(nameof(GetTestFilePaths), nameof(MatchesCodesignOutput))]
[PlatformSpecific(TestPlatforms.OSX)]
void MatchesCodesignOutput(string filePath, TestArtifact _)

We should update the ad-hoc signing in HostModel to account for this new behaviour and re-enable the tests. The end result should work on both macOS 26 and macOS 15.</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 3 commits November 20, 2025 00:15
…ibility

Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com>
Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com>
Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com>
Copilot AI changed the title [WIP] Update ad-hoc signing in HostModel to hash only __TEXT segment Update ad-hoc signing to hash only __TEXT segment for macOS 26 compatibility Nov 20, 2025
Copilot finished work on behalf of elinor-fung November 20, 2025 00:22
Copilot AI requested a review from elinor-fung November 20, 2025 00:22
@jtschuster
Copy link
Member

Agh, I may have missed something when I found the difference in codesign behavior locally. It looks like the range hashed in the logs of #121373 was the same.

@copilot can you make the test print more details of the managed signature when MatchesCodesignOutput fails? See the examples below:

This is what codesign outputs:

 Identifier=apphost-5555494441534509f1a63be88a7c5024794cb811
 Format=Mach-O thin (arm64)
 CodeDirectory v=20400 size=1961 flags=0x2(adhoc) hashes=50+7 location=embedded
 VersionPlatform=1
 VersionMin=786432
 VersionSDK=918016
 Hash type=sha256 size=32
 CandidateCDHash sha256=cdfdd9f7ac88e98af1d9bb13eac30b83437ae64f
 CandidateCDHashFull sha256=cdfdd9f7ac88e98af1d9bb13eac30b83437ae64f3f37748242723cdc3917051a
 Hash choices=sha256
 CMSDigest=cdfdd9f7ac88e98af1d9bb13eac30b83437ae64f3f37748242723cdc3917051a
 CMSDigestType=2
 Executable Segment base=0
 Executable Segment limit=98304
 Executable Segment flags=0x1
 Page size=4096
     -7=4d8d4b9e4116e8edd996176b5553463acb64287bb635e7f141155529e20457bc
     -6=0000000000000000000000000000000000000000000000000000000000000000
     -5=cca8afe72425463c13b813da9ae468ae3b5fe20fe5fe1d3f34302ba2f15722f2
     -4=0000000000000000000000000000000000000000000000000000000000000000
     -3=0000000000000000000000000000000000000000000000000000000000000000
     -2=987920904eab650e75788c054aa0b0524e6a80bfc71aa32df8d237a61743f986
     -1=0000000000000000000000000000000000000000000000000000000000000000
      0=3906d5a7cc1880505c8bb7afccf92e9dedb82c6f594995b2d5059202ea9a5de3
      1=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
      2=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
      3=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
      4=ffdde085eb3c32c11164111db27d0751e407a3152f56c52bc87b2280aeb00066
      5=b831e8dbeaa709abdfa34f624f0f6f8daadab96f193b7c82b38f63d1f45483e5
      6=95a1fb2d09dda38f25596ed00b9bdf27a11a19936dee06403969592382cadcd2
      7=b9dea78a7108fee48b8fec9a6acbf20158a2155f7f53a78cc00eb09e375e478f
      8=2504e645ad9e6003d32ba1f5bef046eca68fe6768101083cd5d0bd6c3faf40d9
      9=708f3ef768802c9c8673d0e938df6360ef75f19afd0b1ff9e380014ca023a3e2
     10=234a38636e456366f60e390aa4da3d837d062b61b410c2ff16d29ade21eb054a
     11=30fe38f12e3f24c2e36e445665cf1c3587c1290d4ecae63bcd4475893e8217bd
     12=cac1662ad9a1541ff7b28a7c43c3c3df3281dab95b2163a2aa10a4c13b0654a2
     13=3be9b8fb3d9d5335a1786bd1330f26044b6d76f61678ac92bb2dcbc7c4d5f2f7
     14=216478b2d05812ff541842a3cc92f553bb05ce24ec47f6d8b7c29e2010b8910d
     15=b3a8dcfe9d1f545244fdae33221ea560a3fcbec9768ad27227248c9a56fd42be
     16=0c28641fdfa50a842471fbbc029fb7255378285306e793624646ea82f0680bbd
     17=452846f6c865d56cbf5e3f4d7a76593f258d2ec355021329888c9bffc6d6f667
     18=38260974c1272012e9f1fefefbf86213438890644229b3eb902659dc25257973
     19=65f81d3ad31d01f8fe94c31ba63e135042d26577b33e1ed791288ef5284de0ae
     20=d9ab0e930aa7a1d3514a940176cb1be2a0552795202215f591abffc793440cf4
     21=d1667ac42e28c33a9735e50bb8d59f6b30f2d2122323792be0c05f6c6d518a4d
     22=97a36ff3eeb3efff660ec1f32f33cd33e9f6d6ef46fd0b7c76e9ed41acde0717
     23=b84c39d20a261d12688a027669f3af93f20ec3d5c0b211c1dc55748ed03a772e
     24=6f0d073799fcac71e23133bf2e07f4aa587cef5400f4fba944ac1c2dbf43ba37
     25=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
     26=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
     27=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
     28=b80327ee5995e618b6dff1fdbd055135d7ff4f3742aab81e6a138540f030a643
     29=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
     30=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
     31=ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7
     32=cfd689e45265594c6a96f9e4cfe07ca2089357c7edf602b3d6d113a5a03b6302
     33=a97c5288dbca1f875fad6af44ad403e49413d0b8ea7d392d18ed41fd08597013
     34=32d6c58ff971f2b87bb8ba3451100626b8633d34a6f256f5473521908dc8c1ab
     35=c60cb86d4d0f6f9a5182630794b0e180d35d01db42d666b20d8972b8b2a999a5
     36=3ccfca6396542404bed3dc9686d0c52fad659249a7ffe90cd7e3f5f361651986
     37=89ade1e0377be75ad4e473f5fd5a4e44804ce8faa368f8a689406024819d746a
     38=8ff61a0ab3b4a4319c47e11dcb3008d591b7be3da74dad66e64d45894cd964be
     39=13e833811b84fb118e1fe3213d74f8bc7090f069735c6616a465e2ffd2417098
     40=24f1397e9bf7e00a8e3b167f5aef4efccebfed864e067c5c87fc22c0d08626a4
     41=f83dfb3f648c47541914f76e14377d810d4453b316ae7245215b02e336360fcf
     42=f2947df5aa9d9e528b2dac5601c0bece8f7cce9cba119638872a56c30c089cae
     43=4f678af5f878f8cdf0b2eb9d09386339216a8ce40c2e55e67176f940cae1e6b1
     44=c7b0c88a063d3fe842e921091620fd6d915c2ab1677c361e000d28c6566b0f25
     45=163251d82335758fc2ac9dcef553a389e014f4d3bdffbee1651e33b6259da18c
     46=849ed9b41a00ffff845043a6d77ff251736e961ed9defc121da41834a1bb5c25
     47=923a7aef0f4a58aed3b86bdd8234c3b2d96ce33eda52c3a7fc4df07c164ca92a
     48=66385a845c9c9f76d2b04b4d222f1d146f0d7ed79cf0496db30ff510004a4be4
     49=6d4a2c8caf76b21a4188d92e9203b1481b5afa00f9a5c92ce3960fb75924fc0b
 CDHash=cdfdd9f7ac88e98af1d9bb13eac30b83437ae64f
 Signature=adhoc
 Info.plist=not bound
 TeamIdentifier=not set
 Sealed Resources=none
 Internal requirements count=0 size=12

This is what we output:

Identifier: apphost-5555494441534509f1a63be88a7c5024794cb811,
 CodeDirectoryFlags: Adhoc,
 CodeDirectoryVersion: SupportsExecSegment,
 ExecutableSegmentBase: 0,
 ExecutableSegmentLimit: 98304,
 ExecutableSegmentFlags: MainBinary,
 SpecialSlotHashes: [4D8D4B9E4116E8EDD996176B5553463ACB64287BB635E7F141155529E20457BC, 0000000000000000000000000000000000000000000000000000000000000000, CCA8AFE72425463C13B813DA9AE468AE3B5FE20FE5FE1D3F34302BA2F15722F2, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 987920904EAB650E75788C054AA0B0524E6A80BFC71AA32DF8D237A61743F986, 0000000000000000000000000000000000000000000000000000000000000000],
 CodeHashes: [3906D5A7CC1880505C8BB7AFCCF92E9DEDB82C6F594995B2D5059202EA9A5DE3, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, FFDDE085EB3C32C11164111DB27D0751E407A3152F56C52BC87B2280AEB00066, B831E8DBEAA709ABDFA34F624F0F6F8DAADAB96F193B7C82B38F63D1F45483E5, 95A1FB2D09DDA38F25596ED00B9BDF27A11A19936DEE06403969592382CADCD2, B9DEA78A7108FEE48B8FEC9A6ACBF20158A2155F7F53A78CC00EB09E375E478F, 2504E645AD9E6003D32BA1F5BEF046ECA68FE6768101083CD5D0BD6C3FAF40D9, 708F3EF768802C9C8673D0E938DF6360EF75F19AFD0B1FF9E380014CA023A3E2, 234A38636E456366F60E390AA4DA3D837D062B61B410C2FF16D29ADE21EB054A, 30FE38F12E3F24C2E36E445665CF1C3587C1290D4ECAE63BCD4475893E8217BD, CAC1662AD9A1541FF7B28A7C43C3C3DF3281DAB95B2163A2AA10A4C13B0654A2, 3BE9B8FB3D9D5335A1786BD1330F26044B6D76F61678AC92BB2DCBC7C4D5F2F7, 216478B2D05812FF541842A3CC92F553BB05CE24EC47F6D8B7C29E2010B8910D, B3A8DCFE9D1F545244FDAE33221EA560A3FCBEC9768AD27227248C9A56FD42BE, 0C28641FDFA50A842471FBBC029FB7255378285306E793624646EA82F0680BBD, 452846F6C865D56CBF5E3F4D7A76593F258D2EC355021329888C9BFFC6D6F667, 38260974C1272012E9F1FEFEFBF86213438890644229B3EB902659DC25257973, 65F81D3AD31D01F8FE94C31BA63E135042D26577B33E1ED791288EF5284DE0AE, D9AB0E930AA7A1D3514A940176CB1BE2A0552795202215F591ABFFC793440CF4, D1667AC42E28C33A9735E50BB8D59F6B30F2D2122323792BE0C05F6C6D518A4D, 97A36FF3EEB3EFFF660EC1F32F33CD33E9F6D6EF46FD0B7C76E9ED41ACDE0717, B84C39D20A261D12688A027669F3AF93F20EC3D5C0B211C1DC55748ED03A772E, 6F0D073799FCAC71E23133BF2E07F4AA587CEF5400F4FBA944AC1C2DBF43BA37, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, B80327EE5995E618B6DFF1FDBD055135D7FF4F3742AAB81E6A138540F030A643, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, AD7FACB2586FC6E966C004D7D1D16B024F5805FF7CB47C7A85DABD8B48892CA7, CFD689E45265594C6A96F9E4CFE07CA2089357C7EDF602B3D6D113A5A03B6302, A97C5288DBCA1F875FAD6AF44AD403E49413D0B8EA7D392D18ED41FD08597013, 32D6C58FF971F2B87BB8BA3451100626B8633D34A6F256F5473521908DC8C1AB, C60CB86D4D0F6F9A5182630794B0E180D35D01DB42D666B20D8972B8B2A999A5, 3CCFCA6396542404BED3DC9686D0C52FAD659249A7FFE90CD7E3F5F361651986, 89ADE1E0377BE75AD4E473F5FD5A4E44804CE8FAA368F8A689406024819D746A, 8FF61A0AB3B4A4319C47E11DCB3008D591B7BE3DA74DAD66E64D45894CD964BE, 13E833811B84FB118E1FE3213D74F8BC7090F069735C6616A465E2FFD2417098, 24F1397E9BF7E00A8E3B167F5AEF4EFCCEBFED864E067C5C87FC22C0D08626A4, F83DFB3F648C47541914F76E14377D810D4453B316AE7245215B02E336360FCF, F2947DF5AA9D9E528B2DAC5601C0BECE8F7CCE9CBA119638872A56C30C089CAE, 4F678AF5F878F8CDF0B2EB9D09386339216A8CE40C2E55E67176F940CAE1E6B1, C7B0C88A063D3FE842E921091620FD6D915C2AB1677C361E000D28C6566B0F25, 163251D82335758FC2AC9DCEF553A389E014F4D3BDFFBEE1651E33B6259DA18C, 849ED9B41A00FFFF845043A6D77FF251736E961ED9DEFC121DA41834A1BB5C25, 923A7AEF0F4A58AED3B86BDD8234C3B2D96CE33EDA52C3A7FC4DF07C164CA92A, 66385A845C9C9F76D2B04B4D222F1D146F0D7ED79CF0496DB30FF510004A4BE4, 6D4A2C8CAF76B21A4188D92E9203B1481B5AFA00F9A5C92CE3960FB75924FC0B]
 specialSlotHashes: 4D8D4B9E4116E8EDD996176B5553463ACB64287BB635E7F141155529E20457BC, 0000000000000000000000000000000000000000000000000000000000000000, CCA8AFE72425463C13B813DA9AE468AE3B5FE20FE5FE1D3F34302BA2F15722F2, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 987920904EAB650E75788C054AA0B0524E6A80BFC71AA32DF8D237A61743F986, 0000000000000000000000000000000000000000000000000000000000000000
 machObjectFile specialSlotHashes: 4D8D4B9E4116E8EDD996176B5553463ACB64287BB635E7F141155529E20457BC, 0000000000000000000000000000000000000000000000000000000000000000, CCA8AFE72425463C13B813DA9AE468AE3B5FE20FE5FE1D3F34302BA2F15722F2, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 987920904EAB650E75788C054AA0B0524E6A80BFC71AA32DF8D237A61743F986, 0000000000000000000000000000000000000000000000000000000000000000

We should try to make out output match the codesign output as much as possible, add more details about the CMS blob, and remove redundant hashes.

Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 20, 2025

Agh, I may have missed something when I found the difference in codesign behavior locally. It looks like the range hashed in the logs of #121373 was the same.

...

Done in ff4b945. Added ToCodesignString() method that formats output to match codesign's style, including:

  • Identifier, CodeDirectory version, size, flags, and hash counts
  • Hash type and size
  • Executable segment base, limit, and flags
  • Page size
  • Special slot hashes (numbered -7 to -1)
  • Code hashes (numbered 0 to N)

The enhanced Equals() and AssertEquivalent() methods now write detailed diagnostics to Debug.WriteLine() when comparisons fail, showing both the expected (codesign) and actual (managed) signatures in the same format.

Copilot finished work on behalf of jtschuster November 20, 2025 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update ad-hoc signing in HostModel to only hash the __TEXT segment

3 participants