Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Add detailed diagnostic output for code signature mismatches
Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com>
  • Loading branch information
Copilot and jtschuster committed Nov 20, 2025
commit ff4b945519b0c972c05b01938d83bc2850d3b2e8
Original file line number Diff line number Diff line change
Expand Up @@ -262,18 +262,29 @@ public override bool Equals(object? obj)
return false;

if (_identifier != other._identifier)
{
Debug.WriteLine($"Identifiers differ: '{_identifier}' vs '{other._identifier}'");
Debug.WriteLine($"Expected (codesign):\n{other.ToCodesignString()}");
Debug.WriteLine($"Actual (managed):\n{ToCodesignString()}");
return false;
}

CodeDirectoryHeader thisHeader = _cdHeader;
CodeDirectoryHeader otherHeader = other._cdHeader;
if (!CodeDirectoryHeader.AreEqual(thisHeader, otherHeader))
{
Debug.WriteLine("CodeDirectory headers differ");
Debug.WriteLine($"Expected (codesign):\n{other.ToCodesignString()}");
Debug.WriteLine($"Actual (managed):\n{ToCodesignString()}");
return false;
}
for (int i = 0; i < _specialSlotHashes.Length; i++)
{
if (!_specialSlotHashes[i].SequenceEqual(other._specialSlotHashes[i]))
{
Debug.WriteLine($"Special slot hash {-(int)SpecialSlotCount + i} differs");
Debug.WriteLine($"Expected (codesign):\n{other.ToCodesignString()}");
Debug.WriteLine($"Actual (managed):\n{ToCodesignString()}");
return false;
}
}
Expand All @@ -282,6 +293,9 @@ public override bool Equals(object? obj)
{
if (!_codeHashes[i].SequenceEqual(other._codeHashes[i]))
{
Debug.WriteLine($"Code hash {i} differs");
Debug.WriteLine($"Expected (codesign):\n{other.ToCodesignString()}");
Debug.WriteLine($"Actual (managed):\n{ToCodesignString()}");
return false;
}
}
Expand Down Expand Up @@ -328,4 +342,43 @@ public int Write(IMachOFileWriter accessor, long offset)
}
return (int)Size;
}

/// <summary>
/// Formats the CodeDirectory information in a style similar to codesign's output
/// </summary>
internal string ToCodesignString()
{
var sb = new StringBuilder();
sb.AppendLine($"Identifier={_identifier}");
sb.AppendLine($"CodeDirectory v={(uint)_cdHeader.Version:X} size={Size} flags=0x{(uint)_cdHeader.Flags:X}({_cdHeader.Flags.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture)}) hashes={CodeSlotCount}+{SpecialSlotCount} location=embedded");
sb.AppendLine($"Hash type={_cdHeader.HashType.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture)} size={HashSize}");
sb.AppendLine($"Executable Segment base={_cdHeader.ExecSegmentBase}");
sb.AppendLine($"Executable Segment limit={_cdHeader.ExecSegmentLimit}");
sb.AppendLine($"Executable Segment flags=0x{(ulong)_cdHeader.ExecSegmentFlags:X}");
sb.AppendLine($"Page size={(1 << _cdHeader.Log2PageSize)}");

// Print special slot hashes (numbered from -SpecialSlotCount to -1)
for (int i = 0; i < SpecialSlotCount; i++)
{
int slotNumber = -(int)SpecialSlotCount + i;
sb.AppendLine($" {slotNumber,3}={ToHexStringLower(_specialSlotHashes[i])}");
}

// Print code hashes (numbered from 0 to CodeSlotCount-1)
for (int i = 0; i < CodeSlotCount; i++)
{
sb.AppendLine($" {i,3}={ToHexStringLower(_codeHashes[i])}");
}

return sb.ToString();
}

private static string ToHexStringLower(byte[] bytes)
{
#if NET
return Convert.ToHexStringLower(bytes);
#else
return BitConverter.ToString(bytes).Replace("-", "").ToLower(System.Globalization.CultureInfo.InvariantCulture);
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;

namespace Microsoft.NET.HostModel.MachO;
Expand Down Expand Up @@ -175,15 +176,29 @@ public static void AssertEquivalent(EmbeddedSignatureBlob? a, EmbeddedSignatureB
throw new ArgumentNullException("Both EmbeddedSignatureBlobs must be non-null for comparison.");

if (a.GetSpecialSlotHashCount() != b.GetSpecialSlotHashCount())
{
Debug.WriteLine($"Special slot hash counts differ: {a.GetSpecialSlotHashCount()} vs {b.GetSpecialSlotHashCount()}");
throw new ArgumentException("Special slot hash counts are not equivalent.");
}

if (!a.CodeDirectoryBlob.Equals(b.CodeDirectoryBlob))
{
Debug.WriteLine("CodeDirectory blobs are not equivalent:");
Debug.WriteLine($"Expected (codesign):\n{b.CodeDirectoryBlob.ToCodesignString()}");
Debug.WriteLine($"Actual (managed):\n{a.CodeDirectoryBlob.ToCodesignString()}");
throw new ArgumentException("CodeDirectory blobs are not equivalent");
}

if (a.RequirementsBlob?.Size != b.RequirementsBlob?.Size)
{
Debug.WriteLine($"Requirements blob sizes differ: {a.RequirementsBlob?.Size} vs {b.RequirementsBlob?.Size}");
throw new ArgumentException("Requirements blobs are not equivalent");
}

if (a.CmsWrapperBlob?.Size != b.CmsWrapperBlob?.Size)
{
Debug.WriteLine($"CMS Wrapper blob sizes differ: {a.CmsWrapperBlob?.Size} vs {b.CmsWrapperBlob?.Size}");
throw new ArgumentException("CMS Wrapper blobs are not equivalent");
}
}
}
Loading