mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Replace AuthenticodeTools with Microsoft.Security.Extensions
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsmResolver.DotNet" Version="5.5.1" />
|
||||
<PackageReference Include="AsmResolver.PE.Win32Resources" Version="5.5.1" />
|
||||
<PackageReference Include="Microsoft.Security.Extensions" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user