From 59418b11e176a6d2d8b4226274dd92691c5715fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Tue, 17 Mar 2026 17:43:55 +0100 Subject: [PATCH] SignCheck: report file and archive context on verification errors When a file inside an archive fails verification (e.g. EndOfStreamException reading a PE header), SignCheck now catches the exception, records an ErrorResult with the failing file name and archive path, and continues processing remaining files. Changes: - Add SignatureVerificationResult.ErrorResult() factory method - Wrap per-file verification in ArchiveVerifier.VerifyContent with try-catch - Wrap top-level verification in SignatureVerificationManager.VerifyFiles - Add DetailVerificationError resource string Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../SignCheckResources.Designer.cs | 9 +++++++++ .../Microsoft.SignCheck/SignCheckResources.resx | 3 +++ .../Verification/ArchiveVerifier.cs | 13 +++++++++++-- .../SignatureVerificationManager.cs | 10 +++++++++- .../Verification/SignatureVerificationResult.cs | 17 +++++++++++++++++ 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/SignCheck/Microsoft.SignCheck/SignCheckResources.Designer.cs b/src/SignCheck/Microsoft.SignCheck/SignCheckResources.Designer.cs index f3096826218..62a57cf7c0f 100644 --- a/src/SignCheck/Microsoft.SignCheck/SignCheckResources.Designer.cs +++ b/src/SignCheck/Microsoft.SignCheck/SignCheckResources.Designer.cs @@ -213,6 +213,15 @@ internal static string DetailSkippedUnsupportedFileType { } } + /// + /// Looks up a localized string similar to Verification error: {0}. + /// + internal static string DetailVerificationError { + get { + return ResourceManager.GetString("DetailVerificationError", resourceCulture); + } + } + /// /// Looks up a localized string similar to Timestamp: {0:MM/dd/yy H:mm:ss} ({1}). /// diff --git a/src/SignCheck/Microsoft.SignCheck/SignCheckResources.resx b/src/SignCheck/Microsoft.SignCheck/SignCheckResources.resx index 97eec695bd2..ced83318221 100644 --- a/src/SignCheck/Microsoft.SignCheck/SignCheckResources.resx +++ b/src/SignCheck/Microsoft.SignCheck/SignCheckResources.resx @@ -168,6 +168,9 @@ Skipped (unsupported file type) + + Verification error: {0} + Timestamp: {0:MM/dd/yy H:mm:ss} ({1}) diff --git a/src/SignCheck/Microsoft.SignCheck/Verification/ArchiveVerifier.cs b/src/SignCheck/Microsoft.SignCheck/Verification/ArchiveVerifier.cs index bb64a96d20a..a1d760457a0 100644 --- a/src/SignCheck/Microsoft.SignCheck/Verification/ArchiveVerifier.cs +++ b/src/SignCheck/Microsoft.SignCheck/Verification/ArchiveVerifier.cs @@ -129,8 +129,17 @@ protected void VerifyContent(SignatureVerificationResult svr) // and we need to ensure they are extracted before we verify the MSIs. foreach (string fullName in archiveMap.Keys) { - SignatureVerificationResult result = VerifyFile(archiveMap[fullName], svr.VirtualPath, - Path.Combine(svr.VirtualPath, fullName), fullName); + SignatureVerificationResult result; + try + { + result = VerifyFile(archiveMap[fullName], svr.VirtualPath, + Path.Combine(svr.VirtualPath, fullName), fullName); + } + catch (Exception e) when (e is not PlatformNotSupportedException) + { + result = SignatureVerificationResult.ErrorResult( + archiveMap[fullName], svr.VirtualPath, Path.Combine(svr.VirtualPath, fullName), e); + } // Tag the full path into the result detail result.AddDetail(DetailKeys.File, SignCheckResources.DetailFullName, fullName); diff --git a/src/SignCheck/Microsoft.SignCheck/Verification/SignatureVerificationManager.cs b/src/SignCheck/Microsoft.SignCheck/Verification/SignatureVerificationManager.cs index 47af1c34bb4..0354e118acf 100644 --- a/src/SignCheck/Microsoft.SignCheck/Verification/SignatureVerificationManager.cs +++ b/src/SignCheck/Microsoft.SignCheck/Verification/SignatureVerificationManager.cs @@ -130,7 +130,15 @@ public IEnumerable VerifyFiles(IEnumerable { FileVerifier fileVerifier = GetFileVerifier(file); SignatureVerificationResult result; - result = fileVerifier.VerifySignature(file, parent: null, virtualPath: Path.GetFileName(file)); + + try + { + result = fileVerifier.VerifySignature(file, parent: null, virtualPath: Path.GetFileName(file)); + } + catch (Exception e) + { + result = SignatureVerificationResult.ErrorResult(file, parent: null, virtualPath: Path.GetFileName(file), e); + } if ((Options & SignatureVerificationOptions.GenerateExclusion) == SignatureVerificationOptions.GenerateExclusion) { diff --git a/src/SignCheck/Microsoft.SignCheck/Verification/SignatureVerificationResult.cs b/src/SignCheck/Microsoft.SignCheck/Verification/SignatureVerificationResult.cs index 177d19bd5d6..0dbd1fa8409 100644 --- a/src/SignCheck/Microsoft.SignCheck/Verification/SignatureVerificationResult.cs +++ b/src/SignCheck/Microsoft.SignCheck/Verification/SignatureVerificationResult.cs @@ -308,6 +308,23 @@ public static SignatureVerificationResult UnsupportedFileTypeResult(string path, return signatureVerificationResult; } + /// + /// Creates a SignatureVerificationResult for a file that failed verification due to an unexpected error. + /// + /// The path to the file that caused the error. + /// The parent container of the file, or null for top-level files. + /// The virtual path of the file. + /// The exception that occurred during verification. + public static SignatureVerificationResult ErrorResult(string path, string parent, string virtualPath, Exception exception) + { + var signatureVerificationResult = new SignatureVerificationResult(path, parent, virtualPath); + + signatureVerificationResult.AddDetail(DetailKeys.Error, + String.Format(SignCheckResources.DetailVerificationError, exception.ToString())); + + return signatureVerificationResult; + } + /// /// Creates a SignatureVerificationResult for an excluded file type or file extension. ///