From 3e645b823a3a1c05ba19a3dff6c6357ae1d7ddc1 Mon Sep 17 00:00:00 2001 From: Caelan Sayler Date: Mon, 30 Dec 2024 09:43:09 +0000 Subject: [PATCH] Replace AuthenticodeTools with Microsoft.Security.Extensions --- .../AuthenticodeTools.cs | 241 ------------------ .../Velopack.Packaging.Windows/CodeSign.cs | 15 +- .../Velopack.Packaging.Windows.csproj | 1 + .../TrustedSigningTests.cs | 10 +- 4 files changed, 22 insertions(+), 245 deletions(-) delete mode 100644 src/vpk/Velopack.Packaging.Windows/AuthenticodeTools.cs diff --git a/src/vpk/Velopack.Packaging.Windows/AuthenticodeTools.cs b/src/vpk/Velopack.Packaging.Windows/AuthenticodeTools.cs deleted file mode 100644 index 0e1aff68..00000000 --- a/src/vpk/Velopack.Packaging.Windows/AuthenticodeTools.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; - -namespace Velopack.Packaging.Windows; - -[SupportedOSPlatform("windows")] -[ExcludeFromCodeCoverage] -public static class AuthenticodeTools -{ - [DllImport("Wintrust.dll", PreserveSig = true, SetLastError = false)] - static extern uint WinVerifyTrust(IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData); - - static uint winVerifyTrust(string fileName) - { - Guid wintrust_action_generic_verify_v2 = new Guid("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}"); - - uint result = 0; - using (WINTRUST_FILE_INFO fileInfo = new WINTRUST_FILE_INFO(fileName, Guid.Empty)) - using (UnmanagedPointer guidPtr = new UnmanagedPointer(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))), AllocMethod.HGlobal)) - using (UnmanagedPointer wvtDataPtr = new UnmanagedPointer(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_DATA))), AllocMethod.HGlobal)) { - WINTRUST_DATA data = new WINTRUST_DATA(fileInfo); - IntPtr pGuid = guidPtr; - IntPtr pData = wvtDataPtr; - - Marshal.StructureToPtr(wintrust_action_generic_verify_v2, pGuid, true); - Marshal.StructureToPtr(data, pData, true); - - result = WinVerifyTrust(IntPtr.Zero, pGuid, pData); - } - return result; - - } - public static bool IsTrusted(string fileName) - { - return winVerifyTrust(fileName) == 0; - } -} - -[ExcludeFromCodeCoverage] -internal struct WINTRUST_FILE_INFO : IDisposable -{ - public WINTRUST_FILE_INFO(string fileName, Guid subject) - { - - cbStruct = (uint) Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)); - pcwszFilePath = fileName; - - if (subject != Guid.Empty) { - pgKnownSubject = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))); - Marshal.StructureToPtr(subject, pgKnownSubject, true); - } else { - pgKnownSubject = IntPtr.Zero; - } - - hFile = IntPtr.Zero; - - } - - public uint cbStruct; - - [MarshalAs(UnmanagedType.LPTStr)] - public string pcwszFilePath; - - public IntPtr hFile; - public IntPtr pgKnownSubject; - - public void Dispose() - { - Dispose(true); - } - - void Dispose(bool disposing) - { - if (pgKnownSubject != IntPtr.Zero) { - Marshal.DestroyStructure(this.pgKnownSubject, typeof(Guid)); - Marshal.FreeHGlobal(this.pgKnownSubject); - } - } -} - -enum AllocMethod -{ - HGlobal, CoTaskMem -}; - -enum UnionChoice -{ - File = 1, - Catalog, - Blob, - Signer, - Cert -}; - -enum UiChoice -{ - All = 1, - NoUI, - NoBad, - NoGood -}; -enum RevocationCheckFlags -{ - None = 0, - WholeChain -}; -enum StateAction -{ - Ignore = 0, - Verify, - Close, - AutoCache, - AutoCacheFlush -}; -enum TrustProviderFlags -{ - UseIE4Trust = 1, - NoIE4Chain = 2, - NoPolicyUsage = 4, - RevocationCheckNone = 16, - RevocationCheckEndCert = 32, - RevocationCheckChain = 64, - RecovationCheckChainExcludeRoot = 128, - Safer = 256, - HashOnly = 512, - UseDefaultOSVerCheck = 1024, - LifetimeSigning = 2048 -}; -enum UIContext -{ - Execute = 0, - Install -}; - -[StructLayout(LayoutKind.Sequential)] - -[ExcludeFromCodeCoverage] -internal struct WINTRUST_DATA : IDisposable -{ - public WINTRUST_DATA(WINTRUST_FILE_INFO fileInfo) - { - this.cbStruct = (uint) Marshal.SizeOf(typeof(WINTRUST_DATA)); - pInfoStruct = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_FILE_INFO))); - - Marshal.StructureToPtr(fileInfo, pInfoStruct, false); - - this.dwUnionChoice = UnionChoice.File; - - pPolicyCallbackData = IntPtr.Zero; - pSIPCallbackData = IntPtr.Zero; - dwUIChoice = UiChoice.NoUI; - fdwRevocationChecks = RevocationCheckFlags.None; - dwStateAction = StateAction.Ignore; - hWVTStateData = IntPtr.Zero; - pwszURLReference = IntPtr.Zero; - dwProvFlags = TrustProviderFlags.Safer; - dwUIContext = UIContext.Execute; - } - - public uint cbStruct; - public IntPtr pPolicyCallbackData; - public IntPtr pSIPCallbackData; - public UiChoice dwUIChoice; - public RevocationCheckFlags fdwRevocationChecks; - public UnionChoice dwUnionChoice; - public IntPtr pInfoStruct; - public StateAction dwStateAction; - public IntPtr hWVTStateData; - public TrustProviderFlags dwProvFlags; - public UIContext dwUIContext; - - IntPtr pwszURLReference; - - public void Dispose() - { - Dispose(true); - } - - - - void Dispose(bool disposing) - { - if (dwUnionChoice == UnionChoice.File) { - WINTRUST_FILE_INFO info = new WINTRUST_FILE_INFO(); - Marshal.PtrToStructure(pInfoStruct, info); - - info.Dispose(); - - Marshal.DestroyStructure(pInfoStruct, typeof(WINTRUST_FILE_INFO)); - } - - Marshal.FreeHGlobal(pInfoStruct); - } -} - -[ExcludeFromCodeCoverage] -internal sealed class UnmanagedPointer : IDisposable -{ - IntPtr m_ptr; - AllocMethod m_meth; - - internal UnmanagedPointer(IntPtr ptr, AllocMethod method) - { - m_meth = method; - m_ptr = ptr; - } - - ~UnmanagedPointer() - { - Dispose(false); - } - - void Dispose(bool disposing) - { - if (m_ptr != IntPtr.Zero) { - if (m_meth == AllocMethod.HGlobal) { - Marshal.FreeHGlobal(m_ptr); - } else if (m_meth == AllocMethod.CoTaskMem) { - Marshal.FreeCoTaskMem(m_ptr); - } - - m_ptr = IntPtr.Zero; - } - - if (disposing) { - GC.SuppressFinalize(this); - } - } - - public void Dispose() - { - Dispose(true); - } - - public static implicit operator IntPtr(UnmanagedPointer ptr) - { - return ptr.m_ptr; - } -} - diff --git a/src/vpk/Velopack.Packaging.Windows/CodeSign.cs b/src/vpk/Velopack.Packaging.Windows/CodeSign.cs index 98c712b2..8aaf0a73 100644 --- a/src/vpk/Velopack.Packaging.Windows/CodeSign.cs +++ b/src/vpk/Velopack.Packaging.Windows/CodeSign.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; +using Microsoft.Security.Extensions; using Velopack.Core; using Velopack.Util; @@ -15,6 +16,13 @@ public class CodeSign Log = logger; } + private bool IsTrusted(string filePath) + { + using var fileStream = File.OpenRead(filePath); + var targetPackageSignatureInfo = FileSignatureInfo.GetFromFileStream(fileStream); + return targetPackageSignatureInfo.State == SignatureState.SignedAndTrusted; + } + private bool ShouldSign(string filePath) { if (String.IsNullOrWhiteSpace(filePath)) return true; @@ -25,7 +33,7 @@ public class CodeSign } try { - if (VelopackRuntimeInfo.IsWindows && AuthenticodeTools.IsTrusted(filePath)) { + if (VelopackRuntimeInfo.IsWindows && IsTrusted(filePath)) { Log.Debug($"'{filePath}' is already signed, skipping..."); return false; } @@ -57,7 +65,8 @@ public class CodeSign Log.Info($"Preparing to codesign using a single file signing template, with a parallelism of {parallelism}."); signArguments = signArguments.Replace("{{file...}}", "{{file}}"); } else { - throw new UserInfoException("The sign template must contain '{{{file}}}' or '{{{file...}}}', " + + throw new UserInfoException( + "The sign template must contain '{{{file}}}' or '{{{file...}}}', " + "which will be substituted by one, or many files, respectively."); } } else { @@ -132,4 +141,4 @@ public class CodeSign $"Output was:" + Environment.NewLine + output); } } -} +} \ No newline at end of file diff --git a/src/vpk/Velopack.Packaging.Windows/Velopack.Packaging.Windows.csproj b/src/vpk/Velopack.Packaging.Windows/Velopack.Packaging.Windows.csproj index fc896d17..2a3475cf 100644 --- a/src/vpk/Velopack.Packaging.Windows/Velopack.Packaging.Windows.csproj +++ b/src/vpk/Velopack.Packaging.Windows/Velopack.Packaging.Windows.csproj @@ -15,6 +15,7 @@ + diff --git a/test/Velopack.Packaging.Tests/TrustedSigningTests.cs b/test/Velopack.Packaging.Tests/TrustedSigningTests.cs index d1f07eb2..160439bc 100644 --- a/test/Velopack.Packaging.Tests/TrustedSigningTests.cs +++ b/test/Velopack.Packaging.Tests/TrustedSigningTests.cs @@ -1,5 +1,6 @@ using Azure.Core; using Azure.Identity; +using Microsoft.Security.Extensions; using Velopack.Packaging.Windows; using Velopack.Util; @@ -71,7 +72,14 @@ public class TrustedSigningTests Assert.NotEmpty(files); #pragma warning disable CA1416 // Validate platform compatibility, this test only executes on Windows - Assert.All(files, x => Assert.True(AuthenticodeTools.IsTrusted(x))); + Assert.All(files, x => Assert.True(IsTrusted(x))); #pragma warning restore CA1416 // Validate platform compatibility } + + private bool IsTrusted(string filePath) + { + using var fileStream = File.OpenRead(filePath); + var targetPackageSignatureInfo = FileSignatureInfo.GetFromFileStream(fileStream); + return targetPackageSignatureInfo.State == SignatureState.SignedAndTrusted; + } } \ No newline at end of file